Container hardening
What this page is
Stigmem's reference node image ships with a hardened container posture as of pre-reset hardening (Spec-10-Hardening). This page describes the controls baked into the image and how to verify them.
What's includedโ
node/Dockerfile.uv, compiler, and pip are absent from the shipped image./tmp and /run are tmpfs.CAP_DROP ALLno-new-privilegesdeploy/seccomp/stigmem-node.jsonsyft-generated SPDX JSONcosign keyless (Sigstore)Image referenceโ
ghcr.io/eidetic-labs/stigmem-node:<tag>
The hardened image is published for linux/amd64 and linux/arm64.
The <tag> placeholder above stands in for the tag you choose. For
supply-chain-conscious deployments use @sha256:<digest> instead โ a
digest pin is tamper-evident and immune to tag reassignment. See the
tag-selection guide for
the full breakdown.
Verifying the image signatureโ
# Requires cosign โฅ 2.x
cosign verify \
--certificate-identity-regexp "https://github.com/eidetic-labs/stigmem/.github/workflows/publish.yml" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/eidetic-labs/stigmem-node:<tag>
A successful verification prints the signing certificate and Rekor log entry.
Verifying the SBOMโ
# Download the SBOM attached to a specific digest
cosign download sbom ghcr.io/eidetic-labs/stigmem-node@<digest> \
| python3 -m json.tool | head -40
# Or pull it with oras (OCI referrers API)
oras discover --platform linux/amd64 \
ghcr.io/eidetic-labs/stigmem-node:<tag>
Running with the seccomp profileโ
Docker / Composeโ
The profile is shipped at deploy/seccomp/stigmem-node.json. The
deploy Compose recipe loads it automatically:
docker compose -f deploy/compose/docker-compose.yml up -d
For a manual docker run:
docker run -d \
--user 65532:65532 \
--read-only \
--tmpfs /tmp:mode=1777,size=64m \
--tmpfs /run:mode=755,size=16m \
--cap-drop ALL \
--security-opt no-new-privileges \
--security-opt seccomp=deploy/seccomp/stigmem-node.json \
-v stigmem-data:/data \
-e STIGMEM_DB_PATH=/data/stigmem.db \
-p 8765:8765 \
ghcr.io/eidetic-labs/stigmem-node:0.9.0a1
For audit-traceable production, replace :0.9.0a1 with
@sha256:<digest> โ see the
tag-selection guide.
Helm chart hardening defaults and Fly.io micro-VM guidance lived
alongside the v1.0 deploy recipes. Those recipes are deferred to
experimental/deploy-helm/
and
experimental/deploy-fly/
in v0.9.0a1 and are unsupported until they pass the
ADR-008 reintroduction gates.
The Docker and Docker Compose hardening guidance above is the
supported v0.9.0a1 surface.
Build reproducibilityโ
The Dockerfile pins the uv version using Docker's --from copy
syntax:
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
For fully reproducible builds, pin the digest:
COPY --from=ghcr.io/astral-sh/uv:0.6.14@sha256:<digest> /uv /usr/local/bin/uv
And pin the base image tag in node/Dockerfile to a specific digest
as well.
What the seccomp profile blocksโ
deploy/seccomp/stigmem-node.json uses a denylist strategy
(default ALLOW) and explicitly blocks the following syscall classes.
Process injection
ptrace, process_vm_readv, process_vm_writev.
Kernel module loading
init_module, finit_module, delete_module.
kexec
kexec_load, kexec_file_load.
Namespace manipulation
Container escape vectors: pivot_root, mount, umount2, unshare, setns, open_tree, move_mount, fsopen, fsconfig, fsmount, fspick.
eBPF
bpf, perf_event_open.
Kernel time adjustment
adjtimex, clock_adjtime, settimeofday, clock_settime.
Privileged I/O
iopl, ioperm.
Key ring
add_key, keyctl, request_key.
Misc dangerous
reboot, syslog, chroot, acct, swapon, swapoff, userfaultfd, seccomp, quotactl.
io_uring
CVE-2022-29582, CVE-2023-2598, CVE-2022-2586: io_uring_setup, io_uring_enter, io_uring_register โ blocked because Python/uvicorn does not use io_uring and the interface has accumulated significant kernel exploit history.
Shocker-class escape
Host inode access via bind-mount: open_by_handle_at, name_to_handle_at.
Cross-process disclosure
kcmp.
The clone/clone3 syscalls are NOT denied.
Python's threading model requires them. Namespace-related misuse is
blocked by the missing CAP_SYS_ADMIN capability,
providing defense-in-depth.
Known limitationsโ
Per-distro AppArmor profiles
Out of scope for pre-reset hardening; community contributions welcome.
Multi-arch matrix
Covers linux/amd64 and linux/arm64 only.
Helm RuntimeDefault
seccompProfile.type: RuntimeDefault Helm default does not apply the stigmem-specific profile; operators who want the full denylist must load the JSON file as a Localhost profile.