Kubernetes Security Auditing: Automating Trivy with Admission Controllers
Master Kubernetes security auditing by automating Trivy scans with admission controllers. Prevent vulnerable container images from deploying to your cluster.
Why Manual Scanning Fails at Scale
I’ve seen too many teams treat Kubernetes security as a post-deployment checklist. They run a scan, find a mountain of CVEs, and then spend three days patching things that shouldn't have been deployed in the first place. If you’re relying on your developers to manually run Trivy scans before pushing to the registry, you’re already losing.
To build a robust DevSecOps pipeline, you need to shift security left—all the way to the cluster gatekeeper. By integrating container scanning directly into the deployment workflow using Admission Controllers, you ensure that no image hits your nodes unless it meets your security threshold.
The Strategy: Admission Controllers as Gatekeepers
Kubernetes Admission Controllers are the secret sauce here. Specifically, we'll use a Validating Admission Webhook. When a kubectl apply hits the API server, the webhook intercepts the request, checks the image against a Trivy scan report, and denies the request if it finds critical vulnerabilities.
Prerequisites
- A Kubernetes cluster (v1.24+)
- Trivy (v0.48.0+)
- Kyverno or OPA Gatekeeper (I prefer Kyverno for its simplicity)
Implementing the Guardrails
We aren't going to build a custom webhook from scratch—that’s a maintenance nightmare. Instead, we’ll use Kyverno to trigger Trivy-based security checks.
Step 1: Deploy Trivy Operator
The Trivy Operator automatically scans your cluster resources. Install it via Helm:
Bashhelm repo add aqua https://aquasecurity.github.io/helm-charts helm install trivy-operator aqua/trivy-operator \ --namespace trivy-system \ --create-namespace
Once installed, the operator creates VulnerabilityReport custom resources for every pod in your cluster. This is the data we'll use to make our "go/no-go" decisions.
Step 2: Configure the Admission Policy
Now, we create a Kyverno ClusterPolicy that blocks deployments containing images with "CRITICAL" vulnerabilities.
YAMLapiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: block-critical-vulnerabilities spec: validationFailureAction: Enforce background: false rules: - name: check-trivy-vulnerabilities match: resources: kinds: - Pod validate: message: "Deployment blocked: Image contains CRITICAL vulnerabilities." pattern: metadata: annotations: trivy-operator.aquasecurity.github.io/vulnerability-report-status: "scanned" trivy-operator.aquasecurity.github.io/critical-vulnerabilities: "0"
Step 3: Testing the Gate
Try deploying a known vulnerable image, like nginx:1.14.2.
Bashkubectl run vulnerable-pod --image=nginx:1.14.2
If your policy is active, the API server will reject the request with a clean, descriptive error message. You've just stopped a vulnerability before it became a runtime risk.
Lessons from the Field
- Don't block everything on Day 1: Start with
validationFailureAction: Audit. This logs violations without breaking your current deployments. Once your teams fix the backlog, flip it toEnforce. - Handle exceptions: You'll inevitably have legacy apps that can't be patched immediately. Use Kyverno
excluderules based on specific namespaces or labels. - Monitor the scanner: If the Trivy Operator hangs, your deployments will hang. Ensure you have proper resource limits set on the operator pods to prevent OOM kills.
Why This Matters
By automating Kubernetes security, you remove the human element from the compliance process. Developers get instant feedback in their CI/CD logs, and you get the peace of mind that your production environment is hardened by default.
Container scanning isn't just about finding bugs; it's about enforcing a quality standard. When you combine the power of Trivy with the strict enforcement of admission controllers, you create a "secure by default" platform that scales with your organization.
Stop chasing CVEs in production. Start blocking them at the gate.