You know what keeps me up at night, besides webhooks that fire into the void and CRM APIs that change their OAuth scopes without warning? The thought of a compromised container image, blessed by CI/CD, happily deployed across my production cluster because we only checked for a tag and not a cryptographic provenance. The SLSA framework is a fantastic blueprint for supply chain integrity, but blueprints don't enforce themselves. You need a bouncer at the club door. In our world, that bouncer is OPA Gatekeeper, and I've spent the last quarter making it check SLSA tickets.
The core challenge is translating SLSA's requirements—like "verified build provenance" and "two-person reviewed source"—into concrete, machine-readable policy for Kubernetes admission control. You're not just checking an image signature; you're validating that the attestations *about* the build process exist and satisfy predicates. This requires a two-pronged approach: constraints that target the image, and constraints that target the attestations stored alongside it.
First, you need a `ConstraintTemplate` that defines the logic for checking a specific SLSA level. Below is a simplified one for enforcing that images come from a trusted registry *and* have a known, verifiable provenance. It uses Gatekeeper's Rego, which, let's be honest, is its own special kind of middleware horror story, but it gets the job done.
```yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sslsalevel2
spec:
crd:
spec:
names:
kind: K8sSLSALevel2
validation:
openAPIV3Schema:
properties:
allowedRepos:
type: array
items:
type: string
requiredProvenanceTypes:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper/v1beta1
rego: |
package k8sslsalevel2
violation[{"msg": msg}] {
input.review.object.kind == "Pod"
some container := input.review.object.spec.containers[_]
not image_check(container.image)
}
image_check(image) {
# 1. Parse repo/name:tag
repo := parse_repo(image)
# 2. Enforce repo allow list
repo_matches_allowed(repo)
# 3. (Mock) In real life, you'd call to a verifier service here.
# This would validate the in-toto attestation against public keys
# and check the predicate details.
has_valid_provenance(image)
}
repo_matches_allowed(repo) {
allowed_repos := input.parameters.allowedRepos
allowed := {r | r := allowed_repos[_]}
repo in allowed
}
has_valid_provenance(image) {
# Placeholder for actual attestation fetch & verify logic.
# You'd likely need a sidecar or external data provider for this.
true
}
```
Then, you apply a concrete `Constraint` that uses this template, pinning it to your specific infrastructure.
```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sSLSALevel2
metadata:
name: prod-images-must-be-slsa2
spec:
enforcementAction: deny
parameters:
allowedRepos:
- "gcr.io/trusted-projects/"
- "ghcr.io/my-org/"
requiredProvenanceTypes:
- "https://slsa.dev/provenance/v0.2"
```
The real devil is in the details, of course:
* **Attestation Verification:** Gatekeeper's Rego isn't a cryptography library. You'll need to offload the actual signature verification and predicate parsing. My current pattern involves a small, audited sidecar that exposes a simple HTTP API for verification; the Rego rule makes an `http.send` call to it. Yes, it's another service to manage. Welcome to the glue factory.
* **Performance:** Admission control is a hot path. Adding complex HTTP calls to verify every single pod spec will add latency. You'll need caching, optimistic validation, and possibly a move towards a policy-as-data model with Gatekeeper's `external-data` provider.
* **False Positives & Developer Experience:** Prepare for the flood of "my pod won't start" tickets when someone tries to run a `busybox:latest` for debugging. You'll need exclusions, dry-run modes, and clear error messages that tell the dev exactly which SLSA requirement their image failed.
In practice, this moves compliance from a "hopefully the pipeline did it" to a "the cluster *physically will not run* non-compliant workloads" model. It's a significant piece of custom middleware, but after the third "security scare" stemming from an unvetted base image, the investment starts to look pretty reasonable. Has anyone else tried to codify SLSA (or similar) into Gatekeeper? I'm particularly curious about strategies for handling the attestation verification without making the admission controller a bottleneck.
APIs are not magic.