Trivy Operator
Aqua Security's Kubernetes operator that runs Trivy inside a cluster and stores the results as custom resources. It watches workloads and starts a scan Job when a new image appears, then writes VulnerabilityReport, ConfigAuditReport, exposed-secret, RBAC, infra, SBOM and compliance reports that kubectl and Prometheus can read. Apache 2.0 and free. It fits a cluster that needs a continuous view of what is actually running, as a complement to scanning images in CI.
Trivy Operator runs the Trivy scanner continuously inside a Kubernetes cluster. It watches for new and changed workloads, scans their container images and their manifests, and stores each result as a Kubernetes custom resource next to the workload it describes. The result is a live security inventory of what is actually running, readable with kubectl and exportable as Prometheus metrics, instead of a CI report about what was built.
What it is
A Go controller, installed with Helm into its own namespace (trivy-system in the docs), that uses Trivy as its scan engine. Aqua Security maintains it under the Apache 2.0 licence. It is the successor to Starboard: the Starboard repository now states that it is superseded by trivy-operator, and its CLI half lives on as trivy kubernetes.
The current release is v0.35.0 (2026-10-05), shipped as Helm chart 0.37.0. Releases arrive roughly monthly, and most recent ones are a Trivy version bump plus fixes: v0.33.0 moved to Trivy 0.73.0, v0.34.0 to 0.74.0 and v0.35.0 to 0.75.0, with a fix that restores ConfigMap data for content-based config audits. Trivy itself is at v0.76.0 upstream, so the operator's bundled scanner usually trails the CLI by one minor.
Report types it produces, all in the aquasecurity.github.io API group:
- VulnerabilityReport — CVEs in the OS packages and language dependencies of each container image.
- ConfigAuditReport / ClusterConfigAuditReport — misconfigurations in workloads, Services, Roles, Ingresses, NetworkPolicies and other objects, checked against Trivy's built-in Rego checks.
- ExposedSecretReport — secrets baked into image layers.
- RbacAssessmentReport / ClusterRbacAssessmentReport — risky permissions in Roles and ClusterRoles.
- InfraAssessmentReport / ClusterInfraAssessmentReport — node and control-plane settings, collected by a node-collector Job.
- SbomReport / ClusterSbomReport — a software bill of materials per image.
- ClusterComplianceReport — CIS Kubernetes Benchmark, NSA hardening guidance and Pod Security Standards (baseline and restricted), regenerated on a cron.
How it works
The operator is a set of controllers. Two kinds of work happen. Vulnerability, secret and SBOM scans need the image, so the operator creates a short-lived Kubernetes Job that runs Trivy against it, then reads the Job's output and writes the report. Config audits need only the object's spec, so the operator evaluates the Rego checks in its own process and writes a ConfigAuditReport without a Job. Every report carries an owner reference to the workload, so Kubernetes garbage collection removes it when that revision goes away.
Trivy has two modes here. In Standalone (the default) each scan Job downloads the vulnerability database in an init container. In ClientServer a long-running Trivy server holds the database and the scan Jobs only inspect images and send what they find to the server for matching.
Step 1 of 6. The operator sees a new Pod template or ReplicaSet revision. By default it scans only the current revision of each workload.
ClientServer mode: scan Jobs inspect images, a Trivy server holds the vulnerability database.
The TTL step matters. A VulnerabilityReport is a snapshot: a CVE published the day after a scan does not appear until the image is scanned again. The report TTL is what turns a one-time scan into a daily one for workloads that never change.
When to use it
Reach for it when:
- The question is "what vulnerable images are running right now," across every namespace, including system pods and third-party charts that never pass through a CI pipeline.
- Findings should be queryable as Kubernetes objects, so other tools (Grafana, policy engines, scripts) can read them with the Kubernetes API.
- A cluster needs CIS, NSA or Pod Security Standards compliance reports without a separate product.
- An SBOM per running image is wanted as a by-product.
Skip it when:
- Images are already scanned in CI and nothing reaches the cluster except through that pipeline. A
trivy imagestep in the build gives the same CVE list earlier. - The cluster is very small on memory. Scan Jobs pull full images and Trivy needs real memory to unpack large ones.
- The goal is to block a vulnerable image at admission. The operator reports, it does not enforce. Pair it with an admission controller.
- The need is runtime threat detection. Falco and similar tools watch syscalls; Trivy Operator looks at static content.
At a glance
Core concepts
- Scan Job — a Kubernetes Job per image scan, created in the operator's namespace by default. Concurrency, timeout and retry delay are operator settings.
- Standalone vs ClientServer — where the vulnerability database lives: in every Job, or in one Trivy server.
- Report TTL — how long a vulnerability report lives before deletion forces a rescan.
- Owner references — each report belongs to its workload and is garbage-collected with it.
- Checks bundle — the Rego misconfiguration checks, pulled as the
trivy-checksOCI artifact. - Metrics —
trivy_image_vulnerabilities,trivy_resource_configaudits,trivy_image_exposedsecrets,trivy_role_rbacassessmentsand others on port 8080.
Key defaults (chart 0.37.0)
| Setting | Default | Effect |
|---|---|---|
trivy.mode |
Standalone |
Each scan Job downloads the database |
operator.builtInTrivyServer |
false |
true deploys a server and switches to ClientServer |
operator.scanJobsConcurrentLimit |
10 |
Maximum scan Jobs at once |
operator.scanJobTimeout |
5m |
Job is abandoned after this |
operator.scannerReportTTL |
24h |
Reports deleted and rescanned after this |
operator.vulnerabilityScannerScanOnlyCurrentRevisions |
true |
Old ReplicaSets are not scanned |
trivy.severity |
all levels | Filter to HIGH,CRITICAL to cut noise |
trivy.ignoreUnfixed |
false |
true hides CVEs with no fix available |
compliance.cron |
0 */6 * * * |
Compliance reports every 6 hours |
serviceMonitor.enabled |
false |
Requires the Prometheus Operator CRDs |
Trivy Operator vs Trivy in CI
| Aspect | Trivy Operator | trivy image in CI |
|---|---|---|
| Sees | Everything running, including third-party charts | Only images the pipeline builds |
| When | Continuously, plus a rescan on TTL | Once, at build time |
| Output | CRDs and Prometheus metrics | Pipeline log, SARIF, JSON |
| Can block | No | Yes, by failing the build |
| Cost | Scan Jobs and reports in the cluster | CI minutes |
The two are complementary: CI stops known-bad images before deploy, the operator catches CVEs published after deploy and images that skipped CI.
How to integrate
Install with Helm
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator \
--namespace trivy-system --create-namespace \
--version 0.37.0 \
-f trivy-values.yaml
The chart is also published as an OCI artifact at oci://ghcr.io/aquasecurity/helm-charts/trivy-operator.
Values for ClientServer mode and a quieter report set
# trivy-values.yaml
operator:
builtInTrivyServer: true # deploy trivy-server-0 and use ClientServer mode
scanJobsConcurrentLimit: 3 # small clusters: fewer image pulls at once
scannerReportTTL: "24h" # daily rescan picks up new CVEs
exposedSecretScannerEnabled: true
infraAssessmentScannerEnabled: false
clusterComplianceEnabled: false
trivy:
severity: HIGH,CRITICAL
ignoreUnfixed: true
nonSslRegistries:
internal: registry.example.svc:5000 # plain-HTTP private registry
serviceMonitor:
enabled: true # only if kube-prometheus-stack is installed
To use an existing Trivy server instead of the built-in one, leave builtInTrivyServer off and set trivy.mode: ClientServer with trivy.serverURL to the server's address (the chart's example is https://trivy.trivy:4975). A server token goes in trivy.serverToken, or in an externally managed Secret named trivy-operator-trivy-config with trivy.existingSecret: true.
Read the reports
kubectl get vulnerabilityreports -A -o wide # short name: vulns
kubectl get configauditreports -A -o wide # short name: configaudit
kubectl -n shop get vulns -l trivy-operator.resource.name=api -o yaml
The printer columns show repository, tag and counts of critical, high and medium findings, which is the quickest triage view.
In the GL stack
Trivy Operator v0.35.0 runs on the beta cluster, one of the three K3s clusters behind builddaily.io, paiddaily.io and the other products. It works in ClientServer mode with a Trivy 0.75.0 server, which matches the scanner version bundled with that operator release.
- What it scans. It scans the images of running workloads and their configuration, and writes VulnerabilityReport and ConfigAuditReport objects next to each workload.
- Why beta. Product images are built once, tagged by git SHA and pushed to the private registry, and changes go feature to beta to main. A workload therefore runs on beta before the same image reaches prod, so the beta reports describe an image before it ships.
- Neighbours. It sits in the security layer beside Kyverno, which enforces admission policy, and Falco, which watches runtime behaviour. Trivy Operator adds the static view: known CVEs and misconfigurations in what is deployed.
Gotchas
- Standalone mode hits rate limits. Every scan Job downloads the database. With many workloads this can trip anonymous rate limits on the database registry. ClientServer mode, or a
trivy.dbRepositorymirror, removes the repeated download. - CRDs survive
helm uninstall. Helm leaves the report CRDs in place. The docs list thekubectl delete crdcommands, and deleting the CRDs deletes every report. - Reports live in etcd. Large clusters with SBOM generation on create many large objects. Turn off scanners that are not used, or set
alternateReportStorage.enabledto write JSON to a volume instead. - Private and HTTP registries need settings. Scan Jobs need the pull secrets for private images (see the private-registries tutorial in the docs). A plain-HTTP registry needs an entry in
trivy.nonSslRegistries, a self-signed one intrivy.insecureRegistries, or the Job fails to pull. - Keep the server on the bundled version. With an external server in ClientServer mode, run the server on the Trivy version the operator release bundles (
trivy.image.tagin the chart, 0.75.0 for chart 0.37.0), so client and server upgrade together. - The docs site trails the releases. The install page on the docs site still shows an older chart pin. Take the current version from the GitHub releases and the chart's
Chart.yaml. - Metric cardinality.
metricsVulnIdEnabledadds one series per CVE ID. It is off by default for a reason.
Risks
- Supply chain of the scanner itself. On 2026-03-19 compromised credentials were used to publish a malicious Trivy v0.69.4 and to repoint tags in
trivy-actionandsetup-trivy; malicious v0.69.5 and v0.69.6 images followed on Docker Hub on 2026-03-22. Aqua's advisory (GHSA-69fq-xp46-6x23) lists the exposure windows. Pin Trivy and operator images by digest, not by tag. - Advisories in Trivy itself. A path traversal through a crafted database or other downloaded artifact (GHSA-mcj4-mphf-j9ff) is fixed in Trivy 0.71.1. The scanner parses untrusted content by design, so stay current.
- Privileges. The operator reads every workload, Role and Secret reference in the cluster, and the node collector mounts host paths for infra checks. Treat its service account as cluster-sensitive.
- Single-vendor project. Aqua Security sets the roadmap and the release cadence. The code is Apache 2.0, and the reports are plain CRDs, so lock-in is low.
- False sense of coverage. A clean report means no known CVE in the database for the detected packages. It says nothing about runtime behaviour or unknown flaws.
Alternatives
- Trivy in CI (
trivy image,trivy k8s) — pick it when every image passes through a pipeline and a build-time gate is enough. - Kubescape — a CNCF project that combines posture scanning, image scanning and an operator. Pick it for a broader posture product with frameworks such as NSA and MITRE.
- Grype and Syft (Anchore) — pick them for SBOM-first scanning in pipelines, where Syft generates the SBOM and Grype matches it.
- NeuVector — SUSE's open-source container security platform. Pick it when runtime protection, network segmentation and admission control should come from one product.
Related
- Kyverno and Falco — admission policy and runtime detection, the other two parts of the security layer.
- Distribution registry and Argo CD — where scanned images come from and how they reach the beta cluster.
- Prometheus, Alertmanager and Grafana — the metrics path for
trivy_*series. - K3s and Rancher — the clusters it runs on and how they are managed.
- Security layer overview: /resources/stack-security/.
- Official: Trivy Operator docs, aquasecurity/trivy-operator releases, Trivy client/server mode, Trivy supply-chain advisory.
