Distroless image reference

Reference for the LinuxGuard agent distroless container image — contents, exclusions, security context, host paths, PSS compatibility, RBAC, and image-signing verification.

The LinuxGuard agent ships as a digest-pinned distroless container image built on gcr.io/distroless/static-debian12:nonroot. This page describes what is in the image, what is explicitly excluded, the security context the image runs under, and how to verify a published image before deployment.

Important: The image runs as nonroot UID 65532 by default. Linux file capabilities (CAP_BPF, CAP_PERFMON, CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE, CAP_SETPCAP) are baked into the agent ELF binary so the nonroot user gains effective capabilities through the standard execve transition. Container runtimes MUST add the same five capabilities to the bounding set (Docker --cap-add, Kubernetes securityContext.capabilities.add) or execve returns EPERM before main() runs.

Image coordinates

Coordinate
Value

Registry host

packages.linuxguard.io

Repository

packages.linuxguard.io/linuxguard-agent

Tag convention

Immutable vX.Y.Z semver tags published per release. Floating tags (:latest, :stable) are anti-patterns in production.

Base image

gcr.io/distroless/static-debian12:nonroot (digest-pinned in the Dockerfile)

Entrypoint

/usr/local/bin/linuxguard-agent

Default CMD

start

Default user

nonroot (UID 65532, GID 65532)

Working directory

Inherited from base (/)

Exposed ports

None — the agent makes outbound HTTPS to the LinuxGuard API; it does not listen on a port

Pin to an immutable digest when reproducibility matters more than upgrade convenience:

docker pull packages.linuxguard.io/linuxguard-agent@sha256:<digest>

What's in the image

The final image contains exactly two artifacts on top of the distroless base:

Path
Contents
Purpose

/usr/local/bin/linuxguard-agent

Statically-linked Go binary, CGO_ENABLED=0, built with tags osusergo,netgo,nocgo,loader_embedded,pid1. File capabilities cap_bpf,cap_perfmon,cap_dac_read_search,cap_sys_ptrace,cap_setpcap=eip are baked into the ELF.

The agent itself.

/usr/local/share/linuxguard/probes.bpf.o

Compiled eBPF object (amd64/arm64), or a zero-byte sentinel on ARMv7.

eBPF probe payload loaded by the in-process loader (build tag loader_embedded).

The base layer additionally provides:

  • /etc/passwd, /etc/group — entries for nonroot UID 65532 and root UID 0.

  • /etc/ssl/certs/ca-certificates.crt — the Mozilla CA bundle for mTLS to the LinuxGuard API (no embedded bundle is required).

  • /tmp — writable temporary directory.

What's NOT in the image

The distroless contract is deliberately minimal. Operators familiar with Debian or Alpine container images will find every diagnostic tool absent. This is by design — the attack surface of an image with no shell and no package manager is dramatically smaller than the equivalent :slim or :alpine variant.

Excluded
Implication

Shell (/bin/sh, /bin/bash)

docker exec -it <ctr> sh does NOT work. Use kubectl debug --image=... or docker exec with a specific command, not an interactive shell.

Package manager (apt, dnf, apk)

The image cannot install additional packages at runtime. Ship them at build time in a custom layer if you need them.

Standard utilities (ls, cat, ps, curl, wget)

Diagnostics from inside the container are limited to what the agent emits to stdout/stderr (its log output) and to its support-bundle collect subcommand.

NSS resolver (/etc/nsswitch.conf, libnss_*)

The agent uses pure-Go user and network resolution (build tags osusergo,netgo). No NSS lookups occur.

Dynamic linker (ld-linux-x86-64.so.2, etc.)

The agent is statically linked (-extldflags "-static"). No .so dependencies exist.

getcap / setcap / libcap2-bin

File capabilities are set in the builder stage and copied through COPY --link to preserve the security xattr. Inspection inside the running container is not possible.

/sys/kernel/tracing (tracefs)

Distroless does not include /sys mounts; tracefs MUST be bind-mounted from the host for probe attach to succeed (see Host paths).

Debugging a distroless container

When you need an interactive shell on a running agent container, do NOT modify the base image. Instead, use a debug ephemeral container that mounts the agent's process namespace:

Or for Docker:

The support-bundle collect subcommand is the canonical diagnostic surface for distroless deployments — see support-bundle CLI reference.

Security context

The image is hardened by default; operators MUST preserve these defaults at the orchestrator layer.

Surface
Default in image
Notes

User

nonroot (UID 65532, GID 65532) — set by base image USER directive

Do NOT override with USER root in a downstream layer; the file capabilities baked into the binary make root unnecessary.

File capabilities (binary)

cap_bpf,cap_perfmon,cap_dac_read_search,cap_sys_ptrace,cap_setpcap=eip

The =eip (effective + permitted + inheritable) suffix demands the same caps in the calling process's bounding set at execve time.

Bounding set requirement (runtime)

NOT set by the image — runtime must add

Docker: --cap-add CAP_BPF --cap-add CAP_PERFMON --cap-add CAP_DAC_READ_SEARCH --cap-add CAP_SYS_PTRACE --cap-add CAP_SETPCAP. Kubernetes: securityContext.capabilities.add: [BPF, PERFMON, DAC_READ_SEARCH, SYS_PTRACE, SETPCAP].

