End-to-end supply chain security: GitHub Actions CI pipeline with Cosign signing, Syft SBOM generation, Grype vulnerability scanning, SLSA provenance, and Kyverno admission enforcement on EKS
On March 31, 2026, a missing line in a packaging config file exposed 512,000 lines of Anthropic's internal Claude Code source to the public npm registry. Within 24 hours, attackers had registered fake packages mimicking the leaked internals to drop malware on developers. No sophisticated hack — one oversight. That's all it takes.
Most pipelines I'd seen — including ones I'd built — had the same gap: they build, push, and ship. No one could answer "can I prove what's running in production is exactly what was built from this commit, hasn't been tampered with, and has no critical vulnerabilities?" So I built a pipeline that can.
Stack
What I Built
A production-grade supply chain security pipeline on AWS EKS. Every image that runs in the cluster has to prove its identity before it's allowed in. The CI pipeline (GitHub Actions) runs automatically on every push.
Docker image tagged with the exact Git SHA. Never latest. One commit, one image, full traceability.
Cosign keyless signing by image digest using GitHub's OIDC token. No long-lived keys to manage.
Syft generates a CycloneDX bill of materials listing every OS package and Python dependency inside the image.
Grype scans the SBOM. Critical CVE found? Pipeline fails. The image never reaches the registry.
The SBOM is cryptographically attached to the image in ECR — not just uploaded somewhere and forgotten.
The SLSA GitHub Generator produces a Level 2 provenance attestation, independently signed, recording exactly how and from where the image was built.
Admission Enforcement with Kyverno
At deployment, Kyverno (a Kubernetes admission controller) enforces three policies before any pod starts:
Try to run nginx:latest in the cluster — Kyverno blocks it immediately. An image that passed the full pipeline is admitted without issue.
Observability
After deployment, everything is observable. Prometheus scrapes Kyverno's admission metrics. A Grafana dashboard shows allowed vs. blocked requests, image verification results, and webhook latency in real time.
A custom SBOM query service lets you ask "which images contain this package?" or "which images are affected by this CVE?" and get an answer in milliseconds.
Infrastructure
Infrastructure is Terraform (EKS, VPC, ECR, IAM). Deployment is Helm, referencing images by digest — not tag. If the digest doesn't match a signed, attested, SLSA-provenance-bearing image in ECR, it doesn't run.
The Oops
Halfway through I had ECR tag immutability turned on. Seemed like the obviously secure choice.
Then the SLSA provenance job started failing. Turns out both the SBOM attestation step and the SLSA generator write to the same tag suffix in ECR. With immutable tags, the second write fails every time — permanently.
I had it backwards. Tag immutability is the wrong control. Tags are just labels — mutable by design, and any attestation tooling will hit this wall. The real security is referencing images by digest in Helm and enforcing that at admission with Kyverno. A digest is content-addressable and can't be faked. A tag can be moved to anything.
I set ECR tags back to mutable and moved on. Security didn't get weaker — it never depended on tag immutability to begin with. That's the kind of thing you only learn by building it end to end.