Build in progress. This page will be updated with the repository link and recorded attack demonstrations on completion.
The problem
Container image scanning tells you whether the artifact you inspected was safe. It tells you nothing about whether the artifact running in your cluster is that same artifact — or whether the workload running it can reach anything it shouldn’t.
Most platforms scan. Few verify. Almost none test that either actually works.
The architecture
Seven independent enforcement layers, each verified by attacking it.
| Layer | Control | Enforced by |
|---|---|---|
| 1 | SBOM, vulnerability scan, keyless signature | Syft · Trivy · Cosign |
| 2 | Signed commits, restricted deployment scope | ArgoCD AppProject |
| 3 | Admission policy — signature, privilege, registry, limits | Kyverno |
| 4 | Pod Security Admission at restricted | Kubernetes |
| 5 | Default-deny network policy (L3/L4) | NetworkPolicy |
| 6 | STRICT mTLS, identity-based authorization, egress allowlist (L7) | Istio |
| 7 | Runtime behavioural detection | Falco |
Verification
Each control is tested by trying to defeat it, with the terminal output recorded.
| Attack | Result |
|---|---|
| Deploy an unsigned image | Rejected at admission |
| Deploy a privileged container | Rejected at admission |
| Pull from an untrusted registry | Rejected at admission |
| Call a service from an unauthorised workload | RBAC: access denied at the sidecar |
| Exfiltrate to an undeclared external host | Blocked by egress policy |
| Modify a live resource by hand | Reverted by GitOps reconciliation |
| Spawn a shell inside a container | Detected and alerted by Falco |
The detail that matters most
The admission policy does not merely require a signature. It requires one produced by a specific CI workflow, in a specific repository, on a specific branch, verified against the Sigstore transparency log.
An attacker with full write access to the container registry still cannot get an image admitted. Compromising the registry is not sufficient — they would need to compromise the identity of the build workflow itself.
Design decisions
Sign the digest, not the tag. Tags are mutable; a signature bound to :v1 is invalidated the moment someone repoints the tag. Digests are immutable and are what the cluster actually pulls.
Keyless signing. Sigstore issues a short-lived certificate bound to the CI workflow’s OIDC identity. There is no long-lived signing key to store, rotate or lose.
NetworkPolicy and Istio authorization together, not either/or. NetworkPolicy matches on labels, which any workload author can set. Istio matches on mTLS workload identity, which cannot be asserted without the certificate. They defend against different attackers.
Audit before Enforce. Every admission policy runs in Audit mode first. Deploying admission control straight to Enforce on a live cluster is how you break production and lose the mandate to secure anything.
Relationship to my production work
This is the same default-deny with an explicit allowlist architecture I run in production for host firewalls across a Linux fleet — applied here at seven layers, from the CI pipeline down to the kernel.
The firewall enforces at L3/L4 on source address and port. Istio enforces at L7 on cryptographically verified workload identity. Same design, different layer, and the combination is what zero trust actually means in practice.
Limitations
This runs on a single-node k3s cluster. A production deployment would additionally require: etcd encryption at rest verified on a managed control plane, multi-node network policy testing across a real CNI, workload identity federation to cloud IAM (IRSA or equivalent), external secrets management rather than in-cluster secrets, and centralised log aggregation for the Falco stream.
The policy set is a working baseline, not a complete control catalogue.