Trivy Operator
Scan running containers for vulnerabilities, misconfigurations, and exposed secrets with the Trivy Operator.
Time: ~15 minutes Difficulty: Intermediate
What You Will Learn
Section titled “What You Will Learn”- How Trivy Operator automatically scans container images in your cluster
- Reading VulnerabilityReport CRDs to find CVEs by severity
- Comparing scan results between vulnerable and hardened images
- ConfigAuditReport for Kubernetes misconfiguration detection
- How vulnerability scanners work with CVE databases
Prerequisites
Section titled “Prerequisites”Trivy Operator must be installed via Helm before running this demo:
helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/helm repo updatehelm install trivy-operator aquasecurity/trivy-operator \ --namespace trivy-system \ --create-namespace \ --set trivy.ignoreUnfixed=trueWait for Trivy Operator to be ready:
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=trivy-operator -n trivy-system --timeout=120sDeploy
Section titled “Deploy”Navigate to the demo directory:
cd demos/trivy-operatorCreate the namespace:
kubectl apply -f manifests/namespace.yamlDeploy the vulnerable applications (these use old images with known CVEs):
kubectl apply -f manifests/vulnerable-app.yamlDeploy the secure application for comparison:
kubectl apply -f manifests/secure-app.yamlCheck that all pods are running:
kubectl get pods -n trivy-demoVerify
Section titled “Verify”Wait 60-90 seconds for Trivy Operator to scan the running pods. The operator watches for new pods and automatically triggers image scans.
List Vulnerability Reports
Section titled “List Vulnerability Reports”kubectl get vulnerabilityreports -n trivy-demoYou should see reports for each container:
NAME REPOSITORY TAG SCANNER AGEreplicaset-old-nginx-xxx-nginx nginx 1.21 Trivy 2mreplicaset-old-redis-xxx-redis redis 6.0 Trivy 2mreplicaset-secure-nginx-xxx-nginx nginx 1.25... Trivy 2mCheck Summary for Old Nginx
Section titled “Check Summary for Old Nginx”kubectl get vulnerabilityreports -n trivy-demo -o wideThe output shows the severity breakdown. Old nginx should have CRITICAL and HIGH findings.
View Detailed CVEs
Section titled “View Detailed CVEs”To see the actual vulnerabilities, extract them from a report:
kubectl get vulnerabilityreports -n trivy-demo \ -l trivy-operator.resource.name=old-nginx \ -o jsonpath='{range .items[0].report.vulnerabilities[*]}{.severity}{"\t"}{.vulnerabilityID}{"\t"}{.title}{"\n"}{end}' | head -20Sample output:
CRITICAL CVE-2023-44487 HTTP/2 Rapid Reset AttackHIGH CVE-2023-4911 glibc buffer overflowHIGH CVE-2022-3715 bash improper input validationMEDIUM CVE-2022-48174 busybox denial of service...Compare with Secure Nginx
Section titled “Compare with Secure Nginx”The secure nginx (1.25.3-alpine) should have far fewer findings:
kubectl get vulnerabilityreports -n trivy-demo \ -l trivy-operator.resource.name=secure-nginx \ -o jsonpath='{.items[0].report.summary}'Expected output shows minimal or zero critical/high vulnerabilities:
{"criticalCount":0,"highCount":0,"mediumCount":2,"lowCount":5}Check Configuration Audit Reports
Section titled “Check Configuration Audit Reports”Trivy Operator also scans for Kubernetes misconfigurations:
kubectl get configauditreports -n trivy-demoView details for a specific deployment:
kubectl get configauditreports -n trivy-demo -o wideThese reports flag missing security settings like:
- No securityContext defined
- Running as root
- Missing readiness/liveness probes
- No resource limits
The secure-nginx deployment should have fewer warnings because it includes securityContext.
What is Happening
Section titled “What is Happening”manifests/ namespace.yaml # trivy-demo namespace vulnerable-app.yaml # old-nginx (nginx:1.21) and old-redis (redis:6.0) secure-app.yaml # secure-nginx (nginx:1.25.3-alpine with securityContext)Trivy Operator workflow:
- Watches for new pods in the cluster using a Kubernetes controller
- Reads the container image references from pod specs
- Scans each image for vulnerabilities using the Trivy scanner
- Creates a VulnerabilityReport CRD for each container
- Runs Kubernetes best practice checks and creates ConfigAuditReport CRDs
- Updates reports when images are updated or new pods are created
VulnerabilityReport contains:
- List of CVEs with severity (CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN)
- Package name and version
- Fixed version (if available)
- Links to CVE database entries (NVD, GitHub Advisory)
ConfigAuditReport contains:
- Checks against CIS Kubernetes Benchmark
- Pod Security Standards violations
- Best practices (resource limits, health probes, security contexts)
Why the old images have vulnerabilities:
- nginx:1.21 was released in 2021 and contains unpatched OS packages (Debian)
- redis:6.0 has known CVEs in the base Alpine image
- Newer images (1.25.3-alpine) receive security patches and updates
Experiment
Section titled “Experiment”-
Deploy a pod with an older Alpine image to see new scan results appear:
Terminal window kubectl run test-alpine --image=alpine:3.14 -n trivy-demo --command -- sleep infinityWait 60 seconds, then check:
Terminal window kubectl get vulnerabilityreports -n trivy-demo -l trivy-operator.resource.name=test-alpine -
Extract the summary counts for all reports using jq:
Terminal window kubectl get vulnerabilityreports -n trivy-demo -o json | jq '.items[].report.summary' -
Filter for only CRITICAL vulnerabilities across all reports:
Terminal window kubectl get vulnerabilityreports -n trivy-demo -o json \| jq '.items[].report.vulnerabilities[] | select(.severity == "CRITICAL") | {id: .vulnerabilityID, title: .title, pkg: .resource}' -
Check if Trivy found any embedded secrets in container images:
Terminal window kubectl get secrets-reports -n trivy-demo(This requires enabling the
--secret-scannerflag in the Trivy Operator Helm values) -
Review the ConfigAuditReport for the old-nginx deployment:
Terminal window kubectl get configauditreports -n trivy-demo \-l trivy-operator.resource.name=old-nginx \-o yamlLook at the
checkssection to see best practice violations. -
Trigger a manual rescan by deleting a report (it will be recreated):
Terminal window kubectl delete vulnerabilityreports -n trivy-demo -l trivy-operator.resource.name=old-nginxWait 30 seconds and the report reappears.
Cleanup
Section titled “Cleanup”Delete the demo namespace:
kubectl delete namespace trivy-demoTo remove Trivy Operator entirely:
helm uninstall trivy-operator -n trivy-systemkubectl delete namespace trivy-systemFurther Reading
Section titled “Further Reading”See docs/deep-dive.md for a detailed explanation of how CVE databases work, Trivy’s scanning architecture, VulnerabilityReport CRD structure, integrating Trivy into CI/CD pipelines, and comparing Trivy with other scanners like Grype, Snyk, and Clair.
Next Step
Section titled “Next Step”Move on to Falco Runtime Security to learn how to detect threats in running containers using behavioral monitoring.