Operationalizing Hardened Containers: The Scan Is Not the Job

Operationalizing Hardened Containers: The Scan Is Not the Job

Series: From Container to Cluster, Part 2 of 4

Part 1 ended with a warning. When your program adopted containers, it inherited a software supply chain built by strangers. This post is about what you do with that inheritance. Specifically, it is about the gap between having hardened containers and operating hardened containers, because those are very different problems and the second one is where programs actually fail.

What "hardened" means when it means something

A hardened container image is one where the attack surface has been deliberately reduced and the remaining contents are known, current, and justified. In practice that means several things stacked together.

Minimal contents. Every binary, library, and package in the image is a potential vulnerability. Hardening starts by removing everything the application does not need to run. No package managers, no shells, no debugging tools riding along into production because they were convenient during development.

Patched and current. The packages that remain are at versions with known CVEs remediated. Not "remediated as of the quarter we built it." Remediated now.

Provenance and attestation. You can prove where the image came from, what went into it, and that it has not been modified since. Signatures on the image. A software bill of materials describing its contents. An audit trail an assessor can actually follow.

Configuration that assumes hostility. Non-root by default. Read-only file systems where possible. No secrets baked into layers.

Most teams can produce an image like this once. That is a project. The problem is that hardening is not a state. It is a rate.

The treadmill nobody budgets for

New CVEs are published every day. An image that scanned clean in March is carrying known vulnerabilities by June without a single byte changing. The image did not get worse. The world's knowledge of it got better.

So operationalizing hardened containers means rebuilding constantly. Every base image update, every upstream patch, every new CVE disclosure triggers a rebuild, a rescan, a re-test, and a redeployment. Multiply that across the dozens or hundreds of distinct images a real platform runs, and you have a full-time engineering function. Programs that treat hardening as a one-time compliance gate discover this about ninety days after their ATO, when the first continuous monitoring report comes back red.

This is the honest math. You can staff that function yourself, or you can consume hardened images from someone whose entire job is running that treadmill. Most programs discover they cannot staff it. The container hardening backlog quietly becomes the platform team's largest work category, crowding out the mission work the platform exists for.

The consumption problem

Suppose you solve the supply side. Hardened images exist, rebuilt continuously, scanned, signed, documented. You still have to get them into your pipelines, and this is where good intentions go to die.

The failure mode looks like this. The hardened images live in some approved repository. Developers have to find the right one, rewrite their Dockerfiles against unfamiliar base images, chase down missing packages, and repeat that work every time upstream changes. The friction is high enough that teams quietly drift back to public images, and six months later a scan finds docker.io references all over the cluster. Nobody was malicious. The secure path was just harder than the insecure one.

The design principle that fixes this: the hardened path has to be the path of least resistance. This is exactly how we built Ghost, AlphaBravo's hardened container registry. Ghost takes the upstream open source images teams already use, hardens them continuously, and serves them from the Ghost registry. Adoption is one credential and a one-line change: the image reference in your manifest points at Ghost instead of the public registry. Same image names your teams already know. No Dockerfile rewrites. No new build process. The developer workflow does not change, which is precisely why it sticks.

However you solve it, with Ghost or otherwise, judge the solution by that test. If adopting the hardened image requires developers to change how they work, they eventually won't.

Enforcement: trust, then verify, then block

Hardened images available and easy to consume is necessary. It is not sufficient. Production needs a gate.

Admission control is where policy becomes real. The cluster refuses to run images that are not signed by your trusted authority, not sourced from your approved registry, or not accompanied by current scan results. This turns "we use hardened containers" from a policy memo into a mechanical fact. An unsigned image from a public registry does not generate a finding. It does not run.

Pair that with runtime posture: containers running as non-root, capabilities dropped, file systems read-only, resource limits set. The hardened image gets you a clean start. Runtime constraints keep a compromised process from turning one bad container into a bad cluster.

What the assessor sees

There is a compliance dividend to doing this right, and it is worth naming because it is often what gets the budget approved.

A program running continuously hardened images from a controlled registry, enforced by admission policy, with SBOMs and signatures on everything, walks into a continuous monitoring review with evidence instead of narrative. The POA&M shrinks because the vulnerability backlog is being burned down upstream, before images ever reach the cluster. The assessor's questions get boring. Boring assessments are the goal.

Where this series goes next

Hardened containers running on a compromised orchestrator are hardened containers working for the adversary. Part 3 moves up a layer to Kubernetes itself: the API server, the RBAC model, the network policies, and all the ways a default cluster configuration betrays you.


Ghost is AlphaBravo's hardened container registry. Continuously hardened upstream images, delivered with one credential and a one-line change. Learn more at seeghost.dev.