Seccomp profile

NOT set by the image — runtime must override default

Docker's default seccomp profile blocks perf_event_open(2) regardless of CAP_PERFMON. The agent calls perf_event_open via link.Tracepoint() when attaching probes. Use --security-opt seccomp=unconfined for UAT/dev, or a custom seccomp profile that adds perf_event_open to the allowlist for production. The recommended K8s localhostProfile ships in the agent packaging artifacts as linuxguard-agent.seccomp.json.

AppArmor / SELinux profile

NOT set by the image — apply at node level

A reference AppArmor profile (linuxguard-agent.apparmor) ships in the agent packaging tree. Install it on every node via the linuxguard-profile-installer DaemonSet referenced in Kubernetes DaemonSet.

runAsNonRoot

Implied by base image USER directive (UID 65532)

Set runAsNonRoot: true in the Pod spec to enforce it at admission time.

allowPrivilegeEscalation

Should be false at the Pod level

The file caps already provide the required capabilities; no setuid binary needs to escalate.

readOnlyRootFilesystem

Should be true at the Pod level

The agent does not write to the image filesystem; ephemeral state goes to a tmpfs at /run/linuxguard/.

Host paths

The image itself does NOT declare any volume mounts — those are the orchestrator's responsibility. For an image-reference scope, the relevant host paths are the ones the agent expects to find when started in ephemeral or DaemonSet mode. Each per-orchestrator spoke documents the exact mount syntax; the table below catalogs what each path is for.

Host path
Mount mode
Required for
Rationale

/sys/kernel/tracing

read-only

Probe attach via link.Tracepoint()

The agent resolves tracepoint IDs via /sys/kernel/tracing/events/<group>/<name>/id. Distroless does not include /sys mounts; without this bind mount probe attach trips "neither debugfs nor tracefs are mounted" and the agent degrades to DEGRADED_PROBES_PARTIAL.

/sys/fs/bpf

read-write

BPF pinned maps

Required when the in-process loader pins maps for cross-process sharing.

/proc

read-only

Process introspection

The agent walks /proc for the workload-discovery pass on startup; host PID is required for the DaemonSet shape but not for ephemeral mode.

/run/linuxguard

read-write, tmpfs, mode 0700, size 10m

TLS cert cache when --tls-cache is set

Ephemeral mode writes the mTLS cert chain + token-hash tag to this directory. Tmpfs (not a hostPath) so cert material never touches durable storage.

/var/lib/linuxguard

read-write

Typical-service-mode persistence

NOT used by ephemeral mode. The agent never writes to this path when --ephemeral (or PID-1 auto-detection) is active.

Security Note: Mount each host path only if the spoke requires it, and mount it read-only unless explicit write access is justified. Do NOT mount the host root filesystem (/); see the anti-patterns hub section.

Pod Security Standard compatibility

The distroless image itself is a passive artifact — PSS applies to the Pod specification that runs the image, not to the image bytes. Per-orchestrator PSS classification is documented on each spoke; this table summarizes the binding decision.

Pod spec shape
PSS profile
Workable in restricted?

DaemonSet with CAP_BPF + CAP_PERFMON + hostPID: true + tracefs hostPath

privileged

No — restricted disallows added capabilities beyond a small allowlist, host namespaces, and most hostPath volumes.

Sidecar with CAP_BPF + CAP_PERFMON and no host PID

baseline

No — baseline allows the agent's capabilities but restricted does not.

Ephemeral one-shot in restricted cluster

Not currently supported

Requires an explicit AdmissionPolicy waiver granting CAP_BPF + CAP_PERFMON. Consult support.

The image carries no Pod spec opinions — the same image satisfies all three shapes; the difference is the orchestrator manifest.

RBAC

The agent makes no Kubernetes API calls at runtime. Workload identity is derived from the Downward API env vars (LINUXGUARD_NODE_NAME, LINUXGUARD_POD_UID) injected at Pod admission time — see Downward API. Telemetry is shipped over outbound mTLS to the LinuxGuard API, not via the Kubernetes apiserver.

Consequently, the distroless image requires no ServiceAccount RBAC binding of its own. The Pod runs under a ServiceAccount (the namespace default SA is acceptable), but no Role, ClusterRole, RoleBinding, or ClusterRoleBinding needs to be created for the agent to function.

RBAC is documented per-spoke only where the spoke's lifecycle requires it (e.g., the profile-installer DaemonSet referenced in Kubernetes DaemonSet requires its own ServiceAccount because it writes seccomp + AppArmor profiles to host paths).

Image signing and verification

Published images are signed at release time. Verify the signature before deployment:

The verification step confirms two facts: the image was built by the LinuxGuard release pipeline (not a fork or a typosquatted registry), and the signing transparency log entry exists. A successful verification prints the certificate's subject and the Rekor log index.

If cosign verify fails, do NOT deploy the image. Open a support case and pin to the most recent verified version while the cause is investigated.

For the OCI multi-arch manifest behavior and per-platform digest stability, see OCI Multi-Arch Manifest.


Next Step: Ephemeral mode →

Related: Container deployment hub | OCI multi-arch manifest | start CLI reference | support-bundle CLI reference

Last updated

Was this helpful?