Materialize Monitoring Alloy#

mzmon-alloy is a minimal, distroless repackaging of Grafana Alloy hardened for use in Materialize Monitoring. It is published to ghcr.io/materializeinc/mzmon-alloy and is a drop-in replacement for the upstream grafana/alloy image.

Rather than build Alloy from source, the image repackages the signed upstream release binary (verified against the release SHA256SUMS) onto a distroless base. This keeps us in lockstep with upstream releases while giving us a smaller, non-root, FIPS-capable image.

Tags and versioning#

Images are tagged <alloy-version>-<suffix>, for example v1.17.0-mz1.

  • <alloy-version> is the upstream Alloy release the binary comes from.
  • <suffix> is the Materialize revision of that repackaging. Release images use mzN (mz1, mz2, …); the counter increments when we change the image at a fixed Alloy version and resets to mz1 on an Alloy upgrade.
  • Pull requests that touch the image publish a throwaway build tagged <alloy-version>-dev.0--pr.g<short-sha> for pre-release testing.

Compliance and security posture#

The table below summarizes how the image maps to the frameworks we track. Status legend: ✅ enforced in the image · ⚙️ enforced at deploy/CI (image is compatible) · ⚠️ operator/config-dependent.

FrameworkControlStatusHow it is met
FIPS 140-3Validated cryptographic modulealloy-boringcrypto routes Go crypto through the CMVP-validated BoringCrypto module; build-asserted via grep boringcrypto.
FIPS 140-3Approved-mode operation⚠️Requires FIPS-approved ciphers / TLS 1.2+ in the overlaid pipeline config.
CIS Docker 4.1Run as non-root userUSER 473:473 (numeric).
CIS Docker 4.2Trusted, pinned base imageDistroless base, pinned by digest and tracked by Renovate.
CIS Docker 4.3No unnecessary packagesDistroless final stage — no shell or package manager.
CIS Docker 4.5Image signing⚙️cosign signing in CI (planned).
CIS Docker 4.6Health check⚙️No HEALTHCHECK (distroless); use a Kubernetes httpGet probe on /-/ready:12345.
CIS Docker 4.7No standalone apt-get updateCombined update+install layer in the builder.
CIS Docker 4.8No setuid/setgid binariesBinary installed 0755; distroless base has none.
CIS Docker 4.9Prefer COPY over ADDADD used only to fetch the release artifact, then checksum-verified.
CIS Docker 4.10No secrets in the imageNone present.
CIS Docker 4.11Verify downloaded packagesAlloy binary verified against upstream SHA256SUMS.
CIS Kubernetes §5Restricted pod securityContext⚙️Image supports the securityContext below (non-root, read-only rootfs, drop all caps).
NIST SP 800-190 §4.1.1Image vulnerabilities⚙️Distroless minimizes surface; Trivy/Grype scan gate in CI (planned).
NIST SP 800-190 §4.1.2Image configuration defectsNon-root, minimal, no secrets, no embedded services.
NIST SP 800-190 §4.1.3Embedded malware / integrityChecksum-verified binary + build provenance + SBOM (signing planned).
NIST SP 800-190 §4.1.5Use of untrusted imagesDigest-pinned distroless base; official verified Alloy release.

FIPS 140-3#

The image ships the alloy-boringcrypto release variant, so Alloy’s Go cryptography is routed through the CMVP-validated BoringCrypto module. FIPS mode is engaged automatically at process start (power-on self-tests run at init); no runtime environment variable is required. The build asserts the FIPS backend is present (alloy --version | grep boringcrypto), so a wrong or downgraded release asset fails the build.

The FIPS boundary is Alloy’s in-process Go cryptography only. The distroless base ships Debian’s (non-validated) OpenSSL libraries, but Alloy is a pure-Go binary and never calls them, so they are outside the boundary — a FIPS-validated base OS is not required for this workload. Operating in an approved mode still requires configuration: TLS on remote_write and receivers must be constrained to FIPS-approved cipher suites and TLS 1.2+ in the overlaid pipeline config.

Image hardening#

  • Non-root by default. Runs as uid/gid 473:473 (a numeric user, which satisfies Kubernetes runAsNonRoot).
  • Distroless base. No shell, package manager, or unnecessary packages, minimizing CVE and attack surface (NIST SP 800-190 §4.1).
  • Verified provenance. The Alloy binary is checksum-verified against the upstream SHA256SUMS at build time; base images are pinned by digest and tracked by Renovate.
  • Supply-chain attestations. Published images carry build provenance (provenance: mode=max) and an SBOM.

Kubernetes securityContext#

The image is compatible with a locked-down securityContext; set this in the deployment (CIS Kubernetes Benchmark §5):

securityContext:
  runAsNonRoot: true
  runAsUser: 473
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]
  seccompProfile:
    type: RuntimeDefault

With readOnlyRootFilesystem: true, provide writable emptyDir volumes for the two paths Alloy writes to:

  • /var/lib/alloy — the storage path (WAL / remote-config state). Declared as a VOLUME in the image.
  • /tmp — scratch space.

A host-monitoring DaemonSet that scrapes the node (host /proc, /sys, journal) is a deliberate exception that needs additional mounts and relaxed settings. The Materialize scraping use case does not, and should run fully unprivileged as above.

Health checks#

The image has no HEALTHCHECK — distroless has no shell and Alloy has no self-probe subcommand. Use a Kubernetes httpGet readiness/liveness probe against /-/ready on the Alloy HTTP port (12345) instead.

Building locally#

make alloy-image

This builds the multi-arch image (linux/amd64, linux/arm64) and smoke-tests alloy --version on both. Publishing to GHCR happens in CI, not from the Makefile.