Skip to content
back to the map
practice
stage: proteger
4 min read

Containers - images and supply chain

Layered images inherit privileges: CVE scanning, signing and a rootless runtime shrink the surface the container hands to the host.

DockerFalcoTrivyCosign

What it is

A container is a Linux process isolated by namespaces and cgroups, running a filesystem stacked in layers. Each layer is a decision: the base you pull, the apt install you run, the user that opens the shell, the binary that goes in. Each one becomes part of the surface the attacker finds.

Two principles solve 80% of the defense: minimal images (less stuff, fewer bugs) and a hardened runtime (less privilege, fewer paths). The rest is process: scanning, signing, policy.

Minimal base image

The base image is the foundation of everything that follows. ubuntu:latest or python:latest bring a shell, a package manager and a set of CVEs that grows every week. For production, choose a base that has only what the binary needs to run.

  • distroless (gcr.io/distroless/*): no shell, no apt, no package manager. For static Go, Java, Node, Python applications
  • alpine: busybox + musl, ~5MB, still has a shell but is much smaller than Debian
  • scratch: nothing, just the binary. Valid for statically compiled Go/C/Rust binaries
  • wolfi/chainguard: distroless with an audited supply chain and daily rebuilds

Trusted registry and signing

Knowing where it came from is worth more than knowing what is inside. Private registries (ECR, GCR, Harbor) give control over who publishes, with SSO and audit. Signing proves integrity: the image that is running is exactly the one CI built.

Cosign (from the Sigstore project) signs and verifies OCI images. The key pair can come from the team itself, from a (key stays in an HSM), or from Fulcio, which issues an ephemeral certificate based on an OIDC login (useful for CI without secrets).

verify image at deploybash
# sign on push
cosign sign --key cosign.key ghcr.io/loja/checkout@sha256:abc123

# verify before starting (admission controller or pre-deploy job)
cosign verify \
  --key cosign.pub \
  --certificate-identity-regexp 'https://github.com/loja/checkout/.github/workflows/release.yml@refs/tags/.*' \
  ghcr.io/loja/checkout@sha256:abc123

Image scanning: finding CVEs before shipping

Scanners compare the image's (or each layer) against vulnerability databases (, GHSA, OSV). The output is the list of packages and CVEs, with severity and fixed version. It runs at three moments: at build (blocks a PR with a critical CVE), in the registry (finds a new CVE against an already published image) and at admission (rejects a pod with an unscanned image).

  • Trivy: a single scanner (FS, image, , SBOM), runs offline, no central database
  • Grype (Anchore): focus on images and CycloneDX SBOM
  • Docker Scout: integrated with Docker Hub, uses the SBOM that Docker builds natively
  • Snyk Container: commercial, good for teams already using Snyk for

Run as non-root and harden the runtime

A container running as UID 0 on the host is a root process on the host. If the attacker escapes the container, they already have administrative privileges on the node. Same with writable filesystems: it marks where the attacker will try to persist. Hardening the runtime is cutting paths before they exist.

Insecure Dockerfiledockerfile
FROM python:latest
RUN apt-get update && apt-get install -y curl netcat
COPY . /app
WORKDIR /app
EXPOSE 8080
CMD ["python", "app.py"]    # runs as root (UID 0)
Fixed Dockerfiledockerfile
# minimal base, no shell, multi-stage so dev deps are not inherited
FROM python:3.12-slim AS builder
WORKDIR /build
RUN pip install --no-cache-dir -r requirements.txt

FROM gcr.io/distroless/python3-debian12
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY . /app
USER 65532                       # fixed non-root UID
EXPOSE 8080
ENTRYPOINT ["python", "/app/app.py"]

Where it fits

Containers touch build, deploy and runtime. At build, the scan gates the PR. In the registry, signing authenticates the origin. At admission, the cluster rejects an unsigned image or one with a policy violation. At runtime, the watches behavior (next topic). Skipping any of these links opens a window.

Strengths

  • immutability: the same image that was tested is the one that ships, with no 'works on my machine'
  • minimal images cut CVEs by an order of magnitude: distroless Python has ~20 packages, Debian has ~600
  • signatures and SBOM give real traceability, piece by piece, down to the installed package

Limitations

  • scanning finds known CVEs: a in a dependency gets through, and signing does not help with that
  • distroless and scratch make debugging harder (no shell). It is the trade-off between security and ergonomics, not a bug
  • runtime policies (non-root, read-only fs) must be accepted by the application: not every binary starts without root, and rewriting takes time
CVEcommon vulnerabilities and exposuresThe unique identifier of ONE specific public vulnerability, in the format CVE-YEAR-NUMBER. E.g., CVE-2021-44228 is Log4Shell. It is the real instance, not the class of the problem.see in glossary →KMSkey management serviceA managed service that creates, stores and controls the use of cryptographic keys. The application rarely touches the master key: it asks the KMS to encrypt or decrypt, and the provider records every use in an auditable log. Without a KMS, the key ends up on disk and becomes a target.see in glossary →SBOMThe software's ingredient list: dependencies, versions, licenses and hashes, in a standard format.see in glossary →NVDnational vulnerability databaseNIST's database that enriches each CVE with a CVSS score and an associated CWE. It is where most SCA tools get their data.see in glossary →IaCinfrastructure as codeDescribing infrastructure in versioned files (Terraform, Ansible). It brings review, history and testing to configuration, but replicates mistakes at scale if it is not scanned.see in glossary →SCAComposition analysis: inventories third-party dependencies and cross-references them with known CVEs.see in glossary →CWPPcloud workload protection platformMonitored protection for running workloads: VMs, containers, serverless functions. It combines visibility into what runs (processes, syscalls, network) with prevention (blocking execution, isolating anomalies). It is endpoint security reworked for the ephemeral reality of the cloud.see in glossary →Zero-dayA vulnerability exploited before a public fix exists. Against a zero-day, only defense in depth and detection help in the moment.see in glossary →

connections on the map

updated on 14/10/2026 · sources to go deeper · report an error

in other domains

  • Containers and imagesdevopsthe good image and the secure cluster: two halves of the same problem
  • Kubernetes fundamentalsdevopsthe same cluster seen as a platform and as an attack surface
  • SCAappsecfeeds into: the image inherits the dependencies
  • SBOMappsecinventories what goes inside the image

Study before

Unlocks

test what you learned

Loading questions…