PodArmor docs
Security

Hardening practices

What each "hardened" property actually means + how to verify it.

PodArmor's TrustHeadline chip row and HardeningBadges on every image card aren't decorative — each badge reflects a property we apply at build time and you can verify externally.

Non-root

Every image runs as a non-root UID by default. For our deploy images (distroless), that's UID 65532 (nonroot in Google's distroless convention). For our build images, it's a deliberately-created podarmor user with UID 65532.

Verify:

docker run --rm <image> id
# uid=65532(nonroot) gid=65532(nonroot)

The Dockerfile's last USER directive is USER 65532:65532, and there's no USER root anywhere later. Customers can override at runtime if they need to (docker run --user 0:0), but the image's default never runs as root.

No SUID / SGID

Build-time step strips every SUID / SGID bit on every file in the image:

RUN find / -xdev \( -perm -4000 -o -perm -2000 \) -type f \
    -exec chmod -s {} + 2>/dev/null || true

This blocks the most common Linux privilege-escalation path inside a container even if the runtime accidentally allows it.

Verify:

docker run --rm <image> find / -xdev \( -perm -4000 -o -perm -2000 \) -type f
# (no output)

No shell / no package manager (deploy images only)

Distroless images by definition contain no /bin/sh, no apt, no dpkg, no curl. There's no interactive shell to drop into, no way for a runtime exploit to spawn apt-get install.

Verify:

# This should error.
docker run --rm --entrypoint /bin/sh <image> -c "echo hi"
# OCI runtime exec failed: exec failed: unable to start container process: ...

Build images intentionally keep /bin/sh because Maven's mvn wrapper script needs it. But they still don't have apt, dpkg, or any package manager — we strip those after the user is created.

CIS Section 4 aligned

The image-level checks from the CIS Docker Benchmark Section 4:

CheckDescriptionHow we satisfy it
4.1Create a user for the containerNon-root by default
4.3Do not install unnecessary packagesAggressive dpkg --purge --force-all of unused packages
4.4Scan and rebuild for security patchesContinuous re-scan; auto-rebuild on upstream patches
4.6Add HEALTHCHECKEvery image's Dockerfile has a HEALTHCHECK directive
4.7Do not use update instructions aloneVersions pinned everywhere
4.8Remove setuid/setgid permissionsSUID/SGID stripped at build time
4.9Use COPY instead of ADDConfirmed
4.10Do not store secrets in DockerfilesConfirmed
4.11Install verified packages onlyAdoptium tarballs sha256-verified; apt packages from official Debian repos

CIS Section 5 (runtime checks like --cap-drop, --read-only, seccomp profile) is the responsibility of your orchestrator (Kubernetes, ECS, etc.) — not something an image can enforce by itself.

SBOM included

Every image-version ships with syft-generated SBOMs in both SPDX 2.3 and CycloneDX 1.5 formats. The portal exposes download endpoints; the SBOMs are also published as OCI referrers on the image manifest, discoverable with cosign tree or oras discover.

See Download an SBOM for details.

Signed with Cosign

Every image is signed using Cosign keyless mode (OIDC against GitHub Actions). The transparency-log entry is publicly verifiable on Rekor.

See Verify a Cosign signature for the verification command.

What's not in every image (yet)

  • Multi-arch. Some images publish both linux/amd64 and linux/arm64; some publish amd64 only. The TrustHeadline chip surfaces this honestly per-image.
  • FIPS. No FIPS variants today. When we ship them, they'll carry a real FIPS chip; until then the chip is absent.
  • STIG. Same — no claim until we've actually run the validation.

On this page