Getting Started

ARMORRED provides drop-in replacements for popular container images with security hardening applied at build time and supply chain verification built in. This guide walks through pulling, verifying, and running your first ARMORRED image.

Prerequisites

Before using ARMORRED images, ensure you have:

  • Container runtime: Podman (recommended) or Docker
  • cosign (optional but recommended): For verifying image signatures
  • Basic understanding: Familiarity with container security concepts

Install cosign for signature verification:


$ curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
$ chmod +x cosign-linux-amd64
$ sudo mv cosign-linux-amd64 /usr/local/bin/cosign

Choosing an Image Tier

ARMORRED images come in two security tiers:

  • Hardened: Guaranteed drop-in replacement for the upstream image. All upstream features retained. Start here.
  • Locked: Not guaranteed to be a 100% drop-in replacement. Drops some rarely-used features for a more aggressive hardening posture.

See the Hardened vs Locked page for detailed comparisons and guidance on which tier to choose.

Pulling an Image

ARMORRED images are hosted on GitHub Container Registry (ghcr.io). Pull the nginx hardened image:


$ podman pull ghcr.io/armorred/nginx:1.26-hardened
[+] Trying to pull ghcr.io/armorred/nginx:1.26-hardened...
[+] Getting image source signatures
[+] Copying blob sha256:3b0e7da72f4b
[+] Copying config sha256:0552e08b1d4e
[+] Writing manifest to image destination
[+] Storing signatures

Available images:

ImageRegistry Path
NGINX 1.26 (hardened)ghcr.io/armorred/nginx:1.26-hardened
NGINX 1.26 (locked)ghcr.io/armorred/nginx:1.26-locked
MariaDB 11.4 (hardened)ghcr.io/armorred/mariadb:11.4-hardened
MariaDB 11.4 (locked)ghcr.io/armorred/mariadb:11.4-locked

Use the latest alias to automatically pull the most recent version:


$ podman pull ghcr.io/armorred/nginx:latest-hardened

Verifying Image Signatures

ARMORRED images are signed with Sigstore cosign. The public key is available at https://armorred.org/cosign.pub. Verify the signature before running:


$ cosign verify --key https://armorred.org/cosign.pub \
ghcr.io/armorred/nginx:1.26-hardened

Verification for ghcr.io/armorred/nginx:1.26-hardened --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key

If verification fails, do not run the image. Signature verification ensures:

  • The image was signed by the ARMORRED project's private key
  • The image has not been tampered with since publication

Running the Image

ARMORRED images are configured to listen on unprivileged port 8080 by default, enabling non-root execution without requiring NET_BIND_SERVICE capability. Start nginx:


$ podman run -d --name nginx \
--tmpfs /tmp:rw \
--tmpfs /var/log/nginx:rw \
-p 8080:8080 \
ghcr.io/armorred/nginx:1.26-hardened

$ curl http://localhost:8080
<!DOCTYPE html>
<html>
<head><title>Nginx</title></head>
<body><h1>Nginx is running</h1></body>
</html>

The --tmpfs mounts provide writable directories for nginx temporary files and logs while keeping the root filesystem read-only capable.

The hardened image runs identically to upstream nginx but with:

  • 87% fewer components (19 vs 150 packages)
  • 38% smaller size (121 MB vs 196 MB)
  • 99% fewer vulnerabilities (1 vs 117 CVEs)
  • Binary hardening (PIE, RELRO, stack canaries, SafeStack)

Inspecting the Image

Check which tier you are running:


$ podman inspect ghcr.io/armorred/nginx:1.26-hardened | jq '.[0].Config.Labels'
{
"org.armorred.base": "scratch",
"org.armorred.tier": "hardened",
"org.opencontainers.image.description": "Hardened Nginx 1.26.3 (hardened tier)",
"org.opencontainers.image.title": "nginx",
"org.opencontainers.image.version": "1.26.3"
}

View the complete SBOM (Software Bill of Materials):


$ cosign download sbom ghcr.io/armorred/nginx:1.26-hardened > sbom.json
[+] Downloading SBOM attestation
[+] SBOM saved to sbom.json

$ jq '.components | length' sbom.json
19

For a comprehensive guide to working with SBOMs, see Understanding SBOMs.

Comparing with Upstream

To understand the impact of hardening, compare the ARMORRED image against the official upstream image:


$ podman images
REPOSITORY TAG SIZE
ghcr.io/armorred/nginx 1.26-hardened 121 MB
docker.io/library/nginx 1.26.3 196 MB

Check binary hardening features:


$ podman run --rm ghcr.io/armorred/nginx:1.26-hardened \
checksec --file=/nix/store/...-nginx-1.26.3/bin/nginx

RELRO STACK CANARY NX PIE SAFESTACK
Full RELRO Canary found NX enabled PIE enabled Enabled

Compare vulnerabilities using Grype:


$ grype ghcr.io/armorred/nginx:1.26-hardened
[+] Critical: 0, High: 1, Medium: 0, Low: 0

$ grype docker.io/library/nginx:1.26.3
[+] Critical: 18, High: 25, Medium: 57, Low: 11

Next Steps

For production deployments, implement runtime security controls (capabilities, seccomp, read-only filesystems) as described in the Runtime Protections guide.