Back to Distributed Systems & Kubernetes Series

Trivy Track Part 2: Operator & Cluster Reports

June 6, 2026 Wasil Zafar 33 min read

The Trivy Operator brings continuous security scanning directly into your Kubernetes cluster. It automatically scans all workload images, generates VulnerabilityReport and ConfigAuditReport CRDs, and exposes Prometheus metrics — giving you a real-time security posture dashboard without manual intervention.

Table of Contents

  1. Trivy Operator Concepts
  2. Installation
  3. VulnerabilityReport CRD
  4. ConfigAuditReport CRD
  5. Alerting & Integration
  6. Exercises
  7. Key Takeaways

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
Operator Pattern: The Trivy Operator follows the Kubernetes operator pattern — it watches for resource changes (new Pods), reconciles desired state (all images scanned), and stores results as CRDs. No manual triggering required.

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"
# }
Common Findings: ConfigAuditReports typically flag: containers running as root, missing resource requests/limits, readOnlyRootFilesystem not set, privilege escalation allowed, and hostNetwork/hostPID enabled. These align with Pod Security Standards (restricted profile).

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)
Dashboard Best Practice: Create a Grafana dashboard with panels for: (1) cluster-wide vulnerability summary by severity, (2) vulnerabilities by namespace, (3) top vulnerable images, (4) config audit pass/fail rates, and (5) time-series of vulnerability counts to track remediation progress.

Exercises

Exercise 1: Install the Trivy Operator via Helm into a Kind or Minikube cluster. Deploy a workload with 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.
Exercise 2: Deploy a workload that runs as root with no resource limits. Inspect the ConfigAuditReport and identify all failing checks. Then fix the Deployment YAML (add securityContext, resource requests/limits) and verify the ConfigAuditReport improves after the operator re-scans.
Exercise 3: If you have Prometheus installed (e.g., via kube-prometheus-stack), create a ServiceMonitor for the Trivy Operator and verify metrics appear in Prometheus. Write a PrometheusRule that fires an alert when any namespace has more than 5 critical vulnerabilities. Trigger it by deploying an old, vulnerable image.

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