Trivy Operator Concepts
While CLI-based Trivy scanning works well in CI/CD, it only catches vulnerabilities at build time. The Trivy Operator extends coverage to runtime by continuously scanning all container images running in your cluster.
- Automatic Discovery — Watches for new/updated Pods, Jobs, ReplicaSets, and scans their images automatically
- CRD-Based Reports — Stores results as Kubernetes custom resources, queryable with
kubectl - VulnerabilityReport — Per-container vulnerability findings with severity counts and CVE details
- ConfigAuditReport — Workload misconfiguration checks (running as root, missing resource limits, etc.)
- ExposedSecretReport — Secrets found in container image layers
- Prometheus Metrics — Exposes vulnerability counts as metrics for alerting and dashboards
Installation
Helm Install
# Add the Aqua Security Helm repository
helm repo add aquasecurity https://aquasecurity.github.io/helm-charts/
helm repo update
# Install the Trivy Operator into its own namespace
helm install trivy-operator aquasecurity/trivy-operator \
--namespace trivy-system \
--create-namespace \
--set trivy.ignoreUnfixed=true \
--set operator.scanJobTimeout=5m \
--set operator.scanJobsConcurrentLimit=3
Verify Operator
# Check operator pod is running
kubectl get pods -n trivy-system
# NAME READY STATUS RESTARTS AGE
# trivy-operator-6b8f9d5c4f-x7k2m 1/1 Running 0 2m
# Verify CRDs are installed
kubectl get crd | grep aquasecurity
# configauditreports.aquasecurity.github.io
# exposedsecretreports.aquasecurity.github.io
# vulnerabilityreports.aquasecurity.github.io
# Check operator logs for scanning activity
kubectl logs -n trivy-system deploy/trivy-operator --tail=20
VulnerabilityReport CRD
After installation, the operator automatically scans all running workloads. VulnerabilityReports appear within minutes for each container in each pod.
# List all vulnerability reports in a namespace
kubectl get vulnerabilityreports -n default
# NAME REPOSITORY TAG SCANNER AGE
# replicaset-nginx-deploy-7d4c-nginx library/nginx 1.25 Trivy 5m
# replicaset-api-deploy-8f3b-api myorg/api v2.1.0 Trivy 4m
# Get detailed report for a specific workload
kubectl get vulnerabilityreport \
replicaset-nginx-deploy-7d4c-nginx -n default -o json | \
jq '.report.summary'
# {
# "criticalCount": 2,
# "highCount": 15,
# "mediumCount": 43,
# "lowCount": 89,
# "noneCount": 12
# }
# List only reports with CRITICAL vulnerabilities
kubectl get vulnerabilityreports -n default \
-o jsonpath='{range .items[?(@.report.summary.criticalCount > 0)]}{.metadata.name}{"\t"}{.report.summary.criticalCount}{"\n"}{end}'
# Example VulnerabilityReport structure (abbreviated)
apiVersion: aquasecurity.github.io/v1alpha1
kind: VulnerabilityReport
metadata:
name: replicaset-nginx-deploy-7d4c-nginx
namespace: default
labels:
trivy-operator.resource.kind: ReplicaSet
trivy-operator.resource.name: nginx-deploy-7d4c
trivy-operator.container.name: nginx
spec:
scanner:
name: Trivy
version: 0.52.0
report:
artifact:
repository: library/nginx
tag: "1.25"
summary:
criticalCount: 2
highCount: 15
mediumCount: 43
lowCount: 89
vulnerabilities:
- vulnerabilityID: CVE-2024-12345
resource: libssl3
installedVersion: 3.0.11-1
fixedVersion: 3.0.13-1
severity: CRITICAL
title: "OpenSSL: Buffer overflow in X.509 parsing"
primaryLink: https://avd.aquasec.com/nvd/cve-2024-12345
ConfigAuditReport CRD
ConfigAuditReports check workload configurations against security best practices — similar to running trivy config but continuously and automatically for every workload in the cluster.
# List all config audit reports
kubectl get configauditreports -n default
# NAME SCANNER AGE
# replicaset-nginx-deploy-7d4c Trivy 5m
# replicaset-api-deploy-8f3b Trivy 4m
# Get audit details
kubectl get configauditreport \
replicaset-nginx-deploy-7d4c -n default -o json | \
jq '.report.summary'
# {
# "criticalCount": 1,
# "highCount": 3,
# "mediumCount": 2,
# "lowCount": 1
# }
# Show specific failing checks
kubectl get configauditreport \
replicaset-nginx-deploy-7d4c -n default -o json | \
jq '.report.checks[] | select(.severity == "CRITICAL") | {title, description, severity}'
# {
# "title": "Container running as root",
# "description": "Container 'nginx' is running as root user",
# "severity": "CRITICAL"
# }
Alerting & Integration
Prometheus Metrics
The Trivy Operator exposes metrics that Prometheus can scrape, enabling alerts when new critical vulnerabilities are detected.
# ServiceMonitor for Prometheus Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: trivy-operator
namespace: trivy-system
labels:
app: trivy-operator
spec:
selector:
matchLabels:
app.kubernetes.io/name: trivy-operator
endpoints:
- port: metrics
interval: 30s
path: /metrics
# PrometheusRule for alerting on critical vulnerabilities
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: trivy-vulnerability-alerts
namespace: trivy-system
spec:
groups:
- name: trivy.vulnerabilities
rules:
- alert: CriticalVulnerabilityDetected
expr: |
trivy_image_vulnerabilities{severity="Critical"} > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Critical vulnerability in {{ $labels.namespace }}/{{ $labels.resource_name }}"
description: "Image {{ $labels.image_repository }}:{{ $labels.image_tag }} has {{ $value }} critical vulnerabilities"
- alert: HighVulnerabilityCount
expr: |
trivy_image_vulnerabilities{severity="High"} > 20
for: 10m
labels:
severity: warning
annotations:
summary: "High vulnerability count in {{ $labels.namespace }}/{{ $labels.resource_name }}"
Grafana Dashboard
# Key Prometheus queries for Grafana panels:
# Total critical vulnerabilities across the cluster
sum(trivy_image_vulnerabilities{severity="Critical"})
# Vulnerabilities by namespace
sum by (namespace) (trivy_image_vulnerabilities{severity=~"Critical|High"})
# Top 10 most vulnerable images
topk(10, trivy_image_vulnerabilities{severity="Critical"})
# Config audit failures by severity
sum by (severity) (trivy_resource_configaudits{})
# Workloads with no vulnerability report (not yet scanned)
count(kube_pod_container_info) - count(trivy_image_vulnerabilities)
Exercises
nginx:1.21 (known vulnerabilities). Wait for the VulnerabilityReport to be created and inspect it with kubectl get vulnerabilityreport -o json. Count the critical and high severity findings.
Key Takeaways
- The Trivy Operator continuously scans all workload images in-cluster — no manual triggering required
- VulnerabilityReports store per-container CVE findings as queryable CRDs
- ConfigAuditReports check workload configurations against security best practices
- Prometheus metrics enable alerting on new critical vulnerabilities and tracking remediation over time
- Combine with Grafana dashboards for a real-time security posture overview
- Trivy Operator complements CI scanning (Part 1) — CI catches at build time, operator catches at runtime