Everything for Trivy in one place — pick a section below. 30 reviewed items across 2 content types, plus a hands-on tutorial.
Quick Answer
Trivy is an open-source, comprehensive security scanner developed by Aqua Security that detects vulnerabilities, misconfigurations, secrets, and license issues. It supports scanning container images, filesystems, Git repositories, Kubernetes clusters, and Infrastructure as Code files in a single unified tool.
Detailed Answer
Think of Trivy as a Swiss Army knife for security scanning. Just as a Swiss Army knife combines multiple tools into a single handle, Trivy combines vulnerability scanning, misconfiguration detection, secret scanning, and license checking into one CLI binary. Before Trivy existed, teams needed separate tools for each type of scan, making security pipelines complex and hard to maintain.
Trivy is an open-source security scanner originally created by Aqua Security and now part of the Cloud Native Computing Foundation (CNCF) ecosystem. It performs static analysis to find known vulnerabilities (CVEs) in operating system packages and application dependencies, misconfigurations in Infrastructure as Code files like Terraform and Kubernetes manifests, hardcoded secrets such as API keys and passwords, and software license violations. The tool is written in Go and distributed as a single binary, which makes installation straightforward across Linux, macOS, and Windows. In a typical DevOps pipeline for a service like payments-api, Trivy can scan the Docker image during the CI build stage and block deployments that contain critical vulnerabilities.
Under the hood, Trivy works by downloading vulnerability databases from GitHub releases and OCI registries, then matching the packages found in your scan targets against known CVEs. It supports multiple scan targets, which Trivy calls 'scanners' and 'targets.' The primary targets are container images (both local and remote registry images), filesystem directories, Git repositories, Kubernetes clusters (via the kubernetes scanner), and virtual machine images. For container images, Trivy unpacks the image layers, identifies the OS distribution and installed packages, detects application dependencies (like npm packages in node_modules or Python packages in requirements.txt), and cross-references everything against its vulnerability database.
In production environments, teams integrate Trivy at multiple stages of the software delivery lifecycle. A developer working on user-auth-service might run Trivy locally before committing to catch obvious issues early. The CI pipeline then runs Trivy as a gate, failing the build if CRITICAL or HIGH vulnerabilities are found in the container image. In Kubernetes environments, Trivy Operator (a separate component) runs as a controller inside the cluster, continuously scanning deployed workloads and generating VulnerabilityReport custom resources. This gives the security team a live inventory of vulnerabilities across all services like order-processing-service, inventory-sync, and checkout-service running in the cluster.
A common misconception for beginners is that Trivy only scans container images. While image scanning is its most popular feature, Trivy's filesystem and repository scanning capabilities are equally powerful. Running trivy fs on your project directory will detect vulnerable dependencies in package-lock.json, go.sum, pom.xml, and dozens of other dependency manifest files without ever building a container image. This makes Trivy useful even for teams that deploy to serverless platforms or traditional virtual machines, not just those running containers.
Code Example
# Scan a container image for vulnerabilities trivy image payments-api:latest # Scan a filesystem directory for vulnerabilities and misconfigurations trivy fs --scanners vuln,misconfig ./src # Scan a remote image from a container registry trivy image registry.company.com/user-auth-service:v2.1.0 # Scan for secrets in a Git repository trivy repo --scanners secret https://github.com/company/checkout-service # Scan a Kubernetes cluster for vulnerabilities trivy k8s --report summary cluster # Scan Infrastructure as Code files for misconfigurations trivy config ./terraform/ # Show Trivy version and database information trivy version
Interview Tip
A junior engineer typically says 'Trivy is a container image scanner' and stops there. That answer only covers one of Trivy's many capabilities. Interviewers want to hear that Trivy is a comprehensive security scanner supporting multiple targets: container images, filesystems, Git repos, Kubernetes clusters, and IaC files. Mention that it detects vulnerabilities, misconfigurations, secrets, and license issues. If you can describe how Trivy fits into a CI/CD pipeline as a quality gate, blocking deployments with critical CVEs in services like payments-api or order-processing-service, you demonstrate practical DevSecOps experience that separates you from candidates who only read the documentation.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Trivy Scanner │ │ │ │ ┌───────────┐ ┌────────────┐ ┌────────┐ │ │ │ Container │ │ Filesystem │ │ Git │ │ │ │ Images │ │ / Code │ │ Repos │ │ │ └─────┬─────┘ └─────┬──────┘ └───┬────┘ │ │ │ │ │ │ │ └──────────┬───┴─────────────┘ │ │ ↓ │ │ ┌──────────────────┐ │ │ │ Scan Engines │ │ │ ├──────────────────┤ │ │ │ ● Vulnerabilities│ │ │ │ ● Misconfigs │ │ │ │ ● Secrets │ │ │ │ ● Licenses │ │ │ └────────┬─────────┘ │ │ ↓ │ │ ┌──────────────────┐ │ │ │ Scan Results │ │ │ │ (JSON/Table) │ │ │ └──────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
You scan container images by running trivy image followed by the image name and tag. Trivy automatically downloads the vulnerability database, pulls or accesses the image layers, identifies OS and application packages, and reports any known CVEs with their severity levels.
Detailed Answer
Scanning a container image with Trivy is like putting a package through an airport X-ray machine. The machine looks inside every layer, identifies all the contents, and flags anything suspicious. Similarly, Trivy unpacks each layer of a Docker image, inventories all installed packages and dependencies, and checks each one against a database of known vulnerabilities.
The basic command is trivy image followed by the image reference. Trivy can scan images from multiple sources: local images built with Docker (trivy image payments-api:latest), remote images from registries like Docker Hub or ECR (trivy image registry.company.com/order-processing-service:v1.3.0), and even OCI image archives saved as tar files (trivy image --input image.tar). When scanning a local image, Trivy communicates with the Docker daemon to access image layers. For remote images, Trivy pulls the layers directly from the registry without requiring Docker to be installed, which is useful in CI environments that use tools like Kaniko or Buildah instead of Docker.
Internally, Trivy performs two passes when scanning a container image. The first pass identifies the operating system distribution (Debian, Alpine, Amazon Linux, etc.) and all OS-level packages installed via the package manager. The second pass detects application-level dependencies by looking for lock files and manifest files within the image layers. For example, it finds package-lock.json for Node.js, requirements.txt or Pipfile.lock for Python, go.sum for Go, and pom.xml or build.gradle for Java. Each discovered package is cross-referenced against Trivy's vulnerability database, which aggregates data from sources like the National Vulnerability Database (NVD), distribution-specific advisories (Debian Security Tracker, Alpine SecDB), and language-specific advisory databases (GitHub Advisory Database, RustSec).
In production CI/CD pipelines, teams typically run Trivy image scanning as a build step after the Docker image is built but before it is pushed to the registry. For a service like checkout-service, the pipeline builds the image, runs trivy image with --exit-code 1 and --severity CRITICAL,HIGH flags, and only pushes the image to the registry if Trivy exits successfully. This prevents vulnerable images from ever reaching production. Teams often use the --ignore-unfixed flag to suppress vulnerabilities that have no available patch, reducing noise in the results. Registry-side scanning is also common: services like Amazon ECR, Google Artifact Registry, and Harbor can integrate Trivy to scan images on push.
A key gotcha for beginners is understanding image layers and caching. If your Dockerfile installs packages in an early layer and that layer is cached, rebuilding the image may not pull the latest security patches even though you ran apt-get update. Trivy will flag these outdated packages. The fix is to ensure your base image is regularly updated and that package installation layers are not aggressively cached. Another common issue is scanning multi-stage build images: Trivy only scans the final image, not intermediate build stages, so vulnerable build tools in earlier stages will not appear in the report as long as they are not copied to the final image.
Code Example
# Scan a locally built Docker image trivy image payments-api:latest # Scan a remote image from Amazon ECR trivy image 123456789.dkr.ecr.us-east-1.amazonaws.com/order-processing-service:v2.0 # Scan only for CRITICAL and HIGH severity vulnerabilities trivy image --severity CRITICAL,HIGH user-auth-service:latest # Fail the CI build if critical vulnerabilities are found trivy image --exit-code 1 --severity CRITICAL checkout-service:latest # Ignore vulnerabilities that have no fix available yet trivy image --ignore-unfixed inventory-sync:latest # Scan a saved image archive (tar file) trivy image --input ./checkout-service-image.tar # Scan without needing Docker installed (pulls layers directly) trivy image --image-src remote registry.company.com/payments-api:v3.1.0
Interview Tip
A junior engineer typically says 'you just run trivy image and it finds vulnerabilities.' Interviewers expect you to explain the scanning mechanics: how Trivy unpacks image layers, differentiates between OS packages and application dependencies, and matches them against vulnerability databases from NVD and distribution advisories. Mention the --exit-code flag for CI/CD gating and --ignore-unfixed for reducing noise. If asked how you would integrate Trivy into a pipeline for a service like payments-api, describe the build-scan-push workflow where the image is scanned after building but before pushing to the registry. Demonstrating awareness of multi-stage builds and layer caching issues shows you understand container security beyond just running a command.
◈ Architecture Diagram
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Build Image │───→│ Trivy Scan │───→│ Push Image │
│ docker build│ │ trivy image │ │ docker push │
└──────────────┘ └──────┬───────┘ └──────────────┘
│
┌──────┴───────┐
│ Image Layers │
├──────────────┤
│ Layer 1: OS │→ apt/apk packages
│ Layer 2: App │→ npm/pip/go deps
│ Layer 3: Conf│→ config files
└──────┬───────┘
↓
┌──────────────┐
│ Vuln DB │
│ NVD + Distro│
│ Advisories │
└──────┬───────┘
↓
┌──────────────┐
│ Results │
│ ✓ Pass / ✗ │
└──────────────┘💬 Comments
Quick Answer
Trivy uses four severity levels based on CVSS scores: CRITICAL (9.0-10.0) for vulnerabilities allowing full system compromise, HIGH (7.0-8.9) for serious exploits, MEDIUM (4.0-6.9) for moderate-impact issues, and LOW (0.1-3.9) for minimal-risk findings. Teams use these levels to prioritize remediation and set CI/CD gate thresholds.
Detailed Answer
Severity levels in Trivy are like a hospital triage system. A CRITICAL patient needs immediate surgery, a HIGH priority patient goes to the emergency room, MEDIUM means urgent care, and LOW is a scheduled appointment. Just as hospitals cannot treat every patient simultaneously, DevOps teams use severity levels to decide which vulnerabilities to fix first and which can wait for the next maintenance window.
Trivy assigns severity levels to each detected vulnerability based on the Common Vulnerability Scoring System (CVSS). The mapping follows industry standards: CRITICAL covers CVSS scores from 9.0 to 10.0, HIGH ranges from 7.0 to 8.9, MEDIUM spans 4.0 to 6.9, and LOW covers 0.1 to 3.9. Some vulnerabilities also have an UNKNOWN severity when the CVE entry lacks a CVSS score. Trivy sources its severity data from multiple advisories, and when different sources disagree on the severity of a vulnerability, Trivy prioritizes the distribution-specific advisory (like Red Hat or Debian) over the generic NVD score, because distribution maintainers often adjust severity based on how the package is compiled and configured in their distribution.
Understanding what each level means in practical terms helps teams make informed decisions. A CRITICAL vulnerability in the base image of your payments-api might allow remote code execution without authentication, meaning an attacker could take full control of the container from the network. A HIGH vulnerability in user-auth-service might enable privilege escalation but require the attacker to already have some level of access. MEDIUM vulnerabilities in order-processing-service might allow information disclosure under specific conditions, while LOW vulnerabilities in inventory-sync might require physical access or highly unusual configurations to exploit. Context matters enormously: a MEDIUM vulnerability in a public-facing service is often more urgent than a HIGH vulnerability in an internal batch processing tool with no network exposure.
In production, teams establish severity-based policies for their CI/CD pipelines. A common approach is to block deployments of checkout-service when CRITICAL or HIGH vulnerabilities are detected using trivy image --exit-code 1 --severity CRITICAL,HIGH, while allowing MEDIUM and LOW findings to be tracked as technical debt. Some mature organizations use Trivy's .trivyignore file to acknowledge accepted risks: if a CRITICAL vulnerability has no fix available and the affected component is not reachable in your application, you add its CVE ID to .trivyignore with an expiration date, preventing it from failing the pipeline while ensuring it gets reviewed periodically.
A nuance beginners often miss is that CVSS scores alone do not tell the full story. The Exploit Prediction Scoring System (EPSS) and whether a public exploit exists are equally important factors. A HIGH vulnerability with a known exploit being actively used in the wild is more dangerous than a CRITICAL vulnerability that is purely theoretical. Trivy can show whether a vulnerability has a known fix, which helps prioritize: a CRITICAL with a simple package upgrade is an easy win, while a HIGH with no fix may require architectural changes or compensating controls like network policies.
Code Example
# Show only CRITICAL severity vulnerabilities
trivy image --severity CRITICAL payments-api:latest
# Show CRITICAL and HIGH vulnerabilities
trivy image --severity CRITICAL,HIGH user-auth-service:latest
# Fail CI pipeline only on CRITICAL findings
trivy image --exit-code 1 --severity CRITICAL order-processing-service:latest
# Show all severity levels with detailed information
trivy image --severity CRITICAL,HIGH,MEDIUM,LOW checkout-service:latest
# Create a .trivyignore file to accept specific CVE risks
# echo 'CVE-2023-44487' >> .trivyignore
# echo 'CVE-2024-21626' >> .trivyignore
# Scan with the ignore file applied
trivy image --ignorefile .trivyignore inventory-sync:latest
# Show vulnerabilities with CVSS score details
trivy image --format json payments-api:latest | jq '.Results[].Vulnerabilities[] | {VulnerabilityID, Severity, CVSS}'Interview Tip
A junior engineer typically recites the CVSS score ranges without connecting them to real-world impact. Interviewers want to hear how you use severity levels to make decisions in a pipeline. Explain that you set CI/CD gates to block CRITICAL and HIGH vulnerabilities in production-bound images like payments-api while tracking MEDIUM and LOW as technical debt. Mention the .trivyignore file for acknowledged risks and explain why distribution-specific severity scores can differ from NVD scores. If you can articulate that a HIGH vulnerability with a public exploit in a network-exposed service is more urgent than a CRITICAL in an air-gapped internal tool, you demonstrate the risk-based thinking that security-conscious teams value.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Vulnerability Severity Levels │ │ │ │ ┌──────────┐ CVSS 9.0-10.0 │ │ │ CRITICAL │ Remote code execution │ │ │ ✗✗✗ │ Full system compromise │ │ └──────────┘ → Block deployment │ │ │ │ ┌──────────┐ CVSS 7.0-8.9 │ │ │ HIGH │ Privilege escalation │ │ │ ✗✗ │ Data breach potential │ │ └──────────┘ → Block deployment │ │ │ │ ┌──────────┐ CVSS 4.0-6.9 │ │ │ MEDIUM │ Limited impact exploit │ │ │ ✗ │ Conditional access needed │ │ └──────────┘ → Track as tech debt │ │ │ │ ┌──────────┐ CVSS 0.1-3.9 │ │ │ LOW │ Minimal risk │ │ │ ● │ Unusual conditions needed │ │ └──────────┘ → Monitor in backlog │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy scans filesystems using trivy fs and Git repositories using trivy repo. Both commands analyze dependency manifest files (package-lock.json, go.sum, requirements.txt) for known vulnerabilities without requiring a container image to be built, enabling early detection in the development lifecycle.
Detailed Answer
Scanning a filesystem with Trivy is like having a building inspector check the blueprints before construction begins. Instead of waiting until the building is finished (the container image is built) to find structural problems, the inspector catches issues while changes are still cheap and easy to make. Trivy's filesystem and repository scanners bring security feedback as far left in the development process as possible.
The trivy fs command scans a local directory for vulnerabilities, misconfigurations, and secrets. When you run trivy fs on the root of your payments-api project, Trivy walks the directory tree looking for dependency manifest files and lock files. It recognizes dozens of package manager formats: package-lock.json and yarn.lock for Node.js, requirements.txt and Pipfile.lock for Python, go.sum for Go, Gemfile.lock for Ruby, pom.xml and build.gradle for Java, Cargo.lock for Rust, and many others. For each dependency it finds, Trivy checks the version against its vulnerability database and reports any known CVEs. The trivy repo command does the same thing but takes a Git repository URL as input, cloning the repository into a temporary directory before scanning.
The key difference between filesystem scanning and image scanning is what gets analyzed. Image scanning examines both OS packages and application dependencies within the built container layers. Filesystem scanning focuses on the application source code and its declared dependencies before any container image is built. This means filesystem scanning is faster, does not require Docker, and can run on a developer's laptop as part of a pre-commit workflow. For user-auth-service, a developer can run trivy fs . in the project directory to catch a vulnerable version of jsonwebtoken before even pushing the code to the repository.
In production workflows, teams use trivy fs at multiple points. Developers run it locally during development as a quick check. The CI pipeline runs it as one of the first steps, before the more time-consuming Docker build and image scan. For a monorepo containing order-processing-service, inventory-sync, and checkout-service, teams can run trivy fs on each subdirectory independently or scan the entire monorepo at once. The trivy repo command is particularly useful for scheduled scanning of third-party dependencies or for security teams that need to audit repositories they do not have checked out locally. A nightly cron job can run trivy repo against all repositories in the organization and aggregate results into a security dashboard.
One gotcha beginners encounter is that trivy fs only detects vulnerabilities in declared dependencies, not in vendored or copied code. If someone copies a vulnerable function from a library directly into their source code instead of importing the package, Trivy will not detect it. Additionally, the accuracy of filesystem scanning depends on having accurate lock files committed to the repository. If the lock file is outdated or missing, Trivy may miss dependencies or report incorrect versions. Teams should enforce that lock files are always committed and kept in sync with the manifest files.
Code Example
# Scan the current project directory for vulnerabilities trivy fs . # Scan a specific project path trivy fs /home/developer/projects/payments-api # Scan for vulnerabilities and secrets in the filesystem trivy fs --scanners vuln,secret ./order-processing-service # Scan a remote Git repository trivy repo https://github.com/company/user-auth-service # Scan a private Git repository with authentication export GITHUB_TOKEN=ghp_xxxxxxxxxxxx trivy repo https://github.com/company/checkout-service # Scan only specific severity levels in filesystem trivy fs --severity CRITICAL,HIGH ./inventory-sync # Fail the build if vulnerabilities are found trivy fs --exit-code 1 --severity CRITICAL . # Scan and output results in JSON for further processing trivy fs --format json --output results.json ./payments-api
Interview Tip
A junior engineer typically confuses filesystem scanning with image scanning or does not know Trivy can scan without Docker. Interviewers want to hear about the shift-left benefit: filesystem scanning catches vulnerabilities before images are built, making it faster and cheaper to remediate. Explain the supported lock file formats (package-lock.json, go.sum, Pipfile.lock, etc.) and that accuracy depends on lock files being committed and up to date. Mention that trivy repo can scan remote repositories without cloning them locally, which is valuable for security audits across many services like payments-api and order-processing-service. Describing how you would integrate trivy fs as a pre-commit hook or early CI step shows you understand the development workflow holistically.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Filesystem & Repository Scanning │ │ │ │ Developer Laptop CI Pipeline │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ trivy fs . │ │ trivy fs . │ │ │ │ (pre-commit) │ │ (build step) │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ └─────────┬─────────┘ │ │ ↓ │ │ ┌─────────────────────────────────┐ │ │ │ Dependency Files Detected │ │ │ ├─────────────────────────────────┤ │ │ │ ● package-lock.json (Node.js) │ │ │ │ ● go.sum (Go) │ │ │ │ ● requirements.txt (Python) │ │ │ │ ● pom.xml (Java) │ │ │ └──────────────┬──────────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────┐ │ │ │ Vuln DB Match → Results │ │ │ └─────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy can be installed via package managers (apt, yum, brew), as a standalone binary download, or as a Docker image. Configuration is done through CLI flags, environment variables, or a trivy.yaml configuration file that centralizes settings like severity thresholds, cache directories, and database mirror locations.
Detailed Answer
Installing Trivy is like setting up a new power tool in your workshop. You can buy it from a hardware store (package manager), order it online and assemble it yourself (binary download), or rent one that comes ready to use (Docker image). Once you have the tool, you adjust its settings (configuration) to match the type of work you do most often.
Trivy offers multiple installation methods to suit different environments. On macOS, the simplest approach is brew install trivy using Homebrew. On Debian and Ubuntu systems, you add the Aqua Security APT repository and run apt-get install trivy. On Red Hat and CentOS, you add the YUM repository and install with yum install trivy. For environments where package managers are not available or not desirable, you can download the pre-built binary from the GitHub releases page and place it in your PATH. In CI/CD pipelines for services like payments-api or user-auth-service, many teams use the official Trivy Docker image (aquasec/trivy) to avoid installing anything on the build agent. There is also a Trivy GitHub Action for GitHub Actions workflows and a Trivy plugin for Jenkins.
Configuration in Trivy follows a precedence hierarchy: CLI flags override environment variables, which override the configuration file. The configuration file is named trivy.yaml and can be placed in the project root or specified with the --config flag. This file allows you to define default settings that apply every time Trivy runs in that project. Common configuration options include the severity levels to report, the output format, the cache directory location, vulnerability database mirror URLs for air-gapped environments, and scanner types to enable. Environment variables follow the pattern TRIVY_ followed by the setting name in uppercase, so --severity becomes TRIVY_SEVERITY and --format becomes TRIVY_FORMAT.
In production environments, teams configure Trivy differently depending on the context. For local development on a service like order-processing-service, a trivy.yaml file in the repository root sets sensible defaults so developers just run trivy fs . without remembering flags. For CI pipelines, environment variables or CLI flags override the defaults to enforce stricter policies. For air-gapped environments where the build agents cannot reach the internet, Trivy is configured to use an internal mirror for the vulnerability database. The database can be downloaded on a machine with internet access using trivy image --download-db-only and then transferred to the internal mirror. Cache management is also important: Trivy caches the vulnerability database locally (default location is ~/.cache/trivy) and only downloads updates when the cache expires.
A common mistake during installation is forgetting to initialize the vulnerability database before the first scan. Trivy downloads the database automatically on the first run, but this can take 30 to 60 seconds depending on network speed. In CI pipelines for checkout-service or inventory-sync, this delay adds up if the database is downloaded fresh on every build. The solution is to either cache the database directory between builds or run trivy image --download-db-only as a separate pipeline step that executes less frequently.
Code Example
# Install Trivy on macOS using Homebrew brew install trivy # Install Trivy on Debian/Ubuntu sudo apt-get install wget apt-transport-https gnupg lsb-release wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/trivy.list sudo apt-get update && sudo apt-get install trivy # Install Trivy on RHEL/CentOS sudo rpm -ivh https://github.com/aquasecurity/trivy/releases/download/v0.50.0/trivy_0.50.0_Linux-64bit.rpm # Run Trivy using the official Docker image docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image payments-api:latest # Pre-download the vulnerability database for offline use trivy image --download-db-only # Verify the installation trivy version # Create a trivy.yaml configuration file # severity: [CRITICAL, HIGH] # format: table # exit-code: 1 # vuln-type: [os, library]
Interview Tip
A junior engineer typically describes only one installation method and skips configuration entirely. Interviewers want to hear that you understand the multiple installation options and when to use each: Homebrew for local development, Docker image for CI pipelines, binary download for restricted environments. Discuss the trivy.yaml configuration file and the precedence hierarchy where CLI flags override environment variables, which override the config file. Mention the database download delay on first run and how caching the database directory speeds up CI builds for services like payments-api and checkout-service. If asked about air-gapped environments, explain the offline database workflow where you download the DB on an internet-connected machine and mirror it internally.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Trivy Installation Options │ │ │ │ ┌───────────┐ ┌───────────┐ ┌─────────┐ │ │ │ Package │ │ Binary │ │ Docker │ │ │ │ Manager │ │ Download │ │ Image │ │ │ │ brew/apt │ │ GitHub │ │ aquasec │ │ │ │ /yum │ │ releases │ │ /trivy │ │ │ └─────┬─────┘ └─────┬─────┘ └────┬────┘ │ │ └──────────┬────┴─────────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ Configuration Precedence │ │ │ ├─────────────────────────────────────┤ │ │ │ 1. CLI flags (highest) │ │ │ │ --severity CRITICAL │ │ │ │ 2. Environment vars │ │ │ │ TRIVY_SEVERITY=CRITICAL │ │ │ │ 3. trivy.yaml (lowest) │ │ │ │ severity: [CRITICAL] │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy uses two main databases: a vulnerability database aggregating data from NVD, distribution advisories (Debian, Alpine, Red Hat), and language-specific sources (GitHub Advisory, RustSec), plus a Java index database. These databases are updated every 6 hours and downloaded automatically as OCI artifacts from ghcr.io.
Detailed Answer
Trivy's vulnerability databases are like the reference libraries that a medical diagnostic system uses to identify diseases. Without up-to-date reference data, the system cannot detect newly discovered conditions. Similarly, Trivy's scanning accuracy depends entirely on the freshness and completeness of its vulnerability databases. Understanding where this data comes from and how it stays current is fundamental to trusting scan results.
Trivy maintains two databases that work together. The primary vulnerability database (trivy-db) contains all known CVE entries aggregated from multiple upstream sources. These sources include the National Vulnerability Database (NVD), which is the U.S. government's comprehensive CVE repository, distribution-specific advisory databases like Debian Security Tracker, Alpine SecDB, Red Hat OVAL, Ubuntu CVE Tracker, and Amazon Linux Security Advisories, and language-specific advisory databases like GitHub Advisory Database, RustSec Advisory Database, Go Vulnerability Database, and PHP Security Advisories. The second database (trivy-java-db) specifically indexes Java archives (JAR files) to map them to their Maven coordinates, enabling accurate vulnerability matching for Java applications like an order-processing-service built with Spring Boot.
The update mechanism is designed for reliability and speed. Trivy's databases are packaged as OCI artifacts and hosted on GitHub Container Registry (ghcr.io). When you run a scan, Trivy checks whether the local cached database is older than the update interval (default is 24 hours since the last successful update). If it is, Trivy pulls the latest database from the registry. The database itself is updated by the Trivy maintainers approximately every 6 hours, meaning newly published CVEs typically appear in Trivy's database within 6 to 12 hours of publication. The database download is incremental when possible, reducing bandwidth usage for teams scanning services like payments-api, user-auth-service, and checkout-service multiple times a day.
In production environments, database management becomes a critical operational concern. For CI/CD pipelines building images for inventory-sync or other services, teams cache the database directory (~/.cache/trivy/db) between pipeline runs to avoid downloading it on every build. In air-gapped environments where build agents cannot access ghcr.io, teams set up an internal OCI registry mirror. An internet-connected machine downloads the database using trivy image --download-db-only, then pushes the OCI artifact to the internal registry. Trivy is then configured with --db-repository to point to the internal mirror. Some organizations run a cron job that updates the mirror every 6 hours to stay current. The --skip-db-update flag is available to prevent Trivy from attempting any database download, which is necessary in fully offline scenarios.
A subtlety beginners often overlook is the difference between the database update frequency and the upstream advisory publication speed. Even though Trivy updates its database every 6 hours, the upstream sources (NVD, distribution advisories) may take days or weeks to publish a CVE after a vulnerability is disclosed. Trivy can only report what its sources have published. For zero-day vulnerabilities, there is an inherent delay. Additionally, the --skip-db-update flag is dangerous if used without understanding: if the cached database is months old, Trivy will happily scan your checkout-service image and report it as clean, missing hundreds of vulnerabilities that were published after the cache was last refreshed.
Code Example
# Download the vulnerability database without scanning trivy image --download-db-only # Check the current database version and metadata trivy version # Force a database update before scanning trivy image --db-repository ghcr.io/aquasecurity/trivy-db payments-api:latest # Skip database update (use cached version only) trivy image --skip-db-update user-auth-service:latest # Point Trivy to an internal database mirror for air-gapped environments trivy image --db-repository registry.internal.company.com/trivy/trivy-db order-processing-service:latest # Clear the local database cache and force fresh download rm -rf ~/.cache/trivy/db && trivy image --download-db-only # Download the Java-specific index database trivy image --download-java-db-only # Set database cache directory via environment variable export TRIVY_CACHE_DIR=/opt/trivy-cache trivy image checkout-service:latest
Interview Tip
A junior engineer typically says 'Trivy uses a vulnerability database' without knowing where the data comes from or how it stays current. Interviewers want to hear the specific sources: NVD, distribution advisories (Debian, Alpine, Red Hat), and language-specific databases (GitHub Advisory, RustSec). Explain the 6-hour update cycle, the OCI artifact distribution mechanism via ghcr.io, and the local caching strategy. If asked about air-gapped environments, describe the mirror workflow where an internet-connected machine downloads the database and pushes it to an internal OCI registry. Mention the risk of using --skip-db-update with a stale cache, as it demonstrates you understand operational security pitfalls beyond just running commands.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Trivy Vulnerability Database Flow │ │ │ │ Upstream Sources Trivy DB │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ NVD │────→│ │ │ │ │ Debian SecDB │────→│ trivy-db │ │ │ │ Alpine SecDB │────→│ (OCI image) │ │ │ │ Red Hat OVAL │────→│ │ │ │ │ GitHub Adv. │────→│ Updated │ │ │ │ RustSec │────→│ every 6hrs │ │ │ └──────────────┘ └──────┬───────┘ │ │ │ │ │ ┌─────────┴──────────┐ │ │ ↓ ↓ │ │ ┌──────────────┐ ┌──────────┐ │ │ │ ghcr.io │ │ Internal │ │ │ │ (public) │ │ Mirror │ │ │ └──────┬───────┘ └────┬─────┘ │ │ ↓ ↓ │ │ ┌──────────────────────────┐ │ │ │ Local Cache │ │ │ │ ~/.cache/trivy/db │ │ │ └──────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy scans IaC files using the trivy config command, which checks Terraform, Kubernetes manifests, Dockerfiles, CloudFormation templates, and Helm charts for security misconfigurations. It uses built-in policies written in Rego (OPA) to detect issues like overly permissive IAM policies, containers running as root, and missing encryption settings.
Detailed Answer
Scanning Infrastructure as Code with Trivy is like having a building code inspector review your architectural drawings before construction starts. Instead of discovering that a wall lacks fire-resistant material after the building is finished (deployed to production), the inspector catches it during the design phase when corrections cost almost nothing. Trivy's IaC scanning catches security misconfigurations in your infrastructure definitions before they become running resources.
The trivy config command scans directories containing IaC files for security misconfigurations. Trivy supports a wide range of IaC formats: Terraform HCL and plan files, Kubernetes YAML manifests, Dockerfiles, AWS CloudFormation templates (JSON and YAML), Helm charts, and Docker Compose files. When you run trivy config on a directory, Trivy automatically detects the file types and applies the relevant security policies. For example, scanning the Terraform directory for your payments-api infrastructure might flag an S3 bucket without encryption enabled, a security group with port 22 open to the world, or an RDS instance without backup retention configured.
The misconfiguration checks are powered by built-in policies written in Rego, the policy language used by Open Policy Agent (OPA). Trivy ships with hundreds of pre-built checks organized by cloud provider and service. For AWS, checks cover IAM policies, security groups, S3 bucket configurations, RDS settings, and more. For Kubernetes, checks cover pod security contexts, resource limits, network policies, and RBAC configurations. Each check has a severity level (CRITICAL, HIGH, MEDIUM, LOW), a description of the issue, a recommended fix, and links to relevant compliance frameworks like CIS Benchmarks, NIST, and PCI-DSS. Teams can also write custom Rego policies for organization-specific requirements, like ensuring all Kubernetes deployments for checkout-service include specific labels or annotations.
In production, teams integrate trivy config into their CI pipelines alongside terraform plan and kubectl diff. For a typical workflow managing infrastructure for order-processing-service, the pipeline runs terraform plan to generate a plan file, then trivy config scans the Terraform directory to catch misconfigurations before terraform apply executes. This prevents insecure infrastructure from ever being provisioned. Some teams go further by scanning Helm chart values files before deploying to Kubernetes, ensuring that security contexts, resource limits, and network policies are correctly configured for services like user-auth-service and inventory-sync. The --exit-code flag works the same as with image scanning, allowing teams to fail the pipeline when misconfigurations exceed their risk tolerance.
A beginner mistake is confusing IaC scanning with vulnerability scanning. Trivy's config scanner looks for misconfigurations in how infrastructure is defined, not for CVEs in software packages. A Terraform file might have a perfectly valid syntax but define an IAM role with wildcard permissions, which is a misconfiguration that trivy config would catch. Conversely, trivy config will not tell you if the Terraform provider plugin itself has a known vulnerability. For comprehensive security, teams run both trivy config on IaC files and trivy image on the container images those IaC files deploy.
Code Example
# Scan a directory of Terraform files for misconfigurations trivy config ./terraform/ # Scan Kubernetes manifests for security issues trivy config ./k8s-manifests/ # Scan a single Dockerfile trivy config ./Dockerfile # Scan Helm chart templates trivy config ./helm/payments-api/ # Show only CRITICAL and HIGH severity misconfigurations trivy config --severity CRITICAL,HIGH ./terraform/ # Fail the pipeline if misconfigurations are found trivy config --exit-code 1 --severity CRITICAL ./infrastructure/ # Scan a Terraform plan file for post-plan analysis terraform plan -out=tfplan && terraform show -json tfplan > tfplan.json trivy config ./tfplan.json # Use custom Rego policies alongside built-in checks trivy config --policy ./custom-policies/ --namespaces user ./terraform/
Interview Tip
A junior engineer typically lumps IaC scanning together with vulnerability scanning, saying 'Trivy scans everything.' Interviewers want you to clearly distinguish between vulnerability scanning (finding CVEs in packages) and misconfiguration scanning (finding insecure infrastructure definitions). Explain the supported IaC formats: Terraform, Kubernetes YAML, Dockerfiles, CloudFormation, and Helm charts. Mention that checks are powered by Rego policies from OPA, and that Trivy includes hundreds of built-in checks mapped to compliance frameworks like CIS Benchmarks. If you can describe a workflow where trivy config runs in the CI pipeline before terraform apply to prevent insecure infrastructure for services like payments-api from being provisioned, you show practical DevSecOps integration skills.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ IaC Scanning with Trivy │ │ │ │ ┌───────────┐ ┌───────────┐ ┌─────────┐ │ │ │ Terraform │ │ K8s YAML │ │Dockerfile│ │ │ │ *.tf │ │ manifests │ │ │ │ │ └─────┬─────┘ └─────┬─────┘ └────┬────┘ │ │ └──────────┬───┴─────────────┘ │ │ ↓ │ │ ┌──────────────────┐ │ │ │ trivy config │ │ │ │ (Rego policies) │ │ │ └────────┬─────────┘ │ │ ↓ │ │ ┌─────────────────────────────────────┐ │ │ │ Misconfiguration Results │ │ │ ├─────────────────────────────────────┤ │ │ │ ✗ S3 bucket without encryption │ │ │ │ ✗ Container running as root │ │ │ │ ✗ Security group open to 0.0.0.0 │ │ │ │ ✓ RDS backup retention configured │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy supports multiple output formats controlled by the --format flag: table (human-readable default), JSON (machine-parsable), SARIF (for GitHub/GitLab code scanning integration), template (custom formats using Go templates), and CycloneDX/SPDX (for software bill of materials). Results can be saved to a file using --output.
Detailed Answer
Trivy's output formats are like choosing between reading a medical report as a patient summary (table), a structured data file for the hospital's database (JSON), or a standardized format that any hospital worldwide can import (SARIF). Each format serves a different audience and use case. Picking the right format determines whether your scan results are actionable by humans, machines, or both.
The default output format is table, which displays a human-readable columnar view in the terminal. Each vulnerability is shown with its CVE ID, package name, installed version, fixed version, and severity. This format is ideal for developers running Trivy locally on a project like payments-api because the results are immediately readable. However, table output is difficult to parse programmatically and does not integrate well with automated tooling. For CI/CD pipelines and security dashboards, other formats are more appropriate.
The JSON format (--format json) produces a structured output that contains all scan metadata, including the target name, scanner type, operating system details, and a complete list of vulnerabilities with their CVSS scores, descriptions, references, and fix availability. This format is essential for integrating Trivy results into security information and event management (SIEM) systems, custom dashboards, or downstream processing scripts. A typical workflow for order-processing-service might pipe JSON output through jq to extract only CRITICAL vulnerabilities, count them, and post the summary to a Slack channel. The SARIF format (Static Analysis Results Interchange Format) is specifically designed for integration with code scanning platforms like GitHub Advanced Security, GitLab SAST, and Azure DevOps. When Trivy generates SARIF output, the results appear as annotations directly on pull requests, showing exactly which file and line introduced a vulnerability or misconfiguration.
Beyond these core formats, Trivy supports SBOM (Software Bill of Materials) formats like CycloneDX and SPDX, which produce a complete inventory of all software components in a container image or filesystem. These formats are increasingly required by government regulations and enterprise procurement processes. Trivy also supports Go template-based custom formats, allowing teams to generate reports in any structure they need. For example, a team managing checkout-service and inventory-sync might create a custom HTML template that produces a branded security report for stakeholders. The --output flag saves results to a file instead of printing to stdout, and it can be combined with any format flag.
In production, teams often generate multiple formats from a single scan. A CI pipeline for user-auth-service might produce table output for the build log, JSON output for the security dashboard, and SARIF output for GitHub code scanning annotations. Since re-running the scan three times would be wasteful, teams typically run Trivy once with JSON output, then use post-processing tools to convert the JSON to other formats as needed. The trivy convert command can transform a previously saved JSON report into SARIF, CycloneDX, or other formats without re-scanning. This approach is both faster and ensures consistency across all report formats.
Code Example
# Default table format (human-readable terminal output) trivy image payments-api:latest # JSON format for machine parsing and automation trivy image --format json --output results.json user-auth-service:latest # SARIF format for GitHub Advanced Security integration trivy image --format sarif --output trivy-results.sarif checkout-service:latest # CycloneDX SBOM format for software bill of materials trivy image --format cyclonedx --output sbom.json order-processing-service:latest # SPDX format for compliance and procurement requirements trivy image --format spdx-json --output sbom-spdx.json inventory-sync:latest # Custom format using Go templates trivy image --format template --template "@contrib/html.tpl" --output report.html payments-api:latest # Convert existing JSON results to SARIF without re-scanning trivy convert --format sarif --output results.sarif results.json # Extract only CRITICAL vulnerabilities from JSON output trivy image --format json payments-api:latest | jq '[.Results[].Vulnerabilities[] | select(.Severity=="CRITICAL")]'
Interview Tip
A junior engineer typically mentions only the table format or says 'you can output as JSON.' Interviewers want to hear about the full range of formats and when to use each one. Explain that table is for developers reading terminal output, JSON is for automation and dashboards, SARIF integrates with GitHub and GitLab code scanning to show annotations on pull requests, and CycloneDX/SPDX are for SBOM compliance requirements. Mention the trivy convert command for transforming a saved JSON report into other formats without re-scanning, which saves CI time for services like payments-api and order-processing-service. If you can describe a pipeline that generates multiple format outputs from a single scan and uploads SARIF results to GitHub code scanning, you demonstrate mature CI/CD integration skills.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐
│ Trivy Output Format Options │
│ │
│ trivy image payments-api:latest │
│ │ │
│ ├──→ --format table │
│ │ ┌────────────────────────┐ │
│ │ │ CVE-ID │ PKG │ SEVERITY│ │
│ │ │ human-readable output │ │
│ │ └────────────────────────┘ │
│ │ │
│ ├──→ --format json │
│ │ ┌────────────────────────┐ │
│ │ │ {"Results": [...]} │ │
│ │ │ → dashboards, SIEM │ │
│ │ └────────────────────────┘ │
│ │ │
│ ├──→ --format sarif │
│ │ ┌────────────────────────┐ │
│ │ │ GitHub/GitLab code │ │
│ │ │ scanning annotations │ │
│ │ └────────────────────────┘ │
│ │ │
│ └──→ --format cyclonedx │
│ ┌────────────────────────┐ │
│ │ SBOM for compliance │ │
│ │ and procurement │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────┘💬 Comments
Quick Answer
Trivy integrates into CI/CD pipelines by running as a scanning step after the Docker image build phase, using exit codes to fail the pipeline when vulnerabilities above a specified severity threshold are detected. Each platform has native integration patterns including the official aquasecurity/trivy-action for GitHub Actions, the Trivy Jenkins plugin, and inline script commands for GitLab CI.
Detailed Answer
Think of Trivy in a CI/CD pipeline like a quality inspector on a factory assembly line. Every product (container image) must pass through the inspector's station before it can be packaged and shipped. If the inspector finds a defect above a certain severity, the line stops and the product is sent back for rework. Without this inspection gate, defective products reach customers and cause costly recalls. Trivy serves as that automated inspector, examining every image before it enters a container registry.
Trivy integrates into CI/CD pipelines as a scanning step that runs after the Docker image build phase but before the image push phase. The fundamental mechanism is straightforward: Trivy accepts an image reference, decomposes the image layers to identify OS packages and application dependencies, matches them against vulnerability databases including NVD, GitHub Advisory Database, and distribution-specific trackers, and produces a report with findings categorized by severity. The critical configuration is the --exit-code flag, which determines whether the pipeline passes or fails. Setting --exit-code 1 with --severity CRITICAL,HIGH means the pipeline fails only when critical or high vulnerabilities are found, allowing medium and low findings to pass through as warnings.
In GitHub Actions, the recommended approach uses the official aquasecurity/trivy-action maintained by Aqua Security. This action handles Trivy installation, database caching between runs, and output formatting. For the payments-api service, you would add a scan step after the docker build step that targets the locally built image. The action supports multiple output formats including table for human-readable console output, JSON for programmatic processing, and SARIF for integration with GitHub's Security tab under Code Scanning. The SARIF integration is particularly valuable because it surfaces vulnerabilities as inline annotations on pull requests, enabling developers to see exactly which dependency introduced the vulnerability without leaving the PR review interface. GitHub Actions caching can store the Trivy vulnerability database between workflow runs to reduce scan times from minutes to seconds.
For Jenkins, integration follows two patterns depending on team preference. The first uses the Aqua Security Trivy plugin, which adds a dedicated build step type to Freestyle and Pipeline jobs. The second, more common approach uses a shell step in a Jenkinsfile that invokes Trivy directly from the command line. In a typical order-processing-service pipeline, the Jenkinsfile would include a stage called Security Scan that runs trivy image with the appropriate severity flags after the Build stage and before the Push stage. Jenkins can archive the JSON report as a build artifact, and teams often use the HTML Publisher plugin to render scan results as a browsable report attached to each build. For GitLab CI, Trivy integrates as a job in the .gitlab-ci.yml file, typically placed in a security stage that runs after the build stage. GitLab has native support for ingesting Trivy's GitLab-formatted JSON output through the artifacts:reports:container_scanning directive, which populates the Security Dashboard accessible from the project's sidebar.
A common gotcha when integrating Trivy into CI/CD is failing to cache the vulnerability database. Without caching, every pipeline run downloads a fresh database, adding 30-60 seconds of latency and creating reliability issues if the download server is unavailable. In GitHub Actions, use the actions/cache action to persist the Trivy database directory between runs. In Jenkins, use the stash/unstash mechanism or a shared volume on the build agent. Another trap is setting the severity threshold too aggressively on day one. If you immediately fail on all HIGH findings in a legacy codebase with hundreds of existing vulnerabilities, the pipeline becomes permanently blocked. Instead, start with CRITICAL only, fix those, then progressively tighten to HIGH. Use the .trivyignore file to temporarily suppress known false positives or vulnerabilities with no available fix so that the pipeline remains actionable rather than noisy.
Code Example
# GitHub Actions workflow for scanning the payments-api image
# name: Security Scan
# on: [push, pull_request]
# jobs:
# trivy-scan:
# runs-on: ubuntu-latest
# steps:
# Step 1: Check out the repository source code
# - uses: actions/checkout@v4
# Step 2: Build the payments-api Docker image
# - run: docker build -t payments-api:${{ github.sha }} .
# Step 3: Cache the Trivy vulnerability database between runs
# - uses: actions/cache@v4
# with:
# path: ~/.cache/trivy
# key: trivy-db-${{ runner.os }}
# Step 4: Run Trivy scan with severity gate
# - uses: aquasecurity/trivy-action@master
# with:
# image-ref: payments-api:${{ github.sha }}
# severity: CRITICAL,HIGH
# exit-code: 1
# format: table
# Step 5: Generate SARIF report for GitHub Security tab
# - uses: aquasecurity/trivy-action@master
# with:
# image-ref: payments-api:${{ github.sha }}
# format: sarif
# output: trivy-results.sarif
# Step 6: Upload SARIF to GitHub Code Scanning
# - uses: github/codeql-action/upload-sarif@v3
# with:
# sarif_file: trivy-results.sarif
# Jenkins pipeline equivalent for order-processing-service
# stage('Security Scan') {
# steps {
# sh 'trivy image --exit-code 1 --severity CRITICAL,HIGH order-processing-service:${BUILD_TAG}'
# }
# }
# GitLab CI equivalent for checkout-service
# container_scanning:
# stage: security
# script:
# - trivy image --format json --output gl-container-scanning-report.json checkout-service:${CI_COMMIT_SHA}
# artifacts:
# reports:
# container_scanning: gl-container-scanning-report.jsonInterview Tip
A junior engineer typically mentions that Trivy can be added to a pipeline but cannot explain the specific integration patterns for each CI platform or the database caching strategy. Demonstrate depth by naming the aquasecurity/trivy-action for GitHub Actions, the SARIF output format that feeds into GitHub's Security tab, and the artifacts:reports:container_scanning directive in GitLab CI that populates the Security Dashboard. Explain that --exit-code 1 is the mechanism that transforms a scan from informational to a quality gate. Discuss the progressive severity strategy: start with CRITICAL only in legacy codebases, then tighten to include HIGH after remediating existing findings. Mentioning database caching as a performance optimization shows you have operated Trivy at scale rather than just reading the documentation.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ CI/CD Pipeline Flow │ │ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ Git Push │ → │ Build Image │ │ │ │ (PR/main)│ │ payments-api │ │ │ └──────────┘ └──────┬───────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────┐ │ │ │ Trivy Scanner │ │ │ │ ● CVE Database │ │ │ │ ● OS Packages │ │ │ │ ● App Deps │ │ │ └────────┬─────────┘ │ │ │ │ │ ┌─────────┼─────────┐ │ │ ↓ ↓ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ ✓ PASS │ │ ✗ FAIL │ │ │ │ Push to │ │ Block Push │ │ │ │ Registry │ │ Alert Team │ │ │ └──────┬───────┘ └──────────────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ SARIF Report │ │ │ │ → GitHub │ │ │ │ Security │ │ │ └──────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
The .trivyignore file allows teams to suppress specific CVEs from Trivy scan results by listing vulnerability IDs one per line, optionally with expiration dates and justification comments. Policy-based exceptions extend this further using OPA Rego policies to define conditional suppression rules based on severity, package name, or affected service.
Detailed Answer
Think of the .trivyignore file as an airport security's known traveler list. Certain passengers have been thoroughly vetted and pre-approved, so they bypass the standard screening without triggering an alarm. Without this mechanism, every known frequent flyer would set off the checkpoint every single time, causing delays and desensitizing security staff to real threats. Similarly, .trivyignore prevents known, accepted vulnerabilities from blocking the pipeline, keeping the scan results focused on actionable findings.
The .trivyignore file is a plaintext file placed in the root of your repository that tells Trivy to skip specific vulnerabilities during scanning. Each line contains a CVE identifier such as CVE-2023-44487 or a vulnerability ID from another advisory source like GHSA identifiers. When Trivy encounters a vulnerability whose ID matches an entry in .trivyignore, it silently excludes that finding from the output and does not count it toward the exit code calculation. This means a pipeline configured with --exit-code 1 and --severity CRITICAL will pass even if a CRITICAL vulnerability exists, provided that vulnerability is listed in .trivyignore. Comments can be added using the hash symbol, and best practice demands that every ignored CVE include a comment explaining the business justification, the risk acceptance owner, and an expiration date after which the suppression should be reviewed.
Trivy supports an extended .trivyignore format using YAML-like metadata blocks that provide more granular control. Each entry can include an exp field specifying an expiration date in YYYY-MM-DD format, after which Trivy will stop ignoring the vulnerability and it will reappear in scan results. This is critical for compliance because it prevents indefinite suppression of known risks. For the user-auth-service, you might suppress CVE-2024-21626 with an expiration of 30 days, giving the team a window to plan the upgrade while keeping the pipeline unblocked. When the expiration passes, the vulnerability resurfaces automatically, forcing resolution. Trivy also supports a statement field where teams document who approved the exception, under what conditions, and what compensating controls are in place.
Policy-based exceptions take this concept further by using OPA Rego policies to define conditional suppression rules that apply across the entire organization rather than per-repository. Instead of maintaining individual .trivyignore files in every service repository, a central security team can publish a Rego policy that suppresses certain low-risk vulnerabilities across all scans when specific conditions are met. For example, a policy might suppress vulnerabilities in development-only dependencies that are not present in the final production image, or suppress CVEs that only affect a specific CPU architecture that the organization does not use. These policies are stored in a central repository and referenced during CI scans using the --policy flag or through Trivy's integration with OPA Gatekeeper in Kubernetes environments. The inventory-sync service team, for instance, might have a policy that allows medium-severity findings in test dependencies but enforces strict zero-tolerance for any severity in runtime dependencies.
A critical gotcha with .trivyignore is the temptation to add CVEs without expiration dates, effectively creating a permanent suppression list that grows unchecked over time. Within months, the ignore file can contain dozens of entries that nobody remembers approving, and some may have patches available that the team never revisited. Enforce a mandatory expiration date policy using a CI check that validates the .trivyignore file format and rejects entries without exp fields. Another common mistake is ignoring vulnerabilities at the CVE level when they should be ignored at the package level, or vice versa. A single CVE might affect multiple packages, and ignoring the CVE suppresses all of them, which may not be the intent. Use Trivy's package-specific ignore syntax when you want finer control. Finally, always store .trivyignore in version control alongside the Dockerfile so that exception history is auditable and changes require code review approval from the security team.
Code Example
# Create a .trivyignore file in the user-auth-service repository root # Suppress CVE with no available fix in the base image # Approved by: [email protected] on 2024-03-15 # Reason: No fix available in Alpine 3.19, affects libcrypto only in FIPS mode # CVE-2024-0727 # Suppress CVE with compensating control in place # Approved by: [email protected] on 2024-04-01 # Reason: WAF rules block the attack vector for this HTTP/2 vulnerability # CVE-2023-44487 # Extended format with expiration dates (trivy >= 0.49) # Create .trivyignore.yaml for richer metadata # vulnerabilities: # - id: CVE-2024-21626 # exp: 2024-07-15 # statement: "Upgrade to runc 1.1.12 planned for Q3 sprint" # - id: CVE-2024-0727 # exp: 2024-06-30 # statement: "No fix available; FIPS mode not used in payments-api" # Run Trivy scan with the .trivyignore file active trivy image --ignorefile .trivyignore --severity CRITICAL,HIGH --exit-code 1 user-auth-service:latest # Validate .trivyignore entries have not expired using a CI check # grep -E '^# exp:' .trivyignore | while read line; do check_date "$line"; done # Run Trivy with a custom OPA Rego policy for organization-wide exceptions trivy image --policy ./policies/exception-policy.rego --severity CRITICAL,HIGH order-processing-service:latest # List all currently ignored CVEs for audit purposes grep -v '^#' .trivyignore | grep -v '^$' | sort # Verify that no .trivyignore entry has been suppressed for more than 90 days # git log --follow -p .trivyignore | grep -A2 'CVE-' | head -20
Interview Tip
A junior engineer typically knows that you can ignore CVEs but cannot explain the governance framework around it. Demonstrate maturity by explaining the full lifecycle: every .trivyignore entry must include a justification comment, an expiration date, and the name of the approver. Mention the extended YAML format with exp and statement fields that Trivy supports for structured metadata. Explain the difference between CVE-level and package-level suppression and why the distinction matters. Discuss how a central security team can publish OPA Rego policies for organization-wide exceptions rather than relying on per-repository ignore files. The strongest answers connect .trivyignore management to compliance requirements like SOC 2 or FedRAMP, where auditors require documented evidence of risk acceptance decisions with review dates.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ .trivyignore Exception Flow │ │ │ │ ┌───────────────────┐ │ │ │ Trivy Scanner │ │ │ │ Finds 12 CVEs │ │ │ └────────┬──────────┘ │ │ │ │ │ ↓ │ │ ┌───────────────────┐ │ │ │ .trivyignore │ │ │ │ ● CVE-2024-0727 │ ← exp: 2024-06-30 │ │ │ ● CVE-2023-44487 │ ← exp: 2024-07-15 │ │ └────────┬──────────┘ │ │ │ │ │ ↓ │ │ ┌───────────────────────────────────┐ │ │ │ Filtered Results: 10 CVEs │ │ │ │ │ │ │ │ ┌─────────┐ ┌─────────────────┐ │ │ │ │ │CRITICAL │→ │ ✗ Pipeline FAIL │ │ │ │ │ │ 2 found │ │ (exit-code 1) │ │ │ │ │ └─────────┘ └─────────────────┘ │ │ │ │ ┌─────────┐ ┌─────────────────┐ │ │ │ │ │HIGH │→ │ ✗ Pipeline FAIL │ │ │ │ │ │ 3 found │ │ (exit-code 1) │ │ │ │ │ └─────────┘ └─────────────────┘ │ │ │ │ ┌─────────┐ ┌─────────────────┐ │ │ │ │ │MEDIUM │→ │ ✓ Warning Only │ │ │ │ │ │ 5 found │ │ (no block) │ │ │ │ │ └─────────┘ └─────────────────┘ │ │ │ └───────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy scans Kubernetes clusters using the trivy k8s command, which connects to the cluster via kubeconfig to analyze running workloads for container image vulnerabilities, Kubernetes manifest misconfigurations, RBAC issues, and secrets exposure. The Trivy Operator extends this to continuous in-cluster scanning by deploying as a Kubernetes operator that automatically scans new workloads.
Detailed Answer
Think of Trivy scanning a Kubernetes cluster like a building inspector who walks through every floor of an office building, checking each room for fire code violations, structural issues, and unauthorized modifications. The inspector does not just look at the blueprints (manifests) but examines the actual rooms as built (running containers). The trivy k8s command is a one-time inspection visit, while the Trivy Operator is a permanent on-site inspector who checks every new tenant as they move in and continuously monitors for emerging issues.
Trivy provides native Kubernetes cluster scanning through the trivy k8s command, which connects to the cluster using the current kubeconfig context and systematically analyzes every accessible resource. The scan covers multiple dimensions: container image vulnerabilities in running pods, Kubernetes manifest misconfigurations such as containers running as root, missing resource limits, or exposed hostPath volumes, RBAC over-permissions where service accounts have cluster-admin level access, and network policy gaps. When you run trivy k8s --report summary against a production cluster, Trivy enumerates all namespaces, pulls the image references from pod specs, scans those images against CVE databases, and simultaneously evaluates the Kubernetes resource configurations against a built-in set of security checks derived from CIS Kubernetes Benchmarks and NSA Kubernetes Hardening Guidance.
Under the hood, Trivy uses the Kubernetes client-go library to authenticate and query the API server. It fetches resource manifests for Deployments, StatefulSets, DaemonSets, Jobs, CronJobs, Pods, Services, Ingresses, NetworkPolicies, Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings. For image scanning, it resolves image digests through the container registry, downloads and caches image layers, and performs the same vulnerability analysis as trivy image. For misconfiguration detection, Trivy evaluates each resource against Rego policies that check for security anti-patterns. For example, in the payments-api deployment, Trivy would flag a container spec that lacks securityContext.runAsNonRoot, missing readiness and liveness probes, or a service account mounted with automountServiceAccountToken not set to false. The scan produces a comprehensive report that maps findings to specific resources with namespace, kind, name, and container details.
The Trivy Operator takes this scanning model and makes it continuous by deploying as a Kubernetes operator using CustomResourceDefinitions. Once installed via Helm chart, the operator watches for new or updated workloads and automatically triggers scans. Results are stored as VulnerabilityReport and ConfigAuditReport custom resources within the same namespace as the scanned workload. This means you can query scan results using kubectl, integrate them with Kubernetes-native monitoring and alerting, and build custom controllers that react to findings. For the checkout-service namespace, running kubectl get vulnerabilityreports -n checkout lists all vulnerability findings for workloads in that namespace. The operator also supports CIS Benchmark scanning of the Kubernetes infrastructure itself, checking kubelet configurations, API server flags, and etcd encryption settings on the node level.
A critical gotcha when scanning clusters is permission scope. The trivy k8s command requires read access to all resources across all namespaces for a complete scan, which means the kubeconfig user or service account must have cluster-wide read permissions. In multi-tenant clusters where teams manage their own namespaces, a cluster-wide scan may expose resources that the scanning user should not see. Use the --namespace flag to scope scans to specific namespaces, or deploy the Trivy Operator with namespace-scoped RBAC if full cluster access is not appropriate. Another common issue is scan performance in large clusters. A cluster running 500 pods with 200 unique images can take 30 minutes or more for a full scan because each unique image must be downloaded and analyzed. The Trivy Operator mitigates this by caching results and only rescanning when image references change. Finally, be aware that trivy k8s scans the declared image tags, and if a tag like latest has been updated in the registry but the running pod still uses the old digest, the scan results reflect the current registry state, not the actually running binary.
Code Example
# Scan the entire Kubernetes cluster for vulnerabilities and misconfigurations trivy k8s --report summary cluster # Scan a specific namespace where the payments-api runs trivy k8s --namespace payments --report all # Generate a detailed JSON report for the order-processing namespace trivy k8s --namespace order-processing --format json --output k8s-scan-report.json # Scan only for misconfigurations (skip vulnerability scanning) trivy k8s --scanners misconfig --namespace checkout-service --report summary # Scan specific workload types only trivy k8s --namespace inventory-sync --report summary deployments,statefulsets # Install the Trivy Operator via Helm for continuous scanning helm repo add aqua https://aquasecurity.github.io/helm-charts/ # Update Helm repo index to get the latest operator version helm repo update # Deploy the Trivy Operator into the trivy-system namespace helm install trivy-operator aqua/trivy-operator --namespace trivy-system --create-namespace # View vulnerability reports for the payments namespace kubectl get vulnerabilityreports -n payments -o wide # View misconfiguration audit reports for order-processing kubectl get configauditreports -n order-processing # Get detailed vulnerability report for a specific deployment kubectl get vulnerabilityreport -n payments payments-api-payments-api -o yaml # Scan cluster against CIS Kubernetes Benchmark trivy k8s --compliance k8s-cis --report summary cluster
Interview Tip
A junior engineer typically mentions that Trivy can scan images but does not realize it can scan entire Kubernetes clusters including manifest misconfigurations and RBAC configurations. Stand out by explaining both the ad-hoc trivy k8s command for one-time scans and the Trivy Operator for continuous monitoring. Describe the CustomResourceDefinitions that the operator creates: VulnerabilityReport and ConfigAuditReport, which are queryable via kubectl. Mention that the operator watches for workload changes and automatically rescans, eliminating the need for scheduled cron jobs. Discuss the permission model, explaining that cluster-wide scans require cluster-reader RBAC permissions and that namespace-scoped scanning is available for multi-tenant environments. Reference the CIS Kubernetes Benchmark compliance checks to show you understand how Trivy fits into a regulatory compliance framework.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Kubernetes Cluster Scanning │ │ │ │ ┌────────────────────────────────────┐ │ │ │ Trivy K8s / Operator │ │ │ └───────────────┬────────────────────┘ │ │ │ │ │ ┌──────────┼──────────┐ │ │ ↓ ↓ ↓ │ │ ┌─────────┐ ┌────────┐ ┌──────────┐ │ │ │ Image │ │Manifest│ │ RBAC │ │ │ │ Vulns │ │Misconf │ │ Audit │ │ │ └────┬────┘ └───┬────┘ └────┬─────┘ │ │ │ │ │ │ │ ↓ ↓ ↓ │ │ ┌─────────────────────────────────┐ │ │ │ CustomResourceDefinitions │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ VulnerabilityReport │ │ │ │ │ │ ● payments-api: 3 HIGH │ │ │ │ │ │ ● checkout-service: 1 CRIT │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ ConfigAuditReport │ │ │ │ │ │ ● runAsRoot: FAIL │ │ │ │ │ │ ● resourceLimits: FAIL │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌─────────────────────────────────┐ │ │ │ kubectl get vulnerabilityreports│ │ │ │ → Alerting → Dashboards │ │ │ └─────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy generates SBOMs in CycloneDX and SPDX formats using the trivy image --format cyclonedx or trivy sbom command, producing a complete inventory of all packages, libraries, and dependencies in a container image. These SBOMs can then be rescanned by Trivy to detect new vulnerabilities as CVE databases are updated, enabling continuous monitoring without re-pulling images.
Detailed Answer
Think of an SBOM as the ingredient list on a food product. Just as a consumer with a peanut allergy needs to know every ingredient in a packaged meal, an organization needs to know every software component in a deployed container to assess risk when a new vulnerability is announced. When a critical CVE drops affecting a specific version of OpenSSL, having SBOMs for every service lets you instantly identify which of your 200 microservices are affected, rather than re-scanning every image from scratch.
A Software Bill of Materials is a machine-readable inventory of all components that make up a software artifact. Trivy generates SBOMs by analyzing container images, filesystem directories, and code repositories to enumerate every OS package, application library, and transitive dependency along with their exact versions, licenses, and supplier information. Trivy supports the two industry-standard SBOM formats: CycloneDX, which is an OWASP project focusing on security and software supply chain use cases, and SPDX, which is a Linux Foundation project emphasizing license compliance. For the payments-api image, running trivy image --format cyclonedx produces a JSON document listing every component from the base Alpine packages like musl and busybox to application dependencies like express and jsonwebtoken, including their PURL (Package URL) identifiers that enable cross-referencing with vulnerability databases.
The SBOM generation process works by leveraging the same scanning engine that powers vulnerability detection. Trivy decomposes the image into layers, identifies package managers and their metadata sources, and extracts the complete dependency tree. For OS packages, it reads the distribution package database such as dpkg status for Debian or apk installed for Alpine. For application dependencies, it parses lockfiles including package-lock.json for Node.js, go.sum for Go, Gemfile.lock for Ruby, and requirements.txt or poetry.lock for Python. The resulting SBOM includes component type classification, version strings, hash digests for integrity verification, and license identifiers using SPDX license expression syntax. Trivy can also generate SBOMs for filesystem directories using trivy fs --format spdx-json, which is useful for scanning source code repositories before containerization.
The real power of SBOMs emerges when they are stored and rescanned over time. Instead of pulling and analyzing every container image when a new critical vulnerability is announced, teams can rescan previously generated SBOMs using trivy sbom, which takes a CycloneDX or SPDX file as input and checks all listed components against the latest vulnerability database. For an organization running 50 microservices including order-processing-service, user-auth-service, and inventory-sync, storing SBOMs in a central repository like Dependency-Track allows the security team to immediately query which services contain the affected component when a zero-day drops. This SBOM-first approach reduces incident response time from hours of re-scanning to seconds of database queries. Executive Order 14028 on Improving the Nation's Cybersecurity mandates SBOM generation for software sold to the US government, making this capability a regulatory requirement for many organizations.
A key gotcha is SBOM completeness versus accuracy. Trivy generates SBOMs based on what it can detect through package managers and lockfiles, but it cannot identify statically compiled binaries, vendored dependencies copied without a manifest, or custom-built shared libraries. If the checkout-service includes a statically linked C library that was compiled from source in a multi-stage build, that component will be absent from the SBOM. Teams should supplement Trivy-generated SBOMs with build system metadata and provenance attestations to fill these gaps. Another trap is assuming that an SBOM generated at build time remains accurate indefinitely. If the base image uses floating tags like alpine:3.19 and the tag is updated with security patches, the stored SBOM no longer reflects the running container. Always generate SBOMs against specific image digests and regenerate them when images are rebuilt. Finally, be aware that SBOM rescanning with trivy sbom does not detect misconfigurations or secrets, only component vulnerabilities, so it complements but does not replace full image scanning.
Code Example
# Generate a CycloneDX SBOM for the payments-api container image
trivy image --format cyclonedx --output payments-api-sbom.cdx.json payments-api:v2.3.1
# Generate an SPDX SBOM for the user-auth-service image
trivy image --format spdx-json --output user-auth-sbom.spdx.json user-auth-service:v1.8.0
# Generate SBOM from a filesystem directory before containerization
trivy fs --format cyclonedx --output source-sbom.cdx.json /app/order-processing-service
# Rescan a previously generated SBOM against the latest vulnerability database
trivy sbom payments-api-sbom.cdx.json
# Rescan with severity filtering and exit code for CI integration
trivy sbom --severity CRITICAL,HIGH --exit-code 1 payments-api-sbom.cdx.json
# Generate SBOM for all images in a Kubernetes namespace
# for pod in $(kubectl get pods -n payments -o jsonpath='{.items[*].spec.containers[*].image}'); do
# trivy image --format cyclonedx --output "sbom-$(echo $pod | tr '/:' '-').json" "$pod"
# done
# Upload SBOM to Dependency-Track for centralized tracking
curl -X POST https://deptrack.internal.company.com/api/v1/bom -H 'X-Api-Key: API_KEY' -F '[email protected]' -F 'projectName=payments-api' -F 'projectVersion=v2.3.1'
# Verify SBOM integrity using cosign attestation
cosign attest --predicate payments-api-sbom.cdx.json --type cyclonedx payments-api:v2.3.1
# Query which services contain a specific vulnerable package
grep -l '"name": "openssl"' *-sbom.cdx.jsonInterview Tip
A junior engineer typically knows what SBOM stands for but cannot explain the operational workflow around generating, storing, and rescanning them. Impress the interviewer by describing the full lifecycle: generate SBOMs at build time using trivy image --format cyclonedx, store them in a centralized tool like Dependency-Track, and rescan them using trivy sbom when new CVEs are published. Explain the two standard formats, CycloneDX and SPDX, and note that CycloneDX is more common in security-focused workflows while SPDX emphasizes license compliance. Mention Executive Order 14028 to show you understand the regulatory drivers behind SBOM adoption. Discuss the completeness gap with statically compiled binaries and vendored dependencies that Trivy cannot detect, and suggest supplementing with build provenance attestations using tools like cosign.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ SBOM Lifecycle with Trivy │ │ │ │ ┌──────────────┐ ┌──────────────────┐ │ │ │ Build Image │ → │ trivy image │ │ │ │ payments-api │ │ --format cyclonedx│ │ │ └──────────────┘ └────────┬─────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────┐ │ │ │ SBOM Document │ │ │ │ ● OS packages │ │ │ │ ● App libraries │ │ │ │ ● Versions │ │ │ │ ● Licenses │ │ │ └────────┬─────────┘ │ │ │ │ │ ┌─────────────┼──────────┐ │ │ ↓ ↓ │ │ ┌────────────────────┐ ┌─────────────────┐ │ │ │ Dependency-Track │ │ cosign attest │ │ │ │ Central Registry │ │ Sign + Store │ │ │ └─────────┬──────────┘ └─────────────────┘ │ │ │ │ │ ↓ (New CVE Published) │ │ ┌────────────────────┐ │ │ │ trivy sbom rescan │ │ │ │ ● Check all SBOMs │ │ │ │ ● Identify affected│ │ │ │ services instantly│ │ │ └────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
In air-gapped environments, Trivy operates without internet access by pre-downloading the vulnerability database on a connected machine using trivy image --download-db-only, transferring the database file to the air-gapped system, and configuring Trivy to use the local database with --skip-db-update. Organizations can also host an internal OCI registry mirror to serve the database within the isolated network.
Detailed Answer
Think of configuring Trivy for an air-gapped environment like stocking a remote island medical clinic. The clinic cannot access the mainland pharmacy, so medical supplies must be loaded onto a ship, transported across the water, and unloaded at the island dock on a regular schedule. The clinic operates perfectly well between shipments, but someone must plan the logistics of keeping supplies current. Similarly, Trivy needs its vulnerability database to function, and in an air-gapped network, that database must be transported manually or through a controlled data transfer mechanism.
Air-gapped environments are networks that are physically isolated from the internet, commonly found in government classified systems, financial trading floors, healthcare networks handling PHI, and industrial control systems. Trivy requires a vulnerability database to match installed packages against known CVEs, and by default it downloads this database from an OCI registry at ghcr.io/aquasecurity/trivy-db on every run. In an air-gapped environment, this download fails because there is no outbound internet connectivity. The solution involves three components: downloading the database on a machine with internet access, transferring it to the air-gapped network through an approved data diode or removable media process, and configuring Trivy to use the local database without attempting to update it.
The database download process uses the trivy image --download-db-only command, which fetches the latest vulnerability database and stores it in the Trivy cache directory, typically located at ~/.cache/trivy/db/ on Linux systems. The database consists of two files: trivy.db, which is a BoltDB file containing vulnerability records indexed by package name and version, and metadata.json, which records the download timestamp and database schema version. These files are approximately 40-50 MB compressed and can be transferred via USB drive, one-way data diode, or an approved file transfer system. On the air-gapped side, the files are placed in the Trivy cache directory, and Trivy is invoked with the --skip-db-update flag to prevent it from attempting an internet connection. For the checkout-service scanning pipeline in a classified environment, this means the Jenkins build agent has a local copy of the database that is refreshed weekly through the approved media transfer process.
For organizations that want a more automated approach, hosting an internal OCI registry mirror is the recommended pattern. On the connected side, a scheduled job pulls the Trivy database image from ghcr.io/aquasecurity/trivy-db:2 and pushes it to a staging registry. The database image is then transferred to the air-gapped network's internal registry, such as an instance of Harbor or Artifactory running inside the isolated network. Trivy is configured with the --db-repository flag pointing to the internal registry URL, allowing it to pull the database as if it were operating normally. This approach also applies to the Java database that Trivy uses for scanning Java archives and the checks bundle used for misconfiguration detection. For the inventory-sync service running in a DoD IL5 environment, the internal Harbor instance at registry.internal.mil serves all three databases, and Trivy operates transparently without any special flags beyond the custom repository configuration.
A critical gotcha is database staleness. In a connected environment, Trivy always has access to the latest vulnerability data, but in an air-gapped setup, the database is only as current as the last transfer. A database that is two weeks old might miss recently published CVEs, creating a false sense of security. Establish a regular transfer cadence, ideally daily or at minimum weekly, and include a validation step that checks the metadata.json timestamp to ensure the database is not older than the acceptable threshold. Another common issue is the Java database and checks bundle, which are separate from the main vulnerability database. If you only transfer the main database, Trivy will still attempt to download the Java DB and checks bundle, causing scan failures for Java applications and misconfiguration checks. Use --skip-java-db-update and --skip-check-update flags, and ensure those databases are also transferred. Finally, ensure the Trivy binary itself is updated through the same air-gap transfer process, as older versions may not be compatible with newer database schemas.
Code Example
# On connected machine: download the latest Trivy vulnerability database trivy image --download-db-only # Locate the downloaded database files in the cache directory ls -la ~/.cache/trivy/db/ # Package the database for transfer to the air-gapped network tar czf trivy-db-$(date +%Y%m%d).tar.gz -C ~/.cache/trivy db/ # Also download the Java database for Java application scanning trivy image --download-java-db-only # Package the Java database for transfer tar czf trivy-java-db-$(date +%Y%m%d).tar.gz -C ~/.cache/trivy java-db/ # Transfer files via approved media to the air-gapped system # scp trivy-db-20240615.tar.gz airgap-build-server:/tmp/ # On the air-gapped machine: extract the database to Trivy cache mkdir -p ~/.cache/trivy && tar xzf /tmp/trivy-db-20240615.tar.gz -C ~/.cache/trivy/ # Extract the Java database as well tar xzf /tmp/trivy-java-db-20240615.tar.gz -C ~/.cache/trivy/ # Run Trivy scan with all update checks disabled for air-gapped operation trivy image --skip-db-update --skip-java-db-update --skip-check-update --severity CRITICAL,HIGH checkout-service:v3.1.0 # Alternative: use an internal OCI registry mirror for the database trivy image --db-repository registry.internal.company.com/security/trivy-db --severity CRITICAL,HIGH payments-api:v2.3.1 # Validate database freshness before scanning cat ~/.cache/trivy/db/metadata.json | python3 -c "import json,sys; print(json.load(sys.stdin)['UpdatedAt'])"
Interview Tip
A junior engineer typically assumes Trivy requires internet access and does not know it can operate offline. Demonstrate enterprise experience by explaining the three-component solution: download the database on a connected machine, transfer it through an approved data diode or removable media process, and run Trivy with --skip-db-update on the air-gapped side. Mention the internal OCI registry mirror approach as the more scalable alternative, where a Harbor or Artifactory instance inside the isolated network serves the database image. Discuss the three separate databases that need transferring: the main vulnerability DB, the Java DB, and the checks bundle. Emphasize the database staleness risk and the need for a regular transfer cadence with freshness validation. Reference specific compliance frameworks like DoD IL5 or FedRAMP that commonly require air-gapped scanning to show you have worked in regulated environments.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Air-Gapped Trivy Configuration │ │ │ │ ┌───────────────────────────────────────┐ │ │ │ Connected Network │ │ │ │ │ │ │ │ ┌─────────────┐ ┌──────────────┐ │ │ │ │ │ ghcr.io/ │ → │ trivy │ │ │ │ │ │ trivy-db │ │ --download- │ │ │ │ │ │ │ │ db-only │ │ │ │ │ └─────────────┘ └──────┬───────┘ │ │ │ └───────────────────────────┼───────────┘ │ │ │ │ │ ┌─────────┼─────────┐ │ │ │ Data Transfer │ │ │ │ ● USB Drive │ │ │ │ ● Data Diode │ │ │ │ ● Approved Media │ │ │ └─────────┼─────────┘ │ │ │ │ │ ┌───────────────────────────┼───────────┐ │ │ │ Air-Gapped Network ↓ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Local Cache │ → │ trivy image │ │ │ │ │ │ ~/.cache/ │ │ --skip-db- │ │ │ │ │ │ trivy/db/ │ │ update │ │ │ │ │ └──────────────┘ └──────┬───────┘ │ │ │ │ ↓ │ │ │ │ ┌──────────────┐ │ │ │ │ │ Scan Results │ │ │ │ │ │ payments-api │ │ │ │ │ └──────────────┘ │ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy scans private registry images by authenticating via Docker's credential helpers, environment variables (TRIVY_USERNAME and TRIVY_PASSWORD), or the docker login session. For cloud registries like ECR, GCR, and ACR, Trivy supports native credential providers and IAM-based authentication without storing static credentials.
Detailed Answer
Think of scanning a private registry image like accessing a members-only library. You cannot just walk in and start reading books. You need a membership card (credentials) that the librarian (registry) validates before granting access to the collection. Different libraries accept different types of identification: some want a username and password, others accept a digital membership token, and premium libraries like the ones run by AWS and Google let you use your government-issued ID (IAM role) for seamless entry without carrying a separate card.
Trivy supports scanning images from private container registries by leveraging the same credential mechanisms used by Docker and container runtimes. The simplest method is to run docker login against the registry before invoking Trivy. Docker login stores credentials in the ~/.docker/config.json file, and Trivy reads this file automatically when it needs to pull an image. This works for any registry that supports Docker's v2 API, including Harbor, Nexus, JFrog Artifactory, GitLab Container Registry, and GitHub Container Registry. For the payments-api stored in a private Harbor instance, running docker login harbor.internal.company.com followed by trivy image harbor.internal.company.com/payments/payments-api:v2.3.1 is all that is needed. Trivy uses the stored credentials to authenticate and pull the image layers for analysis.
For CI/CD pipelines where interactive docker login is not practical, Trivy supports environment variable authentication through TRIVY_USERNAME and TRIVY_PASSWORD. These variables are set in the pipeline's secret management system and consumed by Trivy at runtime without writing credentials to disk. This approach is preferred in Jenkins, GitLab CI, and GitHub Actions where secrets are injected as environment variables. Trivy also supports registry-specific credential files through the TRIVY_REGISTRY_TOKEN environment variable for token-based authentication and the --registry-token CLI flag. For organizations using Docker credential helpers like docker-credential-ecr-login for AWS ECR or docker-credential-gcr for Google GCR, Trivy integrates transparently because it reads the credHelpers configuration from Docker's config.json and delegates authentication to the appropriate helper binary.
Cloud-native registries provide the most seamless authentication experience. For AWS ECR, Trivy can use the AWS credential chain including instance profiles, environment variables, and shared credential files, meaning an EC2 instance or ECS task with the appropriate IAM role can scan ECR images without any explicit credential configuration. The order-processing-service team running their CI pipeline on an EC2 build agent simply needs the ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, and ecr:GetAuthorizationToken IAM permissions attached to the instance profile. For Google GCR and Artifact Registry, Trivy uses Application Default Credentials, so a GKE workload or Cloud Build step with the appropriate service account can scan images natively. Azure ACR supports similar integration through managed identities and the az acr login command. These cloud-native patterns eliminate static credentials entirely, which is a significant security improvement over username and password pairs that can be leaked or rotated improperly.
A critical gotcha is scanning images that use manifest lists (multi-architecture images). When you push a manifest list to a registry, the single tag resolves to different image digests depending on the platform. By default, Trivy scans the image matching the host platform, which in a CI pipeline is typically linux/amd64. If your user-auth-service also runs on ARM nodes, vulnerabilities specific to the ARM image variant will not be detected unless you explicitly specify the platform with --platform linux/arm64. Another common issue is registry rate limiting. Docker Hub enforces pull rate limits for unauthenticated and free-tier users, and a CI pipeline scanning multiple images can exhaust the limit quickly. Always authenticate to Docker Hub even for public images to get higher rate limits, and consider using a pull-through cache registry like Harbor to avoid hitting Docker Hub directly. Finally, ensure that the Trivy process has network access to the registry from the CI runner. In environments with network policies or proxy servers, configure the HTTPS_PROXY environment variable and ensure the registry's TLS certificate is trusted by the system's certificate store.
Code Example
# Authenticate to a private Harbor registry before scanning
docker login harbor.internal.company.com
# Scan a private image after docker login stores credentials
trivy image harbor.internal.company.com/payments/payments-api:v2.3.1
# Use environment variables for CI/CD pipeline authentication
export TRIVY_USERNAME=ci-scanner
# Set the registry password from the CI secret store
export TRIVY_PASSWORD=${HARBOR_TOKEN}
# Scan the private image using environment variable credentials
trivy image --severity CRITICAL,HIGH harbor.internal.company.com/checkout/checkout-service:v1.5.0
# Scan an AWS ECR image using IAM role authentication (no explicit credentials needed)
trivy image 123456789012.dkr.ecr.us-east-1.amazonaws.com/order-processing-service:v3.0.0
# Scan a Google Artifact Registry image using application default credentials
trivy image us-docker.pkg.dev/myproject/services/inventory-sync:v2.1.0
# Scan an Azure ACR image after az login
az acr login --name mycompanyregistry
# Run Trivy against the ACR-hosted user-auth-service image
trivy image mycompanyregistry.azurecr.io/user-auth-service:v1.8.0
# Scan a specific platform variant for multi-arch images
trivy image --platform linux/arm64 harbor.internal.company.com/payments/payments-api:v2.3.1
# Scan through a corporate proxy server
export HTTPS_PROXY=http://proxy.internal.company.com:3128
# Run the scan with proxy configuration active
trivy image --severity CRITICAL,HIGH harbor.internal.company.com/payments/payments-api:v2.3.1Interview Tip
A junior engineer typically defaults to docker login as the only authentication method and does not consider cloud-native credential chains. Demonstrate breadth by explaining three authentication tiers: Docker config.json credentials from docker login for traditional registries, environment variables TRIVY_USERNAME and TRIVY_PASSWORD for CI/CD pipelines, and cloud-native IAM integration for ECR, GCR, and ACR that eliminates static credentials entirely. Name the specific IAM permissions required for ECR scanning: ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, and ecr:GetAuthorizationToken. Mention the multi-architecture scanning consideration with the --platform flag, as this shows you understand container image internals beyond just pulling and scanning. Discuss registry rate limiting on Docker Hub and the pull-through cache pattern as a mitigation strategy.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Private Registry Scanning Flow │ │ │ │ ┌──────────────────────────────────┐ │ │ │ Authentication Methods │ │ │ │ │ │ │ │ ┌────────────┐ ┌─────────────┐ │ │ │ │ │docker login│ │TRIVY_USERNAME│ │ │ │ │ │config.json │ │TRIVY_PASSWORD│ │ │ │ │ └─────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ │ │ ┌─────┼───────────────┼──────┐ │ │ │ │ │ Cloud Native IAM │ │ │ │ │ │ ● AWS: Instance Profile │ │ │ │ │ │ ● GCP: Service Account │ │ │ │ │ │ ● Azure: Managed Identity │ │ │ │ │ └─────────────┬──────────────┘ │ │ │ └────────────────┼─────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────┐ │ │ │ Private Registry │ │ │ │ ┌──────────┐ ┌─────────────┐ │ │ │ │ │payments- │ │checkout- │ │ │ │ │ │api:v2.3 │ │service:v1.5 │ │ │ │ │ └────┬─────┘ └──────┬──────┘ │ │ │ └───────┼──────────────┼─────────┘ │ │ │ │ │ │ ↓ ↓ │ │ ┌────────────────────────────────┐ │ │ │ Trivy Image Scanner │ │ │ │ ● Pull layers via registry API│ │ │ │ ● Scan OS + App dependencies │ │ │ │ ● Report vulnerabilities │ │ │ └────────────────────────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy detects secrets using its built-in secret scanner that applies regular expression patterns and entropy analysis against file contents in container images, git repositories, and filesystems. It identifies API keys, passwords, private keys, tokens, and cloud credentials by matching known secret patterns from providers like AWS, GitHub, Slack, and database connection strings.
Detailed Answer
Think of Trivy's secret detection like a bank's fraud detection system monitoring transactions. The system maintains a catalog of known suspicious patterns, such as transactions from blacklisted regions, unusual amounts, or specific sequences of digits that match stolen card numbers. When a transaction matches one of these patterns, it is flagged for review. Similarly, Trivy maintains a library of regular expression patterns that match the structure of known secret types, and it scans every file in the target looking for matches.
Trivy's secret scanner is one of its built-in scanners alongside vulnerability detection and misconfiguration checking. When invoked with --scanners secret or as part of a comprehensive scan, Trivy examines every file in the target artifact, whether that is a container image, a filesystem directory, or a git repository. The scanner applies a curated library of over 100 regular expression rules that match the known formats of secrets from major providers. For example, AWS access keys always start with AKIA followed by 16 alphanumeric characters, GitHub personal access tokens begin with ghp_ followed by 36 characters, and Slack webhook URLs follow a specific URL pattern. Beyond pattern matching, Trivy uses entropy analysis to detect high-entropy strings that may be randomly generated secrets even if they do not match a known provider pattern.
The scanning process works at the file content level. For container images, Trivy extracts every layer and examines the contents of every file, including configuration files, environment scripts, application code, and embedded resources. This means secrets that were added in an early Dockerfile layer and deleted in a later layer are still detected because Docker layers are additive and the file content persists in the lower layer. For filesystem scanning with trivy fs, Trivy walks the directory tree and reads each file, applying the pattern rules against the content. For git repository scanning with trivy repo, it can clone a remote repository and scan the current state. The scanner respects a built-in allowlist of file paths and patterns to reduce false positives, such as test fixtures, documentation examples, and known placeholder values. Teams can extend this allowlist using the --secret-config flag to provide a custom configuration file that defines additional rules or suppresses specific patterns.
In production workflows for services like the payments-api and user-auth-service, secret scanning is typically integrated at two points. First, it runs as a pre-commit or CI step against the source code repository to catch secrets before they are committed to version control. Running trivy fs --scanners secret against the repository root as part of a pull request check prevents developers from accidentally committing API keys or database passwords. Second, it runs as part of the container image scan in the CI pipeline to catch secrets that might be baked into the image during the build process, such as credentials embedded in configuration files or environment variables hardcoded in Dockerfiles. The inventory-sync team, for instance, discovered that their build process was copying a .env file containing production database credentials into the image because it was not excluded in .dockerignore. Trivy caught this during the image scan and blocked the pipeline, preventing the credentials from reaching the container registry.
A critical gotcha is the false positive rate in secret scanning. High-entropy strings in test fixtures, documentation, and example configuration files frequently trigger matches. A test file containing example_api_key=AKIA1234567890ABCDEF will match the AWS access key pattern even though it is not a real secret. Without proper tuning, the noise from false positives causes teams to ignore or disable the scanner entirely, defeating its purpose. Use the --secret-config flag to add allowlists for specific file paths like test/ and docs/ directories, and for specific patterns that your codebase legitimately uses. Another common issue is performance. Secret scanning reads the full content of every file, which can be slow for large repositories or images with many files. Use the --skip-dirs flag to exclude known safe directories like vendor/ or node_modules/ that contain third-party code unlikely to contain your organization's secrets. Finally, remember that Trivy's secret scanner checks the current file state, not git history. A secret that was committed and then removed in a subsequent commit will not be detected by trivy fs, though it will be detected in the container image if both layers are present.
Code Example
# Scan a container image for embedded secrets trivy image --scanners secret payments-api:v2.3.1 # Scan a local filesystem directory for secrets in the source code trivy fs --scanners secret /app/user-auth-service # Scan a git repository for secrets before committing trivy repo --scanners secret https://github.com/myorg/order-processing-service # Run a comprehensive scan combining vulnerability and secret scanning trivy image --scanners vuln,secret --severity CRITICAL,HIGH --exit-code 1 checkout-service:v1.5.0 # Create a custom secret scanning configuration to reduce false positives # Create trivy-secret-config.yaml with custom allowlists # allow-rules: # - description: "Test fixtures with example keys" # path: "test/.*" # - description: "Documentation examples" # path: "docs/.*" # - description: "Example placeholder values" # match: "EXAMPLE_.*|PLACEHOLDER_.*" # Run scan with custom secret configuration trivy fs --scanners secret --secret-config trivy-secret-config.yaml /app/inventory-sync # Scan filesystem while skipping vendor directories for performance trivy fs --scanners secret --skip-dirs vendor,node_modules,dist /app/payments-api # Generate JSON output for integration with alerting systems trivy fs --scanners secret --format json --output secret-findings.json /app/user-auth-service # Scan a Dockerfile for hardcoded credentials trivy config --scanners secret Dockerfile
Interview Tip
A junior engineer typically mentions that Trivy can find secrets but cannot explain the detection mechanisms or the operational workflow around false positive management. Differentiate yourself by explaining the dual detection approach: pattern matching with over 100 provider-specific regular expressions for known secret formats like AWS AKIA keys and GitHub ghp_ tokens, supplemented by entropy analysis for detecting random strings that may be custom secrets. Discuss the two integration points: pre-commit scanning against source code to prevent secrets from entering version control, and image scanning in CI to catch secrets baked into Docker layers. Address the false positive problem directly by mentioning the --secret-config flag for custom allowlists and the --skip-dirs flag for excluding vendor directories. The strongest answers note that Docker image scanning catches secrets deleted in later layers because layers are additive, a subtlety that filesystem scanning misses.
◈ Architecture Diagram
┌─────────────────────────────────────────────┐ │ Trivy Secret Detection Flow │ │ │ │ ┌────────────────────────────────────┐ │ │ │ Scan Targets │ │ │ │ ● Container Image Layers │ │ │ │ ● Filesystem Directories │ │ │ │ ● Git Repositories │ │ │ └───────────────┬────────────────────┘ │ │ │ │ │ ↓ │ │ ┌────────────────────────────────────┐ │ │ │ Detection Engine │ │ │ │ │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ Pattern Matching (100+ rules)│ │ │ │ │ │ ● AWS: AKIA... (20 chars) │ │ │ │ │ │ ● GitHub: ghp_... (36 chars)│ │ │ │ │ │ ● Slack: hooks.slack.com/...│ │ │ │ │ │ ● Private Keys: -----BEGIN │ │ │ │ │ └──────────────────────────────┘ │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ Entropy Analysis │ │ │ │ │ │ ● High randomness strings │ │ │ │ │ │ ● Custom secret detection │ │ │ │ │ └──────────────────────────────┘ │ │ │ └───────────────┬────────────────────┘ │ │ │ │ │ ┌──────────┼──────────┐ │ │ ↓ ↓ │ │ ┌──────────┐ ┌────────────┐ │ │ │ ✗ Secret │ │ ✓ Clean │ │ │ │ Found │ │ No secrets │ │ │ │ Block CI │ │ Pass gate │ │ │ └──────────┘ └────────────┘ │ └─────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy supports custom OPA Rego policies through its misconfiguration scanner, allowing teams to write organization-specific compliance rules that evaluate Dockerfiles, Kubernetes manifests, Terraform configurations, and other IaC files. Custom policies are placed in a directory and referenced with the --policy flag, extending Trivy's built-in checks with business-specific requirements.
Detailed Answer
Think of Trivy's built-in misconfiguration checks as a standard building code that applies to every construction project. These codes cover universal safety requirements like fire exits and structural load limits. But a hospital has additional regulations about biohazard containment, and a data center has requirements about cooling system redundancy that general building codes do not address. Custom OPA Rego policies are those specialized regulations, written to enforce the unique compliance requirements of your organization that generic security checks cannot cover.
Trivy's misconfiguration scanner uses the Open Policy Agent (OPA) engine internally to evaluate configuration files against security policies written in the Rego policy language. Trivy ships with hundreds of built-in checks covering CIS Benchmarks, NIST guidelines, and security best practices for Docker, Kubernetes, Terraform, CloudFormation, Helm charts, and other infrastructure-as-code formats. However, every organization has custom requirements that go beyond industry standards. A financial services company might require that all container images use a specific approved base image registry, that Kubernetes deployments in the payments namespace always include a PodDisruptionBudget, or that Terraform security groups never allow ingress from 0.0.0.0/0 on any port. Custom Rego policies let you codify these requirements and enforce them through the same Trivy scanning pipeline.
Writing a custom Trivy policy requires understanding the Rego policy structure that Trivy expects. Each policy file must declare a specific package namespace, include metadata annotations that define the policy ID, title, description, severity, and the input type it applies to. The policy must export a deny rule that returns a message string when the configuration violates the policy. For example, a policy that enforces approved base images for the order-processing-service would inspect the Dockerfile's FROM instructions and deny any image that does not match the approved registry pattern. The input document that Trivy provides to the Rego engine varies by file type: for Dockerfiles it provides the parsed instruction tree, for Kubernetes manifests it provides the full resource spec, and for Terraform files it provides the parsed resource blocks. Trivy loads custom policies from a directory specified with the --policy flag and evaluates them alongside the built-in checks.
In a production compliance workflow, custom policies are typically stored in a dedicated repository owned by the security or platform engineering team. The user-auth-service, payments-api, checkout-service, and inventory-sync teams all reference this shared policy repository in their CI pipelines. The pipeline clones the policy repository, then runs trivy config --policy ./compliance-policies against the service's infrastructure files. This ensures consistent enforcement across all teams without requiring each team to maintain their own copy of the policies. For Kubernetes environments, the same Rego policies can be enforced at admission time using OPA Gatekeeper, creating a defense-in-depth approach where policies are checked both at build time by Trivy and at deploy time by Gatekeeper. The platform team at a fintech company might maintain policies that require PCI DSS compliance controls such as encryption at rest for all persistent volumes, network policies that restrict cross-namespace communication, and mandatory pod security standards that prevent privileged containers.
A critical gotcha is the mismatch between the input schema that Trivy provides to Rego policies and the schema that standalone OPA expects. Trivy preprocesses configuration files into a specific input format before passing them to the Rego engine, and this format differs from what you might see when using OPA's conftest tool directly. Always test custom policies using trivy config --policy with --debug to inspect the actual input document. Another common issue is policy priority and conflict resolution. When a custom policy contradicts a built-in check, both results appear in the scan output, which can confuse teams. Use the --skip-check-update flag to prevent Trivy from downloading updated built-in checks that might conflict with your custom policies, and use --skip-policy-update to prevent fetching external policy bundles. Finally, version your policies alongside your infrastructure code and require pull request reviews from the security team for any policy changes, because a permissive policy change could silently disable compliance enforcement across the entire organization.
Code Example
# Custom Rego policy: enforce approved base images for all Dockerfiles
# Save as policies/approved_base_images.rego
# package custom.dockerfile.approved_base
# __rego_metadata__ := {
# "id": "CUSTOM-001",
# "title": "Use approved base images only",
# "severity": "HIGH",
# "type": "Dockerfile Custom Check"
# }
# approved_registries := ["harbor.internal.company.com", "gcr.io/myorg-approved"]
# deny[msg] {
# input.Stages[_].Commands[i].Cmd == "from"
# val := input.Stages[_].Commands[i].Value[0]
# not startswith(val, approved_registries[_])
# msg := sprintf("Base image '%s' is not from an approved registry", [val])
# }
# Run Trivy with custom policies against a Dockerfile
trivy config --policy ./policies --severity HIGH,CRITICAL --exit-code 1 ./Dockerfile
# Scan Kubernetes manifests against custom compliance policies
trivy config --policy ./policies --namespaces custom --severity HIGH,CRITICAL ./k8s-manifests/
# Scan Terraform files against custom policies for infrastructure compliance
trivy config --policy ./policies --namespaces custom ./terraform/
# Run with debug to inspect the input document Trivy passes to Rego
trivy config --policy ./policies --debug ./Dockerfile 2>&1 | head -50
# Combine custom policies with built-in checks for comprehensive scanning
trivy config --policy ./policies --severity LOW,MEDIUM,HIGH,CRITICAL ./k8s-manifests/
# Test a specific policy file in isolation against a target
trivy config --policy ./policies/approved_base_images.rego --namespaces custom ./Dockerfile
# Scan a Helm chart with custom policies applied
trivy config --policy ./policies --helm-values values-production.yaml ./charts/payments-api/
# List all policy check IDs including custom ones
trivy config --policy ./policies --list-all-checksInterview Tip
A junior engineer typically knows that Trivy can check for misconfigurations but does not realize it uses OPA Rego internally or that custom policies can be written. Stand out by explaining the policy structure: the required package namespace, __rego_metadata__ annotations with policy ID and severity, and the deny rule that returns a violation message. Mention that the input document schema varies by file type and that Trivy's format differs from standalone OPA conftest, so policies must be tested with trivy config --debug. Discuss the organizational model where a central security team maintains a shared policy repository that all service teams reference in their CI pipelines. Connect this to defense-in-depth by explaining that the same Rego logic can be enforced at admission time using OPA Gatekeeper in Kubernetes, creating a build-time and deploy-time compliance gate. Reference specific compliance frameworks like PCI DSS or SOC 2 that drive custom policy requirements.
💬 Comments
Quick Answer
Trivy Operator deploys as a Kubernetes operator that automatically scans workloads for vulnerabilities, misconfigurations, secrets, and RBAC issues. It creates CRD-based reports (VulnerabilityReports, ConfigAuditReports, ExposedSecretReports) that integrate with monitoring stacks for continuous security posture visibility.
Detailed Answer
Think of Trivy Operator as a dedicated quality inspector permanently stationed inside a manufacturing plant. Rather than inspecting products only when they arrive at a checkpoint, this inspector continuously walks the floor, checking every machine, every process, and every output against safety standards. When a new machine is installed or a process changes, the inspector immediately evaluates it and files a detailed report. If a safety recall is issued for a component already in use, the inspector re-evaluates every machine using that component without anyone having to request it. Trivy Operator brings this continuous inspection model to Kubernetes, replacing manual scan-and-forget workflows with automated, always-on security evaluation.
Trivy Operator installs into a Kubernetes cluster via Helm and registers several Custom Resource Definitions that represent security findings. When a new pod is created or an existing deployment is updated, the operator detects the change through Kubernetes watch mechanisms and automatically triggers scans against the container images, Kubernetes manifests, and RBAC configurations. For a microservices platform running services like payments-api, user-auth-service, and order-processing-service, the operator scans every container image in every pod across every namespace without requiring teams to configure individual scanning jobs. The scan results are stored as Kubernetes custom resources alongside the workloads they describe, making security findings queryable through standard kubectl commands and accessible through the Kubernetes API. A VulnerabilityReport resource is created for each container, listing every CVE with severity, fix version, and resource context.
The operator's architecture separates the controller from the scanning engine. The controller watches for workload changes and manages the scan lifecycle, while the actual vulnerability scanning is performed by Trivy scanner pods that are created on demand. In large clusters running hundreds of services like inventory-sync, checkout-service, notification-gateway, and settlement-processor, the operator manages scan concurrency to avoid overwhelming the cluster's compute resources. Configuration options control the maximum number of concurrent scan jobs, resource requests and limits for scanner pods, and scan intervals for periodic rescanning. The operator can be configured to use a persistent Trivy server deployment instead of standalone scanner pods, which caches the vulnerability database and significantly reduces scan times for subsequent scans.
Integration with the observability stack transforms raw security data into actionable intelligence. The operator exposes Prometheus metrics for vulnerability counts by severity, namespace, and workload, enabling Grafana dashboards that show the security posture of the entire cluster at a glance. Alert rules trigger when critical vulnerabilities are detected in production namespaces or when a workload exceeds a threshold of high-severity findings. Teams configure separate alerting policies per namespace so the payments team receives alerts about payments-api vulnerabilities while the fraud detection team receives alerts about their own services. ConfigAuditReports identify Kubernetes security misconfigurations such as containers running as root, missing resource limits, or overly permissive network policies, providing a continuous compliance check against CIS Kubernetes benchmarks.
The production challenge with Trivy Operator at enterprise scale is managing the resource footprint and scan noise. In a cluster with 500 deployments across 50 namespaces, the operator generates thousands of scan reports that must be stored in etcd, consuming significant cluster state storage. Teams implement report retention policies that prune old reports after a configurable period and configure scan exclusions for system namespaces or known-good infrastructure images that are managed through a separate pipeline. Another common issue is scan storms during cluster-wide rollouts or base image updates, where hundreds of workloads change simultaneously. Configuring scan rate limiting and prioritizing production namespaces over development namespaces prevents the operator from consuming excessive cluster resources during these events. Enterprise teams also integrate the operator's findings with external vulnerability management platforms through webhook integrations or custom controllers that sync VulnerabilityReports to systems like Jira or ServiceNow for tracking and SLA enforcement.
Code Example
# Install Trivy Operator via Helm into the trivy-system namespace
helm repo add aqua https://aquasecurity.github.io/helm-charts/
# Update Helm repo index to get latest chart versions
helm repo update
# Deploy operator with custom configuration for enterprise use
helm install trivy-operator aqua/trivy-operator \
--namespace trivy-system \
--create-namespace \
--set trivy.mode=ClientServer \
--set trivy.serverURL=http://trivy-server.trivy-system:4954 \
--set operator.scanJobsConcurrentLimit=5 \
--set operator.scanJobsRetryDelay=30s \
--set operator.vulnerabilityScannerEnabled=true \
--set operator.configAuditScannerEnabled=true \
--set operator.exposedSecretScannerEnabled=true \
--set operator.rbacAssessmentScannerEnabled=true \
--set compliance.failEntriesLimit=20
# Deploy a dedicated Trivy Server for vulnerability DB caching
helm install trivy-server aqua/trivy \
--namespace trivy-system \
--set trivy.mode=server \
--set trivy.persistence.enabled=true \
--set trivy.persistence.size=5Gi
# Check VulnerabilityReports for payments-api in the payments namespace
kubectl get vulnerabilityreports -n payments -l trivy-operator.resource.name=payments-api -o wide
# View detailed CVE findings for a specific report
kubectl get vulnerabilityreport -n payments payments-api-payments-api -o jsonpath='{.report.vulnerabilities[?(@.severity=="CRITICAL")]}' | jq .
# Check ConfigAuditReports for misconfigurations across all namespaces
kubectl get configauditreports -A -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,CRITICAL:.report.summary.criticalCount,HIGH:.report.summary.highCount'
# View ExposedSecretReports to find leaked credentials in images
kubectl get exposedsecretreports -n checkout -o yaml
# Prometheus alert rule for critical vulnerabilities in production
# File: trivy-alerts.yaml
# groups:
# - name: trivy-operator-alerts
# rules:
# - alert: CriticalVulnerabilityDetected
# expr: trivy_image_vulnerabilities{severity="Critical",namespace=~"payments|checkout|settlements"} > 0
# for: 5m
# labels:
# severity: critical
# annotations:
# summary: "Critical CVE found in {{ $labels.image_repository }}"Interview Tip
A junior engineer typically describes Trivy Operator as simply installing a Helm chart that scans images, without addressing the operational complexities of running continuous scanning at scale. In an advanced interview, you should explain the CRD-based architecture: VulnerabilityReports, ConfigAuditReports, ExposedSecretReports, and RBACAssessmentReports stored as Kubernetes resources queryable via kubectl. Discuss the client-server mode where a dedicated Trivy server caches the vulnerability database, eliminating redundant downloads across scan jobs. Address the etcd storage pressure from thousands of reports and how retention policies mitigate it. Explain scan concurrency controls that prevent resource storms during mass rollouts. Demonstrate integration with Prometheus metrics and Grafana dashboards for security posture visibility.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────┐ │ Kubernetes Cluster │ │ │ │ ┌──────────────┐ watches ┌──────────────────────┐ │ │ │ Trivy │──────────────→│ Workloads │ │ │ │ Operator │ │ ● payments-api │ │ │ │ Controller │ │ ● user-auth-service │ │ │ └──────┬───────┘ │ ● checkout-service │ │ │ │ └──────────────────────┘ │ │ │ creates scan jobs │ │ ↓ │ │ ┌──────────────┐ queries ┌──────────────────────┐ │ │ │ Scanner │──────────────→│ Trivy Server │ │ │ │ Jobs │ │ (cached vuln DB) │ │ │ └──────┬───────┘ └──────────────────────┘ │ │ │ │ │ │ stores results as CRDs │ │ ↓ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Custom Resources │ │ │ │ ┌─────────────────┐ ┌────────────────────────┐ │ │ │ │ │ Vulnerability │ │ ConfigAudit │ │ │ │ │ │ Reports │ │ Reports │ │ │ │ │ └─────────────────┘ └────────────────────────┘ │ │ │ │ ┌─────────────────┐ ┌────────────────────────┐ │ │ │ │ │ ExposedSecret │ │ RBACAssessment │ │ │ │ │ │ Reports │ │ Reports │ │ │ │ │ └─────────────────┘ └────────────────────────┘ │ │ │ └──────────────────────┬───────────────────────────┘ │ │ │ metrics │ │ ↓ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Prometheus │──→│ Grafana │ │ │ │ Scrape │ │ Dashboard │ │ │ └──────────────┘ └──────────────┘ │ └──────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
Enterprise vulnerability management with Trivy involves centralized scanning across CI/CD pipelines, container registries, and runtime clusters, combined with policy-driven severity gating, automated ticket creation for remediation tracking, SLA enforcement by severity tier, and executive dashboards that show organizational vulnerability posture trends over time.
Detailed Answer
Think of enterprise vulnerability management like a hospital's infection control program. A hospital does not simply test patients when they arrive and then forget about them. It continuously monitors for new infections, tracks treatment progress for every case, escalates unresolved cases to specialists within defined timeframes, reports infection rates to administrators, and adjusts protocols based on trends. The program spans every department, every floor, and every patient simultaneously, with clear ownership and accountability at each level. Enterprise vulnerability management with Trivy follows the same pattern: scan everywhere, track everything, enforce remediation timelines, and report progress to leadership.
The scanning tier establishes visibility across the entire software delivery lifecycle. Trivy scans are embedded at four critical points: developer workstations during local builds, CI/CD pipelines before images are pushed to registries, container registries for continuous rescanning against updated vulnerability databases, and running clusters through the Trivy Operator. For an organization operating dozens of microservices like payments-api, user-auth-service, order-processing-service, inventory-sync, and checkout-service across multiple environments, each scan point serves a different purpose. Local scans provide immediate developer feedback. Pipeline scans enforce gate policies that prevent vulnerable images from reaching registries. Registry scans catch newly published CVEs affecting existing images. Cluster scans confirm the actual deployed state matches the expected security posture. All scan results flow into a centralized vulnerability data lake where they are deduplicated, enriched with asset ownership metadata, and correlated across scan sources.
The policy tier defines how findings are triaged and prioritized. Raw vulnerability counts are meaningless without context: a critical CVE in a public-facing checkout-service is far more urgent than the same CVE in an internal batch-processing job that runs in an isolated network segment. Enterprise policies incorporate asset criticality, network exposure, data sensitivity, and exploitability to produce a risk-adjusted priority score. Trivy supports custom severity overrides through VEX documents and .trivyignore files, but enterprise teams extend this with a policy engine that maps CVE attributes to remediation SLAs. Critical vulnerabilities in tier-one services require remediation within 48 hours. High-severity findings in internet-facing services require patching within 7 days. Medium findings have a 30-day SLA, and low findings are tracked but not SLA-enforced. These SLAs are codified in the vulnerability management platform and automatically create escalation alerts when deadlines approach.
The automation tier connects scanning to remediation workflows without human intervention for routine cases. When Trivy detects a critical vulnerability in the payments-api image, the automation pipeline creates a Jira ticket assigned to the payments team, attaches the full scan report with CVE details and fix versions, updates the vulnerability dashboard, and optionally creates a pull request that bumps the affected dependency to the patched version. For base image vulnerabilities, the automation triggers a rebuild of all images descended from the affected base, runs the full test suite, and opens pull requests across affected repositories. This reduces the remediation cycle from days of manual coordination to hours of automated workflow. Teams that own services like notification-gateway or settlement-processor receive contextualized remediation guidance that specifies exactly which package to update and the minimum version that resolves the vulnerability.
The reporting tier provides visibility at every organizational level. Engineering managers see team-specific dashboards showing open vulnerabilities by service, remediation velocity, and SLA compliance rates. Security leadership sees organizational trends: total vulnerability counts over time, mean time to remediation by severity, percentage of deployments blocked by scanning gates, and comparison across business units. Executive dashboards show risk exposure in business terms: how many customer-facing services have unpatched critical vulnerabilities, what is the trend direction, and whether the organization is meeting its stated security objectives. These dashboards pull data from the centralized vulnerability data lake and are refreshed continuously as new scan results arrive. Quarterly security reviews use this data to adjust policies, allocate engineering capacity for security debt reduction, and demonstrate compliance to auditors and regulators who require evidence that vulnerability management is an active, measured process rather than a periodic checkbox exercise.
Code Example
# Enterprise Trivy scanning across the software delivery lifecycle
# Step 1: CI pipeline scan with policy gate and SBOM generation
trivy image --exit-code 1 \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--format json \
--output scan-results.json \
ecr.company.com/payments-api:${GIT_SHA}
# Generate SBOM in CycloneDX format for asset inventory
trivy image --format cyclonedx \
--output sbom-payments-api.json \
ecr.company.com/payments-api:${GIT_SHA}
# Step 2: Upload results to centralized vulnerability management platform
curl -X POST https://vulnmgmt.internal/api/v1/findings \
-H "Authorization: Bearer ${VULNMGMT_TOKEN}" \
-F "[email protected]" \
-F "[email protected]" \
-F "service=payments-api" \
-F "team=payments-team" \
-F "environment=staging"
# Step 3: Registry continuous scanning with cron-based rescans
# Kubernetes CronJob that rescans all production images nightly
# Iterates through all images in the production registry
for repo in payments-api user-auth-service order-processing-service inventory-sync checkout-service; do
# Scan each service image with the latest vulnerability database
trivy image --skip-update=false \
--format json \
--output "/reports/${repo}-nightly.json" \
"ecr.company.com/${repo}:production"
done
# Step 4: SLA enforcement query — find overdue critical findings
curl -s https://vulnmgmt.internal/api/v1/findings \
-H "Authorization: Bearer ${VULNMGMT_TOKEN}" \
-G -d 'severity=CRITICAL&sla_status=overdue&environment=production' | jq '.findings[] | {service, cve_id, days_overdue, owner_team}'
# Step 5: Automated remediation PR for dependency bumps
trivy image --format json ecr.company.com/checkout-service:production \
| jq -r '.Results[].Vulnerabilities[] | select(.Severity=="CRITICAL") | "\(.PkgName): \(.InstalledVersion) -> \(.FixedVersion)"'
# Step 6: Prometheus metrics for dashboard integration
# Custom exporter scrapes Trivy results and exposes gauges
# vuln_count{service="payments-api",severity="CRITICAL",namespace="production"} 2
# vuln_sla_compliance{team="payments-team"} 0.95
# vuln_mttr_hours{severity="CRITICAL"} 36Interview Tip
A junior engineer typically describes vulnerability management as running Trivy in CI and failing builds on critical findings, which covers only one of four required scan points. In an advanced interview, demonstrate understanding of the full lifecycle: scan at build time, scan registries continuously, scan running clusters with the operator, and feed all results into a centralized platform. Explain risk-adjusted prioritization: not all critical CVEs are equally urgent because asset criticality, network exposure, and exploitability context determine actual risk. Walk through SLA enforcement with concrete numbers (48-hour critical, 7-day high, 30-day medium) and explain how automated ticket creation and escalation alerts ensure accountability. Discuss executive reporting that translates vulnerability counts into business risk language and how quarterly reviews use trend data to allocate remediation engineering capacity.
◈ Architecture Diagram
┌───────────────────────────────────────────────────────────────┐ │ Enterprise Vulnerability Management Flow │ │ │ │ ┌──────────┐ ┌───────────┐ ┌───────────┐ ┌────────────┐ │ │ │Developer │ │ CI/CD │ │ Registry │ │ Cluster │ │ │ │Workstation│ │ Pipeline │ │ Rescan │ │ Operator │ │ │ │ trivy fs │ │ trivy img │ │ CronJob │ │ Trivy Op │ │ │ └────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬──────┘ │ │ │ │ │ │ │ │ └──────────────┴──────────────┴──────────────┘ │ │ │ │ │ ↓ │ │ ┌────────────────────────┐ │ │ │ Centralized Vuln DB │ │ │ │ ● Deduplicate │ │ │ │ ● Enrich with context │ │ │ │ ● Risk-adjust scores │ │ │ └───────────┬────────────┘ │ │ │ │ │ ┌──────────────┼──────────────┐ │ │ ↓ ↓ ↓ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Auto-Create │ │ SLA Engine │ │ Dashboards │ │ │ │ Jira Tickets│ │ 48h/7d/30d │ │ Exec Report │ │ │ │ + Assign │ │ Escalation │ │ Team Trends │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └───────────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
VEX documents allow teams to annotate Trivy findings with exploitability status (not_affected, affected, fixed, under_investigation), reducing noise from CVEs that are not exploitable in a specific deployment context. Trivy consumes VEX data in OpenVEX and CSAF formats to automatically suppress false positives and surface only actionable vulnerabilities.
Detailed Answer
Think of VEX as a pharmacist's note attached to a drug interaction warning. When a pharmacy system flags a potential drug interaction, the pharmacist reviews the specific patient context and may annotate the warning as not clinically significant for this patient because the dosage is below the threshold, the patient is not in the at-risk population, or the interacting drug is being used topically rather than systemically. The warning remains in the system for audit purposes, but it no longer triggers alarms or blocks dispensing. VEX provides the same contextual override for vulnerability findings: the CVE exists in the dependency tree, but expert analysis has determined it is not exploitable in this specific application context, and that determination is recorded in a machine-readable, auditable format.
VEX stands for Vulnerability Exploitability eXchange, a standard format for communicating whether a product is affected by a specific vulnerability and why. The core insight behind VEX is that most CVEs detected by scanners like Trivy are not actually exploitable in every application that contains the vulnerable package. A CVE in a JSON parsing library's XML handling code is irrelevant to an application that never processes XML input. A buffer overflow in a networking function does not affect an application that uses a different code path through the library. Without VEX, security teams waste enormous time investigating vulnerabilities that pose no real risk, creating alert fatigue that causes them to miss genuinely dangerous findings. For enterprise services like payments-api, order-processing-service, and checkout-service, VEX documents reduce the actionable vulnerability count by 40-70 percent, allowing teams to focus their remediation efforts on findings that actually matter.
Trivy supports VEX consumption in two primary formats: OpenVEX and CSAF (Common Security Advisory Framework). An OpenVEX document is a JSON file that contains a list of statements, each specifying a product identifier, a vulnerability identifier (CVE), a status (not_affected, affected, fixed, or under_investigation), and a justification. When Trivy scans an image and finds CVE-2024-32002 in libcurl, and the team has published a VEX statement marking that CVE as not_affected for their product because the vulnerable SOCKS5 proxy code path is not reachable, Trivy automatically suppresses that finding from the scan results. The VEX document becomes part of the software supply chain metadata, stored alongside the SBOM and the image signature in the OCI registry as an attached artifact.
Risk prioritization extends beyond VEX to incorporate multiple contextual signals. Trivy's CVSS scoring provides a base severity, but enterprise risk prioritization layers additional factors: is the affected service internet-facing or internal-only, does it process sensitive data like payment card numbers or personal information, is the vulnerability actively exploited in the wild according to CISA's Known Exploited Vulnerabilities catalog, and what is the blast radius if the service is compromised. Teams build prioritization matrices that combine Trivy's vulnerability data with asset inventory metadata from their CMDB. A high-severity CVE in inventory-sync, an internal batch service running in an isolated network segment, receives a lower priority than a medium-severity CVE in checkout-service, which directly processes customer payment data over the internet. This risk-adjusted approach ensures that limited remediation engineering capacity is applied where it reduces the most actual risk.
The operational challenge with VEX at enterprise scale is maintaining the accuracy and currency of VEX statements across hundreds of services. When a VEX statement marks a CVE as not_affected because a specific code path is not used, that determination must be re-evaluated when the application code changes. A new feature that starts processing XML input invalidates the VEX statement that said the XML parsing vulnerability was not exploitable. Enterprise teams address this by integrating VEX statement management into the code review process: when application code changes in ways that could affect vulnerability exploitability, the VEX documents are reviewed and updated as part of the pull request. Automated tools can partially assist by analyzing code paths and flagging when a VEX justification may no longer hold, but human security engineering judgment remains essential for complex exploitability assessments. VEX documents also have an expiration model where statements must be reviewed periodically even without code changes, ensuring that evolving threat intelligence and new exploit techniques are considered.
Code Example
# Create an OpenVEX document for payments-api
# This documents that specific CVEs are not exploitable in our context
cat > payments-api.openvex.json << 'VEXEOF'
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://company.com/vex/payments-api/2026-001",
"author": "[email protected]",
"timestamp": "2026-06-15T10:00:00Z",
"statements": [
{
"vulnerability": {"@id": "CVE-2024-32002"},
"products": [{"@id": "pkg:oci/payments-api@sha256:abc123"}],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"impact_statement": "payments-api does not use SOCKS5 proxy functionality in libcurl"
},
{
"vulnerability": {"@id": "CVE-2024-28849"},
"products": [{"@id": "pkg:oci/payments-api@sha256:abc123"}],
"status": "not_affected",
"justification": "vulnerable_code_not_present",
"impact_statement": "XML parsing module is excluded from the final build via multi-stage Dockerfile"
}
]
}
VEXEOF
# Scan payments-api with VEX filtering to suppress non-exploitable findings
trivy image --vex payments-api.openvex.json \
--format table \
--severity CRITICAL,HIGH \
ecr.company.com/payments-api:v4.2.0
# Attach VEX document to the OCI image as a referrer artifact
oras attach ecr.company.com/payments-api:v4.2.0 \
--artifact-type application/vex+json \
payments-api.openvex.json
# Compare scan results with and without VEX to measure noise reduction
trivy image --format json ecr.company.com/payments-api:v4.2.0 | jq '.Results[].Vulnerabilities | length'
# Output: 47 (without VEX)
trivy image --vex payments-api.openvex.json --format json ecr.company.com/payments-api:v4.2.0 | jq '.Results[].Vulnerabilities | length'
# Output: 18 (with VEX — 62% noise reduction)
# Generate SBOM and cross-reference with CISA KEV for active exploitation
trivy image --format cyclonedx --output sbom.json ecr.company.com/checkout-service:v2.1.0
# Query CISA Known Exploited Vulnerabilities catalog
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json \
| jq '[.vulnerabilities[].cveID]' > kev-list.json
# Cross-reference Trivy findings with KEV for active exploitation status
trivy image --format json ecr.company.com/checkout-service:v2.1.0 \
| jq --slurpfile kev kev-list.json '[.Results[].Vulnerabilities[] | select(.VulnerabilityID as $id | $kev[0] | index($id))]'Interview Tip
A junior engineer typically treats all CVEs as equally important and describes vulnerability management as fixing everything the scanner reports. In an advanced interview, demonstrate understanding that most scanner findings are not exploitable in every context and that VEX provides the industry-standard mechanism to document exploitability determinations. Explain the four VEX statuses (not_affected, affected, fixed, under_investigation) and the justification taxonomy (vulnerable_code_not_present, vulnerable_code_not_in_execute_path, inline_mitigations_already_exist). Discuss how VEX integrates into the software supply chain as an OCI artifact alongside SBOMs and signatures. Address the maintenance challenge: VEX statements must be reviewed when application code changes in ways that could affect exploitability. Quantify the noise reduction benefit and explain how combining VEX with CISA KEV data creates a two-dimensional prioritization matrix.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────┐ │ VEX-Enhanced Scanning Flow │ │ │ │ ┌──────────────┐ │ │ │ Trivy Scan │ │ │ │ Raw Findings │ │ │ │ 47 CVEs │ │ │ └──────┬───────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────┐ │ │ │ VEX Filter │ │ │ │ │ │ │ │ CVE-2024-32002 → not_affected ✗ │ │ │ │ CVE-2024-28849 → not_affected ✗ │ │ │ │ CVE-2024-50001 → affected ✓ │ │ │ │ CVE-2024-50002 → under_invest ● │ │ │ └──────┬───────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────┐ │ │ │ Risk Prioritization Matrix │ │ │ │ │ │ │ │ ┌─────────────┬──────┬───────────┐ │ │ │ │ │ CVE │ CVSS │ Priority │ │ │ │ │ ├─────────────┼──────┼───────────┤ │ │ │ │ │ CVE-50001 │ 9.8 │ P1 (KEV) │ │ │ │ │ │ CVE-50003 │ 8.1 │ P2 │ │ │ │ │ │ CVE-50004 │ 7.5 │ P3 │ │ │ │ │ └─────────────┴──────┴───────────┘ │ │ │ │ │ │ │ │ 18 actionable (62% noise removed) │ │ │ └─────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
A signing and verification pipeline combines Trivy scanning with Cosign keyless signing to create a chain of trust: images are scanned, scan results are attested as signed metadata, and Kubernetes admission controllers verify both the image signature and the attestation that the image passed security checks before allowing deployment.
Detailed Answer
Think of this pipeline as the pharmaceutical supply chain for prescription medications. Before a drug reaches a pharmacy shelf, it passes through manufacturing quality control, is sealed with a tamper-evident closure, receives a serialized barcode proving its origin, and each handler in the distribution chain verifies the seal and records the handoff. At the pharmacy, the pharmacist checks the seal, verifies the barcode against the manufacturer's database, and confirms the batch passed FDA testing before dispensing it to patients. If any seal is broken, any barcode fails verification, or testing records are missing, the drug is quarantined. The Trivy-plus-Cosign pipeline creates the same chain of trust for container images: scan for quality, sign for provenance, attest for compliance, and verify before deployment.
The pipeline begins with Trivy scanning the freshly built container image in CI/CD. For a service like payments-api, the build stage compiles the application and produces a container image. Before anything else happens, Trivy scans the image for vulnerabilities, misconfigurations, and exposed secrets. The scan results are evaluated against the organization's policy: no critical CVEs, no high CVEs without a documented VEX exception, no embedded credentials. If the image fails the scan, the pipeline stops and the image is never signed, ensuring that the signature acts as a quality seal. The scan results themselves are captured in a structured format (SARIF, CycloneDX, or a custom JSON schema) because they will be signed as an attestation in the next step, creating a cryptographic proof that this specific image passed this specific set of security checks.
Cosign keyless signing provides the cryptographic foundation without the operational burden of managing long-lived private keys. In a GitHub Actions workflow, the OIDC token that identifies the workflow run is exchanged with Sigstore's Fulcio certificate authority for a short-lived signing certificate. Cosign uses this certificate to sign the image digest, and the signing event is recorded in Sigstore's Rekor transparency log, creating a tamper-evident audit trail. The signature is stored as an OCI referrer artifact in the same container registry, linked to the image by its digest. For enterprise services like order-processing-service, checkout-service, and inventory-sync, each image built by the CI/CD pipeline receives a unique signature tied to the specific GitHub repository, workflow, and commit that produced it. This binding between identity and artifact is stronger than traditional key-based signing because there is no private key that can be stolen or shared.
Attestation adds a second layer beyond image signing. While the image signature proves who built the image, attestations prove what checks the image passed. After Trivy scanning completes and the image is signed, Cosign attest creates a signed in-toto attestation containing the scan results as the predicate. This means the Trivy scan report is cryptographically bound to the specific image digest and signed by the same CI/CD identity. Kubernetes admission controllers can then verify not only that the image was signed by an authorized pipeline but also that the attestation contains scan results meeting the organization's security policy. A Kyverno ClusterPolicy can extract fields from the attestation predicate, check that the vulnerability count at critical severity equals zero, verify that the scan was performed within the last 24 hours, and reject the pod if any condition fails.
The production complexity lies in the verification chain and failure modes. When Kyverno or OPA Gatekeeper verifies an image, it must contact the container registry to retrieve the signature and attestation, contact Rekor to verify the transparency log entry, and evaluate the attestation predicate against the policy. Each of these steps can fail due to network issues, registry rate limiting, or Rekor availability. Enterprise teams configure timeout handling, signature caching, and fallback policies that define behavior during verification outages. A common pattern is a break-glass mechanism where a designated security officer can temporarily annotate a namespace to bypass verification during incident response, with all bypass events logged and audited. Teams also implement pre-admission caching where a controller periodically verifies all images referenced by running workloads and caches the results, so that pod restarts during a verification service outage can proceed based on cached verification. For services like settlement-processor and notification-gateway, this ensures that legitimate scaling events and pod evictions do not cause outages because the signature verification infrastructure is temporarily unreachable.
Code Example
# Full CI/CD pipeline: scan with Trivy, sign with Cosign, attest results
# Step 1: Build the container image for order-processing-service
docker build -t ecr.company.com/order-processing-service:${GIT_SHA} \
-f services/order-processing/Dockerfile .
# Step 2: Scan with Trivy and save structured results
trivy image --exit-code 1 \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--format cosign-vuln \
--output trivy-scan-results.json \
ecr.company.com/order-processing-service:${GIT_SHA}
# Step 3: Push image to registry only if scan passes
docker push ecr.company.com/order-processing-service:${GIT_SHA}
# Step 4: Sign the image with Cosign keyless (OIDC identity)
cosign sign --yes \
--oidc-issuer=https://token.actions.githubusercontent.com \
ecr.company.com/order-processing-service:${GIT_SHA}
# Step 5: Attest scan results — cryptographically bind Trivy report to image
cosign attest --yes \
--predicate trivy-scan-results.json \
--type vuln \
ecr.company.com/order-processing-service:${GIT_SHA}
# Step 6: Verify signature and attestation manually
cosign verify \
--certificate-identity-regexp="https://github.com/myorg/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
ecr.company.com/order-processing-service:${GIT_SHA}
# Verify attestation exists and contains valid scan data
cosign verify-attestation \
--certificate-identity-regexp="https://github.com/myorg/.*" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
--type vuln \
ecr.company.com/order-processing-service:${GIT_SHA} | jq '.payload' | base64 -d | jq .
# Step 7: Kyverno policy enforcing signature + scan attestation
# apiVersion: kyverno.io/v1
# kind: ClusterPolicy
# metadata:
# name: verify-trivy-scan-attestation
# spec:
# validationFailureAction: Enforce
# rules:
# - name: check-vulnerability-attestation
# match:
# any:
# - resources:
# kinds: ["Pod"]
# namespaces: ["payments", "orders", "checkout"]
# verifyImages:
# - imageReferences: ["ecr.company.com/*"]
# attestors:
# - entries:
# - keyless:
# issuer: "https://token.actions.githubusercontent.com"
# subject: "https://github.com/myorg/*"
# attestations:
# - type: https://cosign.sigstore.dev/attestation/vuln/v1
# conditions:
# - all:
# - key: "{{ scanner }}"
# operator: Equals
# value: "trivy"Interview Tip
A junior engineer typically describes image signing as running cosign sign after a build, without connecting it to the scanning and admission control steps that make it meaningful. In an advanced interview, walk through the full chain of trust: Trivy scan produces structured results, the pipeline gates on scan policy, Cosign signs the image digest with keyless OIDC-bound identity, Cosign attest cryptographically binds the scan results to the image, and the Kubernetes admission controller verifies both the signature and the attestation content before allowing deployment. Explain why attestations matter beyond signatures: a signature proves who built the image, while an attestation proves what checks it passed. Discuss the Rekor transparency log and why tamper-evident audit trails are essential for compliance. Address failure modes: what happens when Rekor is unreachable during pod scheduling, and how break-glass mechanisms balance security with availability requirements.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────────┐ │ Scan → Sign → Attest → Verify Pipeline │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Build │──→│ Trivy │──→│ Policy │ │ │ │ Image │ │ Scan │ │ Gate │ │ │ └──────────┘ └──────────┘ └────┬─────┘ │ │ │ │ │ PASS │ FAIL │ │ ┌─────────┴────────┐ │ │ ↓ ↓ │ │ ┌──────────┐ ┌──────────┐ │ │ │ Push to │ │ Block │ │ │ │ Registry │ │ Pipeline │ │ │ └────┬─────┘ └──────────┘ │ │ │ │ │ ↓ │ │ ┌──────────┐ ┌──────────────────┐ │ │ │ Cosign │──→│ Rekor │ │ │ │ Sign │ │ Transparency Log │ │ │ └────┬─────┘ └──────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────┐ │ │ │ Cosign │ │ │ │ Attest │ │ │ │ (scan report)│ │ │ └──────┬───────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Kubernetes Admission Controller (Kyverno) │ │ │ │ │ │ │ │ ✓ Signature valid? │ │ │ │ ✓ Issuer matches CI/CD? │ │ │ │ ✓ Attestation present? │ │ │ │ ✓ Scan results pass policy? │ │ │ │ │ │ │ │ ALL PASS → Allow Pod ANY FAIL → Reject Pod │ │ │ └──────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy scanning performance at scale is optimized through client-server architecture where a persistent Trivy server caches the vulnerability database, combined with warm caching of image layers, parallel scan orchestration, selective scanning that targets only changed layers, and registry mirroring that reduces network latency for vulnerability database and image pulls.
Detailed Answer
Think of Trivy scanning optimization like optimizing a large hospital's laboratory testing process. When every patient sample must be tested independently by fetching reference databases from an external source, setting up the testing equipment, running the analysis, and tearing everything down, each test takes twenty minutes. When the lab maintains a persistent reference database, keeps equipment calibrated and ready, batches similar samples together, and only retests when the reference ranges change, throughput increases by an order of magnitude. The same principles apply to Trivy: eliminate redundant database downloads, maintain persistent infrastructure, parallelize independent work, and skip unnecessary re-analysis.
The client-server architecture is the single most impactful optimization for enterprise Trivy deployments. In standalone mode, every Trivy scan downloads the entire vulnerability database (approximately 40-50 MB compressed), decompresses it, and loads it into memory before scanning begins. For a CI/CD platform processing 500 image builds per day across services like payments-api, user-auth-service, order-processing-service, inventory-sync, and checkout-service, this means 500 redundant database downloads consuming bandwidth, time, and external API rate limits. The Trivy server deployment maintains a persistent, pre-loaded vulnerability database in memory, and Trivy clients connect to it over the network to perform scans. The server updates the database on a configurable schedule (typically every 6-12 hours), and all clients immediately benefit from the updated data without any individual download. This reduces per-scan overhead from 30-60 seconds of database initialization to sub-second client connection time.
Image layer caching provides the second major performance improvement. Container images are composed of filesystem layers, and most enterprise images share common base layers. When payments-api and order-processing-service both use the same Java 17 base image, the vulnerability analysis of the base layer packages is identical for both. Trivy can cache layer analysis results so that scanning the second image reuses the cached analysis of shared layers and only analyzes the unique application layers. In Trivy server mode, this cache is maintained centrally, benefiting all clients. For organizations with standardized base images, layer caching reduces scan time for application images by 60-80 percent because the base layer analysis, which typically contains the majority of OS packages, is already cached. The cache key is the layer digest, so any change to a layer invalidates its cached analysis and triggers a fresh scan.
Parallel scan orchestration addresses throughput requirements for organizations that need to scan hundreds of images within tight CI/CD time windows. Rather than scanning images sequentially, the scanning infrastructure distributes scans across multiple Trivy server replicas behind a load balancer. Each CI/CD pipeline job sends its scan request to the Trivy service endpoint, and the load balancer routes it to an available server replica. Kubernetes Horizontal Pod Autoscaler scales the Trivy server deployment based on CPU utilization or custom metrics like scan queue depth, adding replicas during peak build periods and scaling down during off-hours. For organizations using the Trivy Operator for cluster scanning, the operator's scanJobsConcurrentLimit parameter controls how many simultaneous scan jobs run in the cluster, preventing resource contention during mass rescanning events like base image updates that affect services across multiple namespaces.
Advanced optimization techniques include registry mirroring, selective scanning, and database pre-warming. Registry mirroring deploys a pull-through cache for both the vulnerability database sources and the container images being scanned, reducing external network dependencies and latency. Selective scanning uses Trivy's ability to scan specific artifact types, skipping secret scanning or license scanning when only vulnerability data is needed, reducing per-scan computation time. Database pre-warming ensures the Trivy server has the latest vulnerability database loaded before the morning CI/CD rush begins by scheduling database updates during off-peak hours. For air-gapped environments common in financial services and government organizations, the vulnerability database is pre-downloaded to a local OCI registry using oras, and Trivy servers pull from this internal source, eliminating any external network dependency during scanning while maintaining up-to-date vulnerability data through scheduled synchronization jobs.
Code Example
# Deploy Trivy in client-server mode for centralized caching
# Server deployment with persistent vulnerability DB cache
helm install trivy-server aqua/trivy \
--namespace trivy-system \
--set trivy.mode=server \
--set trivy.persistence.enabled=true \
--set trivy.persistence.size=10Gi \
--set trivy.resources.requests.memory=2Gi \
--set trivy.resources.requests.cpu=500m \
--set trivy.dbUpdateInterval=12h \
--set replicaCount=3
# Create a Service for client access
kubectl expose deployment trivy-server \
--port=4954 --target-port=4954 \
--name=trivy-server-svc \
-n trivy-system
# Configure HPA for auto-scaling during peak scan periods
kubectl autoscale deployment trivy-server \
-n trivy-system \
--min=2 --max=8 \
--cpu-percent=70
# Client scan using the remote server (no local DB download)
trivy image --server http://trivy-server-svc.trivy-system:4954 \
--severity CRITICAL,HIGH \
--format json \
ecr.company.com/payments-api:${GIT_SHA}
# Benchmark: standalone vs client-server scan times
time trivy image --skip-db-update=false ecr.company.com/payments-api:v4.2.0
# Standalone: real 0m47.3s (includes 32s DB download)
time trivy image --server http://trivy-server-svc.trivy-system:4954 ecr.company.com/payments-api:v4.2.0
# Client-server: real 0m8.1s (DB already cached on server)
# Pre-warm vulnerability database during off-peak hours
# CronJob runs at 4 AM to update DB before morning CI/CD rush
# kubectl apply -f trivy-db-update-cronjob.yaml
trivy image --download-db-only --db-repository ghcr.io/aquasecurity/trivy-db
# Air-gapped environment: mirror vulnerability DB to internal registry
oras pull ghcr.io/aquasecurity/trivy-db:2 -o /tmp/trivy-db
# Push DB to internal OCI registry for air-gapped access
oras push registry.internal.company.com/security/trivy-db:2 /tmp/trivy-db/db.tar.gz
# Configure Trivy to use internal DB source
trivy image --db-repository registry.internal.company.com/security/trivy-db \
ecr.company.com/checkout-service:v2.1.0
# Selective scanning: skip license and secret checks for faster vuln-only scans
trivy image --scanners vuln \
--server http://trivy-server-svc.trivy-system:4954 \
ecr.company.com/inventory-sync:v1.8.0
# Parallel scan orchestration in CI/CD (scan multiple images concurrently)
for service in payments-api order-processing-service checkout-service inventory-sync; do
# Launch each scan as a background process against the shared server
trivy image --server http://trivy-server-svc.trivy-system:4954 \
--format json --output "results-${service}.json" \
"ecr.company.com/${service}:${GIT_SHA}" &
done
# Wait for all parallel scans to complete
waitInterview Tip
A junior engineer typically mentions caching the vulnerability database without explaining the client-server architecture that makes it effective at scale. In an advanced interview, quantify the performance difference: standalone scans spend 30-60 seconds downloading and loading the database, while client-server scans connect in under a second because the server maintains the database in memory. Discuss layer caching and why shared base images across services like payments-api and order-processing-service make this particularly effective, reducing scan times by 60-80 percent for images sharing common base layers. Explain auto-scaling the Trivy server deployment with HPA to handle peak CI/CD load. Address air-gapped environments where the vulnerability database must be mirrored to an internal OCI registry. Demonstrate understanding of selective scanning: scanning only for vulnerabilities when secret and license checks are handled elsewhere reduces computation time per scan.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────────┐ │ Trivy Client-Server Architecture │ │ │ │ CI/CD Pipelines (Clients) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │payments │ │order │ │checkout │ │inventory │ │ │ │-api │ │-processing│ │-service │ │-sync │ │ │ │pipeline │ │pipeline │ │pipeline │ │pipeline │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ │ └─────────────┴──────┬──────┴─────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────┐ │ │ │ Load Balancer │ │ │ └──────────┬───────────┘ │ │ │ │ │ ┌─────────────┼─────────────┐ │ │ ↓ ↓ ↓ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Trivy Server │ │ Trivy Server │ │ Trivy Server │ │ │ │ Replica 1 │ │ Replica 2 │ │ Replica 3 │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ Vuln DB │ │ │ │ Vuln DB │ │ │ │ Vuln DB │ │ │ │ │ │ (cached) │ │ │ │ (cached) │ │ │ │ (cached) │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ Layer │ │ │ │ Layer │ │ │ │ Layer │ │ │ │ │ │ Cache │ │ │ │ Cache │ │ │ │ Cache │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ HPA: 2-8 replicas │ │ Scale on CPU > 70% │ └──────────────────────────────────────────────────────────────┘ │ Standalone: 47s/scan │ Client-Server: 8s/scan │
💬 Comments
Quick Answer
Trivy's plugin system allows teams to build custom scanners, output formatters, and integration modules that extend Trivy's built-in capabilities. Plugins are distributed as OCI artifacts or Git repositories, installed via trivy plugin install, and invoked as subcommands that receive scan context and produce findings in Trivy's standard format.
Detailed Answer
Think of Trivy plugins like specialized attachments for a power drill. The drill itself handles the core mechanics of rotation and torque, but different jobs require different bits: a spade bit for rough holes in wood, a masonry bit for concrete, a step bit for sheet metal. Each bit is designed by a specialist who understands the specific material, and the drill's universal chuck accepts any standard bit without modification. Trivy's plugin architecture follows the same model: the core scanner handles image layer analysis, dependency parsing, and vulnerability database management, while plugins add specialized detection capabilities, custom output formats, or integrations with proprietary systems that the core scanner does not support.
Trivy plugins are executable programs that conform to a defined interface. A plugin receives input through command-line arguments and environment variables, performs its specialized analysis, and returns results in a structured format. The plugin manifest file (plugin.yaml) declares the plugin's name, version, supported platforms, installation source, and the executable entry point. Plugins can be written in any language: Go for performance-critical scanning logic, Python for rapid prototyping and API integrations, or shell scripts for simple orchestration tasks. For enterprise teams running services like payments-api, user-auth-service, and checkout-service, custom plugins typically address organization-specific requirements that open-source scanners do not cover: proprietary dependency formats, internal compliance rule sets, integration with in-house vulnerability databases, or custom reporting formats required by the security operations center.
A common plugin use case is extending Trivy's misconfiguration scanning with organization-specific policies. While Trivy's built-in checks cover CIS benchmarks and common Kubernetes security best practices, every organization has additional requirements. A financial services company may require that all Deployment manifests include specific labels for cost allocation and regulatory mapping, that all containers specify both resource requests and limits within approved ranges, that all pods reference images from the approved internal registry, and that no service account tokens are auto-mounted unless explicitly justified. A custom plugin implements these checks using Rego policies (the same language used by OPA) or custom Go code, producing findings in Trivy's standard format so they appear alongside built-in findings in vulnerability reports and dashboards. The plugin is distributed through the organization's internal OCI registry, and the CI/CD pipeline installs it before scanning.
Custom output plugins transform Trivy's scan results into formats required by downstream systems. The default output formats (table, JSON, SARIF, CycloneDX) cover most standard integrations, but enterprise environments often need proprietary formats for their specific SIEM, GRC platform, or vulnerability management system. An output plugin for ServiceNow might transform Trivy's JSON findings into ServiceNow vulnerability response format and push them directly to the ServiceNow API, creating or updating vulnerability records with the correct assignment group, priority, and SLA based on the finding severity and the affected service's criticality tier. For organizations running order-processing-service and settlement-processor in regulated environments, the plugin might also generate evidence artifacts in the format required by specific compliance frameworks like PCI-DSS or SOX.
The development and distribution lifecycle for Trivy plugins follows software engineering best practices. Plugins are developed in dedicated repositories with their own CI/CD pipelines that run tests, build platform-specific binaries, and publish them as OCI artifacts to the organization's container registry. Version management follows semantic versioning so that consuming pipelines can pin to specific plugin versions for reproducibility. The plugin installation is declarative in the CI/CD pipeline configuration, ensuring that every scan uses the expected plugin version. For air-gapped environments, plugins are pre-installed into custom Trivy container images that include all required plugins and their dependencies, eliminating runtime installation steps. Enterprise teams maintain an internal plugin catalog documenting available plugins, their purposes, configuration options, and ownership, treating plugins as shared infrastructure components with the same operational expectations as any other production service.
Code Example
# Install a Trivy plugin from an OCI registry
trivy plugin install oci://registry.company.com/trivy-plugins/compliance-checker:v1.2.0
# Install a plugin from a Git repository
trivy plugin install github.com/myorg/trivy-plugin-custom-policies
# List installed plugins to verify installation
trivy plugin list
# Run the custom plugin as a Trivy subcommand
trivy compliance-checker --policy-dir /policies/financial-services \
ecr.company.com/payments-api:v4.2.0
# Plugin manifest file (plugin.yaml) for a custom compliance checker
# name: compliance-checker
# version: 1.2.0
# repository: registry.company.com/trivy-plugins/compliance-checker
# platforms:
# - selector:
# os: linux
# arch: amd64
# uri: https://registry.company.com/trivy-plugins/compliance-checker/v1.2.0/linux-amd64.tar.gz
# bin: compliance-checker
# Example: custom Rego policy for organization-specific checks
# File: policies/required-labels.rego
# package custom.kubernetes.required_labels
#
# deny[msg] {
# input.kind == "Deployment"
# not input.metadata.labels["app.company.com/cost-center"]
# msg := sprintf("Deployment %s missing required cost-center label", [input.metadata.name])
# }
# Run Trivy misconfiguration scan with custom Rego policies
trivy config --policy-namespaces custom \
--config-policy /policies \
--format json \
./kubernetes/deployments/
# Build a custom Trivy image with pre-installed plugins for air-gapped use
# Dockerfile.trivy-custom
# FROM aquasec/trivy:latest
# RUN trivy plugin install github.com/myorg/trivy-plugin-custom-policies
# RUN trivy plugin install github.com/myorg/trivy-plugin-servicenow-output
# RUN trivy image --download-db-only
docker build -t registry.company.com/trivy-custom:v1.0.0 -f Dockerfile.trivy-custom .
# Push custom Trivy image for CI/CD pipeline consumption
docker push registry.company.com/trivy-custom:v1.0.0
# CI/CD usage with custom Trivy image including all plugins
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
registry.company.com/trivy-custom:v1.0.0 \
image --severity CRITICAL,HIGH \
ecr.company.com/order-processing-service:${GIT_SHA}Interview Tip
A junior engineer typically uses Trivy's built-in scanning capabilities without recognizing when custom extensions are needed or how to build them. In an advanced interview, explain the plugin architecture: plugins are standalone executables with a manifest file that declare platform support, version, and entry points. Describe concrete use cases: organization-specific compliance policies as Rego rules that check for required labels, resource limit ranges, and approved image registries. Discuss custom output plugins that transform Trivy findings into formats consumed by enterprise SIEM or GRC platforms like ServiceNow. Address the distribution model: plugins published as OCI artifacts to internal registries with semantic versioning for pipeline reproducibility. For air-gapped environments, explain how custom Trivy images with pre-installed plugins eliminate runtime installation dependencies. Strong candidates demonstrate that they think of Trivy as an extensible platform rather than a fixed-function tool.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────┐ │ Trivy Plugin Architecture │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Trivy Core Engine │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │ │ │ │ │ Image │ │ Filesystem │ │ Config/IaC │ │ │ │ │ │ Scanner │ │ Scanner │ │ Scanner │ │ │ │ │ └────────────┘ └────────────┘ └────────────────┘ │ │ │ └──────────────────────┬───────────────────────────┘ │ │ │ │ │ Plugin Interface │ │ │ │ │ ┌───────────────┼───────────────┐ │ │ ↓ ↓ ↓ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Custom │ │ ServiceNow │ │ Internal │ │ │ │ Compliance │ │ Output │ │ Vuln DB │ │ │ │ Checker │ │ Plugin │ │ Plugin │ │ │ │ │ │ │ │ │ │ │ │ ● Rego │ │ ● Format │ │ ● Enrich │ │ │ │ policies │ │ transform │ │ with │ │ │ │ ● Labels │ │ ● API push │ │ internal │ │ │ │ ● Limits │ │ ● Ticket │ │ threat │ │ │ │ ● Registry │ │ creation │ │ intel │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ Distribution: │ │ ┌──────────────────────────────────────────────────┐ │ │ │ OCI Registry → trivy plugin install oci://... │ │ │ │ Git Repo → trivy plugin install github://... │ │ │ │ Air-gapped → Pre-installed in custom image │ │ │ └──────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
Trivy integrates with Kubernetes admission controllers through webhook-based systems like Kyverno and OPA Gatekeeper that intercept pod creation requests and verify that container images have passed Trivy scans. This creates a runtime enforcement gate that prevents unscanned or vulnerable images from running in production clusters, complementing CI/CD pipeline scanning with deploy-time verification.
Detailed Answer
Think of admission controllers as airport security checkpoints. A passenger may have passed a background check when booking the ticket (CI/CD scanning) and verified their identity at check-in (image signing), but the security checkpoint at the gate provides a final verification before boarding. Even if the booking system had a glitch that let someone through without a background check, the gate checkpoint catches it. Similarly, CI/CD pipeline scanning can be bypassed through emergency deployments, manual kubectl commands, or misconfigured pipelines. Admission controllers provide a non-bypassable enforcement point within Kubernetes itself, ensuring that every pod creation request meets security requirements regardless of how it was submitted.
The integration architecture places Trivy scan results into the admission decision flow through two primary patterns. The first pattern is pre-scan verification, where the admission controller checks whether the image has an existing Trivy scan result stored as an OCI attestation, a Kubernetes ConfigMap, or a record in an external vulnerability management database. When a deployment request for payments-api arrives, the admission webhook extracts the image reference, queries the scan result store, and verifies that a recent scan exists with acceptable findings. If no scan result exists or the scan is older than the configured maximum age, the admission request is rejected with a message directing the team to run their image through the scanning pipeline. This pattern avoids scanning during admission, which would add latency to pod scheduling.
The second pattern is inline scanning, where the admission controller triggers a Trivy scan during the admission webhook processing. When a pod creation request arrives for a new image of checkout-service, the webhook calls a Trivy server to scan the image in real time, evaluates the results against the configured policy, and admits or rejects the pod based on the findings. This pattern provides the strongest guarantee because every image is scanned at deploy time with the latest vulnerability database, but it adds 5-15 seconds of latency to pod scheduling and creates a dependency on the Trivy server's availability. If the Trivy server is down, the admission controller must either fail-open (allowing potentially vulnerable pods) or fail-closed (blocking all pod creation), neither of which is ideal. Enterprise teams typically configure a timeout-based fallback where inline scanning is attempted, and if it does not complete within the timeout, the controller falls back to checking for pre-computed scan attestations.
Kyverno provides the most mature integration with Trivy through its verifyImages rules, which combine image signature verification with attestation validation. A ClusterPolicy can require that every pod in production namespaces references an image that has a valid Cosign signature from the CI/CD pipeline and a vulnerability scan attestation where the critical CVE count equals zero. The policy applies to init containers, sidecar containers, and ephemeral debug containers, not just the primary application container. For services like order-processing-service, inventory-sync, and notification-gateway, the policy can include namespace-specific exceptions: development namespaces may allow images with high-severity CVEs for debugging, while production namespaces enforce strict zero-critical policies. Kyverno's audit mode allows teams to deploy policies in logging-only mode first, identifying all violations across the cluster before switching to enforcement mode.
Operational considerations for production admission controller deployments center on availability, performance, and emergency access. The admission webhook is in the critical path of every pod creation in the cluster, so its availability directly impacts the platform's ability to schedule workloads. Enterprise deployments run admission controller replicas across multiple availability zones with pod anti-affinity rules, configure appropriate resource requests and limits, and set failurePolicy to Ignore for non-critical namespaces while keeping it at Fail for production namespaces. Performance optimization includes caching verification results for recently verified image digests, batching signature verification requests to the registry, and setting appropriate webhook timeout values. Emergency break-glass procedures allow designated platform engineers to temporarily exempt specific namespaces or workloads from admission checks during incident response, with all exemptions logged and automatically expired after a configured duration.
Code Example
# Kyverno ClusterPolicy: enforce Trivy scan results via admission control
# Apply policy to require scanned images in production namespaces
cat <<'EOF' | kubectl apply -f -
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-trivy-scan
annotations:
policies.kyverno.io/title: Require Trivy Vulnerability Scan
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 15
background: false
rules:
- name: verify-vulnerability-scan
match:
any:
- resources:
kinds: ["Pod"]
namespaces:
- payments
- orders
- checkout
- settlements
verifyImages:
- imageReferences:
- "ecr.company.com/*"
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/*"
rekor:
url: https://rekor.sigstore.dev
attestations:
- type: https://cosign.sigstore.dev/attestation/vuln/v1
conditions:
- all:
- key: "{{ scanner }}"
operator: Equals
value: "trivy"
EOF
# Test: deploy an unscanned image — should be rejected
kubectl run test-unscanned --image=ecr.company.com/payments-api:unscanned -n payments
# Error from server: admission webhook denied the request: image verification failed
# Test: deploy a properly scanned and signed image — should succeed
kubectl run test-scanned --image=ecr.company.com/payments-api:v4.2.0 -n payments
# pod/test-scanned created
# Configure audit mode for gradual rollout in new namespaces
kubectl annotate clusterpolicy require-trivy-scan \
policies.kyverno.io/validationFailureAction=Audit --overwrite
# View policy violations without blocking deployments
kubectl get policyreport -A -o custom-columns='NAMESPACE:.metadata.namespace,PASS:.summary.pass,FAIL:.summary.fail,WARN:.summary.warn'
# Emergency break-glass: temporarily exempt a namespace during incidents
kubectl label namespace settlements kyverno.io/policy-exclude=emergency-bypass
# Ensure bypass is time-limited and audited
kubectl annotate namespace settlements \
bypass-expiry="2026-06-26T18:00:00Z" \
bypass-approver="[email protected]" \
bypass-incident="INC-2847"
# Kyverno metrics for monitoring admission decisions
# kyverno_admission_requests_total{policy="require-trivy-scan",result="pass"}
# kyverno_admission_requests_total{policy="require-trivy-scan",result="fail"}Interview Tip
A junior engineer typically describes admission controllers as simply blocking unsigned images, without addressing the two integration patterns, performance implications, or operational failure modes. In an advanced interview, compare the pre-scan verification pattern (checking for existing attestations) with the inline scanning pattern (triggering Trivy during admission), explaining the latency and availability trade-offs of each. Discuss why admission control is necessary even when CI/CD scanning exists: pipelines can be bypassed through kubectl, emergency deployments, or misconfiguration. Walk through a Kyverno verifyImages policy that validates both signatures and scan attestation content. Address the critical operational concern: the admission webhook is in the pod scheduling critical path, so its unavailability blocks workload scheduling. Explain break-glass procedures for emergency access and why failurePolicy configuration differs between production and development namespaces.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────────┐ │ Admission Controller Security Gating │ │ │ │ ┌──────────────┐ │ │ │ kubectl apply│ │ │ │ Deployment │ │ │ └──────┬───────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Kubernetes API Server │ │ │ │ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ Admission Webhook (Kyverno) │ │ │ │ │ │ │ │ │ │ │ │ Pod: payments-api:v4.2.0 │ │ │ │ │ │ │ │ │ │ │ │ Step 1: Extract image reference │ │ │ │ │ │ ↓ │ │ │ │ │ │ Step 2: Query registry for signature │ │ │ │ │ │ ↓ │ │ │ │ │ │ Step 3: Verify Cosign signature ✓ or ✗ │ │ │ │ │ │ ↓ │ │ │ │ │ │ Step 4: Verify scan attestation ✓ or ✗ │ │ │ │ │ │ ↓ │ │ │ │ │ │ Step 5: Check attestation content ✓ or ✗ │ │ │ │ │ │ (critical CVEs == 0?) │ │ │ │ │ └──────────┬────────────────────┬────────────────┘ │ │ │ │ │ │ │ │ │ └─────────────┼────────────────────┼───────────────────┘ │ │ ALL ✓│ ANY ✗│ │ │ ↓ ↓ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Pod Scheduled │ │ Pod Rejected │ │ │ │ ● payments-api │ │ ● Error message │ │ │ │ ● Runs in cluster│ │ ● Team notified │ │ │ └──────────────────┘ └──────────────────┘ │ └──────────────────────────────────────────────────────────────┘
💬 Comments
Quick Answer
Correlating Trivy's static vulnerability findings with runtime security data from tools like Falco, eBPF-based monitors, and network policy engines creates a prioritization system that distinguishes between theoretical vulnerabilities and actively exploitable ones. This correlation identifies which vulnerable packages are actually loaded in memory, exposed to network traffic, or exhibiting suspicious runtime behavior.
Detailed Answer
Think of this correlation like a building security assessment. A structural engineer's report might identify that certain windows use glass rated for lower impact resistance than recommended, that a fire exit door has a lock mechanism with a known bypass technique, and that the elevator control panel uses outdated firmware. These are all valid findings, but the security team needs to know which ones represent actual risk right now. If the vulnerable windows are on the 15th floor facing a private courtyard with no adjacent buildings, the risk is minimal. If the fire exit with the bypass-able lock is the one that opens to the public parking garage, that is a priority. Runtime correlation provides this context for container security: which of the many CVEs that Trivy reports are actually reachable, loaded, and exposed in the running environment.
The first correlation dimension is package reachability: determining whether vulnerable packages detected by Trivy are actually loaded and executing in the running container. Trivy's static scan reports every CVE in every installed package, but many packages are present in the filesystem without being used at runtime. An eBPF-based runtime agent like Falco, Tetragon, or a commercial runtime security tool monitors system calls, library loads, and process execution within each container. By comparing the list of packages flagged by Trivy against the list of libraries actually loaded by the running process, teams can identify that payments-api has 47 CVEs across all installed packages but only 12 of those packages are actually loaded into the Java process's address space. The remaining 35 CVEs exist in packages that are present in the image filesystem but never executed, dramatically reducing the actionable remediation scope.
The second correlation dimension is network exposure. A vulnerability in a network-facing library is far more dangerous than the same vulnerability in a library used for local file processing. Network policy data from Kubernetes NetworkPolicy resources, service mesh telemetry from Istio or Linkerd, and cloud security group configurations reveal which services accept inbound connections from the internet, from other internal services, or from no external sources at all. When Trivy reports a critical CVE in the HTTP request parsing library used by checkout-service, and network telemetry confirms that checkout-service receives traffic directly from the internet-facing load balancer, this combination creates a P1 remediation priority. The same CVE in inventory-sync, which only communicates with an internal message queue and accepts no inbound HTTP connections, receives a lower priority because the vulnerable code path is not reachable from the network attack surface.
The third correlation dimension is behavioral anomaly detection. Runtime security tools establish behavioral baselines for each workload: what processes normally run, what files are accessed, what network connections are made, and what system calls are invoked. When a container exhibits behavior outside its baseline, specifically behavior that correlates with exploitation of a known vulnerability, the alert priority escalates significantly. If Trivy reports a remote code execution CVE in a logging library used by order-processing-service, and Falco simultaneously detects that order-processing-service spawned an unexpected shell process and made an outbound connection to an unknown IP address, the correlation between the known vulnerability and the anomalous behavior strongly suggests active exploitation. This correlation transforms what might be a routine vulnerability finding into an active incident requiring immediate response.
Building the correlation pipeline requires a centralized security data lake that ingests findings from multiple sources. Trivy scan results, Trivy Operator VulnerabilityReports, Falco alerts, network flow logs, eBPF runtime profiles, and Kubernetes audit logs are all ingested into a SIEM or security analytics platform. Correlation rules match vulnerability identifiers across data sources, enriching static findings with runtime context. The output is a risk-scored vulnerability list where each finding includes its static CVSS score, its runtime reachability status, its network exposure level, and any associated behavioral alerts. Engineering teams receive remediation tickets that are pre-prioritized by actual risk rather than theoretical severity, ensuring that the most dangerous vulnerabilities are addressed first. For organizations running hundreds of microservices like settlement-processor, notification-gateway, user-auth-service, and fraud-detection-engine, this correlation reduces the actionable critical vulnerability count by 60-80 percent while ensuring that the remaining findings represent genuine, exploitable risk that demands immediate attention.
Code Example
# Step 1: Export Trivy findings for correlation
# Scan all production images and output structured JSON
trivy image --format json \
--output /data/trivy/payments-api-findings.json \
ecr.company.com/payments-api:production
# Extract vulnerable package names for runtime correlation
cat /data/trivy/payments-api-findings.json \
| jq -r '[.Results[].Vulnerabilities[] | {pkg: .PkgName, cve: .VulnerabilityID, severity: .Severity}]' \
> /data/trivy/payments-api-vuln-packages.json
# Step 2: Capture runtime loaded libraries via eBPF tracing
# Use bpftrace to log shared library loads in the payments-api container
bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2:_dl_open { printf("loaded: %s\n", str(arg0)); }' \
-p $(pgrep -f payments-api) > /data/runtime/payments-api-loaded-libs.txt
# Step 3: Correlate Trivy findings with runtime data
# Python script to cross-reference static findings with loaded libraries
python3 -c "
import json
# Load Trivy vulnerability findings
with open('/data/trivy/payments-api-vuln-packages.json') as f:
vulns = json.load(f)
# Load runtime-observed libraries
with open('/data/runtime/payments-api-loaded-libs.txt') as f:
loaded = set(line.strip() for line in f)
# Classify each vulnerability by runtime reachability
for v in vulns:
v['runtime_loaded'] = any(v['pkg'] in lib for lib in loaded)
v['priority'] = 'P1' if v['runtime_loaded'] and v['severity'] == 'CRITICAL' else 'P2' if v['runtime_loaded'] else 'P3'
print(json.dumps([v for v in vulns if v['runtime_loaded']], indent=2))
"
# Step 4: Query Falco alerts for behavioral anomalies in vulnerable services
kubectl logs -n falco -l app=falco --since=24h \
| grep -E 'payments-api|checkout-service|order-processing' \
| grep -E 'shell_spawn|unexpected_outbound|file_open_sensitive'
# Step 5: Combine network exposure data from Kubernetes
kubectl get networkpolicies -n payments -o json \
| jq '.items[] | {name: .metadata.name, ingress: .spec.ingress}'
# Step 6: Enriched vulnerability report with runtime context
# Output: prioritized findings combining static + runtime signals
# {
# "service": "payments-api",
# "cve": "CVE-2024-50001",
# "severity": "CRITICAL",
# "package": "libssl3",
# "runtime_loaded": true,
# "network_exposed": true,
# "falco_alerts": 0,
# "composite_priority": "P1",
# "remediation_sla": "24 hours"
# }
# Step 7: Prometheus metrics for correlation dashboard
# trivy_runtime_correlated_vulns{service="payments-api",priority="P1"} 3
# trivy_runtime_correlated_vulns{service="payments-api",priority="P2"} 9
# trivy_runtime_correlated_vulns{service="payments-api",priority="P3"} 35Interview Tip
A junior engineer typically treats all Trivy findings as equally important based solely on CVSS score, without considering whether the vulnerability is actually exploitable in the running environment. In an advanced interview, explain the three correlation dimensions: package reachability (is the vulnerable package loaded in the running process), network exposure (is the service reachable from the attack surface), and behavioral anomaly detection (is there evidence of active exploitation). Walk through a concrete example where Trivy reports 47 CVEs in payments-api but runtime correlation reduces the P1 count to 3 because only 12 packages are actually loaded and only 3 of those are in network-exposed code paths. Discuss the tooling stack: Trivy for static findings, eBPF agents or Falco for runtime observability, network policy data for exposure assessment, and a SIEM or security data lake for correlation. Address the 60-80 percent noise reduction that runtime correlation provides, which prevents alert fatigue and focuses engineering effort on genuinely exploitable vulnerabilities.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────────┐ │ Static + Runtime Vulnerability Correlation │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Trivy │ │ eBPF/Falco │ │ Network │ │ │ │ Static Scan │ │ Runtime │ │ Policy │ │ │ │ │ │ Monitor │ │ Data │ │ │ │ 47 CVEs │ │ 12 libs │ │ 3 exposed │ │ │ │ found │ │ loaded │ │ services │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ └─────────────────┴─────────────────┘ │ │ │ │ │ ↓ │ │ ┌────────────────────────┐ │ │ │ Correlation Engine │ │ │ │ (Security Data Lake) │ │ │ └────────────┬───────────┘ │ │ │ │ │ ┌────────────┴───────────┐ │ │ │ Risk-Scored Output │ │ │ │ │ │ │ │ P1: 3 CVEs │ │ │ │ ● Runtime loaded │ │ │ │ ● Network exposed │ │ │ │ ● CRITICAL severity │ │ │ │ │ │ │ │ P2: 9 CVEs │ │ │ │ ● Runtime loaded │ │ │ │ ● Not network exposed │ │ │ │ │ │ │ │ P3: 35 CVEs │ │ │ │ ● Not runtime loaded │ │ │ │ ● Filesystem only │ │ │ └────────────────────────┘ │ │ │ │ 47 total CVEs → 3 actionable P1s (93% noise reduction) │ └──────────────────────────────────────────────────────────────┘
💬 Comments
Context
Netflix deploys over 1,000 container images daily across their microservices architecture serving 260 million subscribers. A critical vulnerability in a base image went undetected for 3 weeks, prompting an urgent initiative to implement automated vulnerability scanning at every stage of their image lifecycle.
Problem
Netflix's container ecosystem had grown to over 4,000 unique container images, with teams building from a mix of official base images, internally maintained golden images, and occasionally third-party images pulled directly from Docker Hub. There was no centralized scanning process, and individual teams were responsible for their own security practices, which varied widely. Some teams ran occasional Clair scans manually before releases, but most teams had no scanning at all. The incident that triggered the initiative involved a critical OpenSSL vulnerability (CVE-2023-0286) present in an Alpine base image used by 340 services. The vulnerability allowed remote code execution and went undetected for 21 days because no automated scanning was in place. When the vulnerability was eventually discovered through an external security advisory, the remediation effort required a dedicated war room with 15 engineers spending 4 days identifying all affected images, determining which services were exposed, building patched images, and coordinating deployments. The lack of a Software Bill of Materials (SBOM) for images meant that identifying vulnerable dependencies required running manual scans against each image individually. Additionally, the existing Clair installation was running an outdated vulnerability database because the update process had silently failed 2 months prior, meaning even the teams that were scanning were getting incomplete results.
Solution
Netflix implemented Trivy as their standard container image scanner, integrating it at three critical points in their image lifecycle: build time in CI, registry admission, and runtime in production Kubernetes clusters. At build time, they added a Trivy scan step to their Spinnaker-based CI pipeline that ran immediately after docker build completed. The scan was configured to fail the build if any critical or high-severity vulnerabilities were detected, with an allowlist mechanism for known false positives or vulnerabilities with accepted risk documented through their security exception process. They configured Trivy with --severity CRITICAL,HIGH --exit-code 1 to enforce the quality gate and --format json for machine-readable output that was ingested into their security data lake for trend analysis. For base images, they set up a nightly Trivy scan job that checked all golden images in their internal registry and automatically created Jira tickets when new vulnerabilities were discovered, assigning them to the base image maintenance team. They deployed Trivy as an admission webhook in their Kubernetes clusters using the Trivy Operator, which prevented any unscanned or non-compliant image from being deployed. The operator also performed continuous scanning of running workloads, detecting newly published vulnerabilities in already-deployed images and creating VulnerabilityReport custom resources that fed into their security dashboard. For SBOM generation, they configured Trivy to produce CycloneDX SBOMs during the CI scan phase, storing them alongside the image in their OCI registry as attestations. This enabled rapid impact assessment when new CVEs were published because they could query the SBOM database to identify affected images within minutes rather than days. The team also implemented trivy image --ignore-unfixed to separate actionable vulnerabilities from those without available patches, reducing alert fatigue significantly.
Commands
trivy image --severity CRITICAL,HIGH --exit-code 1 --format json -o scan-results.json registry.netflix.internal/payments:v2.3.0 # CI scan with quality gate
trivy image --format cyclonedx -o sbom.json registry.netflix.internal/payments:v2.3.0 # Generate CycloneDX SBOM
trivy image --ignore-unfixed --severity CRITICAL registry.netflix.internal/payments:v2.3.0 # Show only fixable critical vulns
trivy image --list-all-pkgs --format json registry.netflix.internal/payments:v2.3.0 # Full package inventory for audit
kubectl get vulnerabilityreports -A -o json | jq '.items[] | select(.report.summary.criticalCount > 0)' # Find critical vulns in cluster
trivy image --db-repository registry.netflix.internal/trivy-db --skip-update registry.netflix.internal/payments:v2.3.0 # Air-gapped scan using mirrored DB
Outcome
Mean time to detect image vulnerabilities decreased from 21 days to under 5 minutes. The percentage of production images with known critical vulnerabilities dropped from 34% to 0.8% within 3 months. SBOM-based impact assessment reduced CVE response time from 4 days to 2 hours.
Lessons Learned
Implementing Trivy scanning without an allowlist mechanism and exception process will quickly lead to developer frustration and pipeline workarounds. The key is to make the secure path the easiest path by providing pre-scanned, approved base images that teams can build upon. Continuous runtime scanning is essential because a clean image at build time can become vulnerable when new CVEs are published days or weeks after deployment.
◈ Architecture Diagram
┌────────────────────────────────────────────────────────┐
│ CI/CD Pipeline │
│ ┌──────────┐ ┌───────────┐ ┌────────────────────┐ │
│ │ Build │→ │ Trivy │→ │ Push to Registry │ │
│ │ Image │ │ Scan │ │ + SBOM Attestation│ │
│ │ │ │ CRIT/HIGH│ │ │ │
│ │ │ │ Gate ✓/✗ │ │ │ │
│ └──────────┘ └───────────┘ └────────┬───────────┘ │
└───────────────────────────────────────┼────────────────┘
▼
┌────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ ┌──────────────────────┐ ┌────────────────────────┐ │
│ │ Admission Webhook │ │ Trivy Operator │ │
│ │ Block unscanned │ │ Continuous scanning │ │
│ │ images ✗ │ │ VulnerabilityReports │ │
│ └──────────────────────┘ └────────────┬───────────┘ │
└────────────────────────────────────────┼────────────────┘
▼
┌────────────────────────────────────────────────────────┐
│ Security Dashboard │
│ Critical: 2 │ High: 14 │ Medium: 89 │ Low: 234 │
│ SBOM Query: Which images use openssl < 3.0.8? │
│ → 3 images found, auto-tickets created ✓ │
└────────────────────────────────────────────────────────┘💬 Comments
Context
Robinhood's infrastructure team manages 2,500+ Terraform resources across 40 AWS accounts handling financial transactions for 23 million users. After a misconfigured S3 bucket policy temporarily exposed internal API documentation, the security team mandated automated IaC scanning before any Terraform plan could be applied.
Problem
Robinhood's Terraform codebase had grown to over 150,000 lines of HCL across 180 modules, maintained by 12 different teams. Security reviews of Terraform changes were performed manually by a 4-person security team who reviewed pull requests, but the volume of changes (30-40 PRs per day) made thorough review impossible. The security team estimated they could meaningfully review only 15% of infrastructure changes, relying on automated checks that were limited to basic linting and formatting. The S3 incident exposed a systemic problem: a developer had written a bucket policy using a wildcard principal to enable cross-account access, which inadvertently allowed public access because the policy did not include a condition restricting the source account. This pattern existed in 23 other Terraform modules that had passed security review because the reviewers focused on obvious misconfigurations rather than subtle policy logic errors. Beyond S3, the team discovered through ad-hoc scanning that their Terraform codebase contained 47 security groups with overly permissive ingress rules including 0.0.0.0/0 on non-standard ports, 12 RDS instances configured without encryption at rest, 8 Lambda functions with wildcard IAM permissions, and 15 CloudFront distributions without WAF associations. The existing pre-commit hooks only checked HCL formatting and variable naming conventions, providing no security value. The team evaluated several IaC scanning tools and chose Trivy because it supported multiple IaC formats and could be integrated into their existing GitHub Actions workflows without requiring a separate SaaS platform.
Solution
Robinhood integrated Trivy's IaC misconfiguration scanning into three layers of their development workflow. First, they provided developers with a pre-commit hook running trivy config on changed Terraform files, giving immediate local feedback before code reached the CI pipeline. Second, they added a GitHub Actions workflow that ran trivy config on every pull request targeting Terraform modules, posting scan results as PR comments with inline annotations showing exactly which lines contained misconfigurations. The workflow was configured with custom severity thresholds: CRITICAL and HIGH misconfigurations blocked the PR from merging, while MEDIUM findings were reported as warnings that required acknowledgment. Third, they implemented a nightly full-codebase scan that checked all Terraform modules against the latest Trivy rules, catching issues in code that had not been modified recently but contained newly identified misconfiguration patterns. For custom policies specific to Robinhood's security requirements, they wrote Rego policies that Trivy evaluated alongside its built-in checks. These custom policies enforced Robinhood-specific rules such as requiring specific tag structures for SOC 2 compliance, mandating VPC flow logs on all VPCs, requiring CloudTrail to be enabled in all accounts, and prohibiting public subnets in production accounts. They also configured Trivy to scan their Terraform plan JSON output (terraform show -json tfplan) rather than just the static HCL, which caught misconfigurations that only manifested after variable interpolation and module composition. The team created a .trivyignore file per module for accepted risks with expiration dates, ensuring that risk acceptances were reviewed periodically rather than becoming permanent exemptions.
Commands
trivy config --severity CRITICAL,HIGH --exit-code 1 ./terraform/modules/ # Scan all Terraform modules
trivy config --format json --output results.json ./terraform/modules/networking/ # JSON output for CI processing
terraform plan -out=tfplan && terraform show -json tfplan > plan.json && trivy config plan.json # Scan Terraform plan output
trivy config --policy ./custom-policies/ --namespaces user ./terraform/ # Apply custom Rego policies
trivy config --tf-vars terraform.tfvars ./terraform/environments/prod/ # Scan with variable file for accurate evaluation
trivy config --skip-dirs ./terraform/modules/deprecated/ --severity CRITICAL ./terraform/ # Skip deprecated modules
Outcome
IaC misconfigurations in production deployments decreased by 89% within the first quarter. The security team's manual review burden dropped from 40 PRs/day to only the 3-5 flagged by Trivy as requiring human judgment. Time to detect misconfiguration patterns across the entire codebase reduced from weeks of manual audit to 12 minutes of automated scanning.
Lessons Learned
Scanning Terraform plan JSON output catches significantly more issues than scanning static HCL because it evaluates the actual values after variable interpolation, data source resolution, and module composition. The .trivyignore file with expiration dates was critical for maintaining developer trust because it provided a documented path for accepting risk rather than forcing workarounds.
◈ Architecture Diagram
┌──────────────────────────────────────────────────┐
│ Developer Workflow │
│ ┌───────────┐ ┌────────────┐ ┌─────────────┐ │
│ │ Write HCL │→ │ Pre-commit │→ │ Git Push │ │
│ │ │ │ trivy scan │ │ │ │
│ │ │ │ (local) │ │ │ │
│ └───────────┘ └────────────┘ └──────┬──────┘ │
└────────────────────────────────────────┼────────┘
▼
┌──────────────────────────────────────────────────┐
│ GitHub Actions CI │
│ ┌──────────────────────────────────────────┐ │
│ │ trivy config --severity CRITICAL,HIGH │ │
│ │ + Custom Rego Policies │ │
│ │ + terraform plan JSON scanning │ │
│ │ │ │
│ │ Results → PR Comment with annotations │ │
│ │ CRITICAL/HIGH → Block merge ✗ │ │
│ │ MEDIUM → Warning (ack required) │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ ✓ Merge Allowed │ │ ✗ Merge Blocked │
│ No CRIT/HIGH │ │ Fix required │
└──────────────────┘ └──────────────────┘💬 Comments
Context
Datadog runs 50+ Kubernetes clusters across AWS and GCP hosting their observability platform. With over 15,000 running pods and 3,000 unique container images, they needed continuous visibility into vulnerabilities and misconfigurations across their entire fleet without impacting cluster performance or developer velocity.
Problem
Datadog's security team had implemented CI-time image scanning using a proprietary scanner, but this only caught vulnerabilities at build time. Once images were deployed to production clusters, there was no ongoing monitoring for newly published CVEs that affected running workloads. When the Log4Shell vulnerability (CVE-2021-44228) was disclosed, the security team spent 72 hours manually scanning every running container image in their fleet to determine exposure. The process involved writing custom scripts to extract image references from all pods across 50 clusters, pulling each unique image, scanning it, and correlating results with the running workloads. This manual process was not only slow but also inaccurate because some pods used init containers and sidecar images that were missed in the initial sweep. Beyond image vulnerabilities, the team had no visibility into Kubernetes resource misconfigurations at scale. Individual teams were responsible for writing secure pod security contexts, but audits revealed that 28% of deployments ran as root, 41% had no resource limits set, 15% mounted the Docker socket, and 12% used hostNetwork. These misconfigurations were only discovered during quarterly manual audits that took the security team 2 weeks to complete. The team also lacked visibility into RBAC misconfigurations, with several service accounts having cluster-admin privileges that were granted during debugging sessions and never revoked. The combination of stale vulnerability data and undetected misconfigurations created significant security blind spots across their Kubernetes fleet.
Solution
Datadog deployed the Trivy Operator (formerly Starboard) across all 50 Kubernetes clusters to provide continuous, automated security scanning. The operator was installed via Helm with carefully tuned resource limits and scan concurrency settings to prevent impact on production workloads. They configured the operator to perform three types of scans: VulnerabilityReports for container image scanning, ConfigAuditReports for Kubernetes resource misconfiguration detection, and RbacAssessmentReports for RBAC analysis. For vulnerability scanning, the operator was configured to scan each unique image only once and cache results as VulnerabilityReport custom resources, significantly reducing scan overhead in clusters where many pods used the same base images. They set up a scan schedule that rescanned all images every 24 hours to detect newly published CVEs. The vulnerability database was mirrored to an internal OCI registry and distributed to all clusters to avoid external network dependencies and ensure consistent scan results. For misconfiguration scanning, they configured the operator with custom policies that enforced Datadog's security standards: pods must run as non-root, containers must have resource limits, host namespaces must not be shared, and service accounts must not automount tokens unless explicitly required. The operator generated ConfigAuditReport resources for every workload, providing a real-time compliance dashboard when aggregated through a custom Prometheus exporter they built. They integrated the operator's output with their own Datadog monitoring platform, creating custom dashboards showing vulnerability trends, compliance scores per namespace, and team-level security posture. Automated alerts fired when critical vulnerabilities were detected in production workloads, with PagerDuty integration for the most severe findings. The RBAC assessment identified 47 service accounts with excessive privileges in the first scan, and automated Slack notifications were sent to cluster administrators for remediation.
Commands
helm install trivy-operator aquasecurity/trivy-operator --namespace trivy-system --set trivy.dbRepository=registry.internal/trivy-db # Install operator with internal DB mirror
kubectl get vulnerabilityreports -A --sort-by='.report.summary.criticalCount' # List reports sorted by critical vuln count
kubectl get configauditreports -A -o json | jq '[.items[] | select(.report.summary.criticalCount > 0)]' # Find critical misconfigs
kubectl get rbacassessmentreports -A # List all RBAC assessment findings
kubectl describe vulnerabilityreport -n payments replicaset-payments-api-7d9f8c # Detailed vulnerability report for a workload
kubectl get vulnerabilityreports -A -o json | jq '[.items[].report.vulnerabilities[] | select(.severity=="CRITICAL")] | unique_by(.vulnerabilityID)' # Unique critical CVEs across cluster
Outcome
Time to assess fleet-wide CVE exposure decreased from 72 hours to 3 minutes using VulnerabilityReport queries. Kubernetes misconfiguration compliance rate improved from 59% to 97% within 8 weeks. RBAC over-privilege findings decreased from 47 to 2 through automated detection and alerting.
Lessons Learned
Tuning the Trivy Operator's scan concurrency and resource limits is critical in large clusters because aggressive scanning can cause resource contention with production workloads. Caching scan results per unique image digest rather than per pod dramatically reduces scan overhead in environments with many replicas of the same image. The operator's CRD-based output model is powerful because it enables GitOps-style compliance workflows where teams can query their security posture using standard kubectl commands.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────────┐
│ Kubernetes Cluster (per cluster) │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Trivy Operator │ │
│ │ ┌────────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Vuln Scan │ │ConfigAudit│ │RBAC Assess │ │ │
│ │ │ (images) │ │(workloads)│ │(serviceaccts)│ │ │
│ │ └─────┬──────┘ └────┬─────┘ └──────┬───────┘ │ │
│ └────────┼─────────────┼──────────────┼────────────┘ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Kubernetes Custom Resources │ │
│ │ VulnerabilityReport │ ConfigAuditReport │ RBAC │ │
│ └───────────────────────┬────────────────────────────┘ │
└──────────────────────────┼───────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ Datadog Monitoring Platform │
│ ┌────────────────┐ ┌────────────┐ ┌──────────────────┐ │
│ │ Vuln Dashboard │ │ Compliance │ │ Alert: Critical │ │
│ │ Trend: ↓ 73% │ │ Score: 97% │ │ CVE → PagerDuty │ │
│ └────────────────┘ └────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────┘💬 Comments
Context
Siemens Digital Industries delivers industrial IoT software deployed in critical infrastructure across 200+ manufacturing facilities. New EU Cyber Resilience Act (CRA) regulations and US Executive Order 14028 mandate that all software vendors provide Software Bills of Materials (SBOMs) for their products, with non-compliance penalties starting in 2025.
Problem
Siemens Digital Industries shipped 85 software products as container images and VM appliances to their manufacturing customers. Each product contained hundreds of open-source dependencies across multiple layers: OS packages in the base image, language-specific libraries installed via pip, npm, and Maven, and statically compiled binaries with embedded dependencies. When regulators and enterprise customers began requesting SBOMs, the team discovered they had no systematic way to generate accurate dependency inventories. Their first attempt involved manually documenting dependencies by examining Dockerfiles and package manager lock files, but this approach missed transitive dependencies, dependencies pulled in during multi-stage builds, and packages installed through custom build scripts. A manual audit of one product revealed 847 dependencies, while the manually maintained list contained only 312, a 63% undercount that would not satisfy regulatory requirements. The EU CRA required SBOMs in standardized formats (CycloneDX or SPDX) with specific fields including supplier information, version numbers, and known vulnerability status. Generating compliant SBOMs manually was estimated to require 6 person-months of effort across all 85 products, and the SBOMs would be outdated by the time they were completed because dependencies changed with every release. Several enterprise customers, including automotive manufacturers and energy companies, made SBOM delivery a contractual requirement for continued procurement, creating a revenue-threatening urgency. The team also needed to track license compliance across all dependencies because some open-source licenses had restrictions incompatible with their commercial distribution model.
Solution
Siemens implemented Trivy as their SBOM generation and vulnerability correlation engine, integrating it into their Jenkins-based CI/CD pipeline and their release management process. For each product build, the pipeline ran trivy image with --format cyclonedx to generate a CycloneDX SBOM containing all OS packages, language-specific libraries, and their transitive dependencies. They also ran trivy fs on the source code repository to capture dependencies declared in lock files that might not be present in the final image due to multi-stage builds. The two SBOMs were merged using a custom tool to create a comprehensive dependency inventory. For VM appliance products, they used trivy rootfs to scan the filesystem of the built VM image, capturing all installed packages including those installed through system package managers. Each SBOM was enriched with supplier metadata, license information, and known vulnerability status by cross-referencing with Trivy's vulnerability database. The enriched SBOMs were stored in a central SBOM repository alongside the release artifacts, with each SBOM cryptographically signed using cosign and linked to the product version through OCI attestations. They built an internal SBOM portal that allowed customers to download SBOMs for any product version and receive automated notifications when new vulnerabilities were discovered in dependencies of products they had deployed. For license compliance, they configured Trivy to extract license information for all packages using --license-full and created automated checks that flagged any dependencies using copyleft licenses (GPL, AGPL) that were incompatible with their commercial distribution. The team also implemented trivy sbom to scan existing SBOMs against the latest vulnerability database, enabling them to provide updated vulnerability assessments for previously shipped product versions without rebuilding them.
Commands
trivy image --format cyclonedx --output sbom-image.json registry.siemens.internal/iot-gateway:v4.2.0 # Generate CycloneDX SBOM from image
trivy fs --format spdx-json --output sbom-source.json ./src/ # Generate SPDX SBOM from source code
trivy rootfs --format cyclonedx --output sbom-vm.json /mnt/appliance-rootfs/ # Generate SBOM from VM filesystem
trivy sbom --severity CRITICAL,HIGH sbom-image.json # Scan existing SBOM for new vulnerabilities
trivy image --license-full --format json registry.siemens.internal/iot-gateway:v4.2.0 # Extract license information for compliance
cosign attest --predicate sbom-image.json --type cyclonedx registry.siemens.internal/iot-gateway:v4.2.0 # Attach signed SBOM attestation
Outcome
SBOM generation time per product reduced from estimated 3-4 weeks of manual effort to 8 minutes of automated pipeline execution. Achieved 100% regulatory compliance with EU CRA SBOM requirements across all 85 products. Dependency visibility increased from 37% coverage to 99.6% coverage, identifying 12 copyleft license violations before product shipment.
Lessons Learned
Combining image scanning and filesystem scanning SBOMs is essential for complete coverage because multi-stage Docker builds intentionally exclude build-time dependencies that may still be legally relevant for SBOM compliance. SBOM generation should happen at build time and be treated as a release artifact with the same versioning, signing, and storage rigor as the software itself rather than being generated on-demand.
◈ Architecture Diagram
┌──────────────────────────────────────────────────────┐
│ CI/CD Pipeline (Jenkins) │
│ │
│ ┌──────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Build │→ │ trivy image │→ │ trivy fs │ │
│ │ Product │ │ (image SBOM) │ │ (source SBOM) │ │
│ └──────────┘ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │
│ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Merge + Enrich SBOM │ │
│ │ + License Check │ │
│ │ + Vulnerability Map │ │
│ └──────────┬───────────┘ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ cosign attest (sign) │ │
│ └──────────┬───────────┘ │
└──────────────────────────────┼───────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ SBOM Repository + Customer Portal │
│ Product v4.2.0 → CycloneDX SBOM (signed) ✓ │
│ 847 dependencies │ 0 copyleft violations ✓ │
│ Customer notification: new CVE affects v4.1.x │
└──────────────────────────────────────────────────────┘💬 Comments
Context
Coinbase operates a large monorepo containing 400+ services with 2,000+ developers contributing daily. After a leaked AWS key in a committed configuration file was exploited within 4 minutes of being pushed to a public fork, the security team needed comprehensive filesystem scanning that could catch secrets, vulnerabilities, and misconfigurations before code left the developer's machine.
Problem
Coinbase's monorepo contained a mix of Go, Python, Java, and TypeScript services alongside Terraform infrastructure code, Kubernetes manifests, and Dockerfiles. The sheer size of the repository (over 5 million lines of code) made manual security review impractical. The leaked AWS key incident revealed multiple gaps in their security posture: there were no pre-commit hooks scanning for secrets, the CI pipeline did not check for exposed credentials in configuration files, and developers frequently committed .env files, test fixtures containing real API keys, and hardcoded database connection strings. A retroactive scan revealed 23 valid credentials committed across the repository's history, including 5 AWS access keys, 8 database passwords, 4 third-party API tokens, and 6 private SSH keys. Beyond secrets, the repository's lock files (go.sum, package-lock.json, requirements.txt, pom.xml) contained references to 12,000+ open-source dependencies, many with known vulnerabilities. The team had no process for tracking vulnerable dependencies across the monorepo, and developers were unaware when their services used libraries with critical CVEs. Terraform modules in the repository had accumulated misconfigurations over time, and Kubernetes manifests varied in quality with some services running privileged containers. The challenge was finding a single tool that could address all these scanning needs across multiple languages and configuration formats without requiring separate scanners for each concern.
Solution
Coinbase adopted Trivy as their unified scanning platform, leveraging its ability to scan filesystems for vulnerabilities, secrets, misconfigurations, and license issues in a single pass. They implemented a multi-layer scanning strategy starting with developer workstations. A pre-commit hook ran trivy fs --scanners secret on changed files, blocking commits containing potential secrets with near-zero false positive rate. The hook was configured with custom regex patterns for Coinbase-specific internal tokens and API keys that Trivy's built-in patterns did not cover. In the CI pipeline, they ran a comprehensive scan using trivy fs --scanners vuln,secret,misconfig,license on the entire changed directory scope for each pull request. The scan results were parsed and posted as GitHub PR comments with severity-based formatting: secrets and critical vulnerabilities blocked the PR, while medium vulnerabilities and misconfigurations were reported as warnings. For dependency vulnerability scanning, they configured Trivy to parse all supported lock files across the monorepo, generating a unified vulnerability report that was ingested into their security data platform. A weekly full-repository scan ran trivy fs --scanners vuln on the entire monorepo, producing a comprehensive vulnerability inventory that fed into team-level security scorecards. They built a custom Trivy wrapper that determined which services were affected by each vulnerability based on the monorepo directory structure, automatically creating Jira tickets assigned to the correct team. For secret scanning, they implemented trivy fs --scanners secret --secret-config custom-secrets.yaml with an extended ruleset that detected Coinbase-specific credential patterns, internal service tokens, and encryption keys. Historical secret scanning was performed using git log piped through Trivy to identify credentials committed at any point in the repository's history, enabling a comprehensive credential rotation effort.
Commands
trivy fs --scanners secret --exit-code 1 --severity HIGH,CRITICAL . # Pre-commit secret scan
trivy fs --scanners vuln,secret,misconfig,license --format json --output results.json ./services/payments/ # Comprehensive service scan
trivy fs --scanners vuln --list-all-pkgs --format json . # Full dependency inventory across monorepo
trivy fs --scanners secret --secret-config ./security/custom-secrets.yaml . # Scan with custom secret patterns
trivy fs --scanners misconfig --config-policy ./security/rego-policies/ ./terraform/ # Custom misconfig policies for Terraform
trivy repo --scanners secret https://github.com/coinbase/internal-service --branch main # Scan git history for leaked secrets
Outcome
Zero credential leaks in the 18 months following implementation, down from 4 incidents in the prior 6 months. Known vulnerable dependencies across the monorepo decreased by 76% as teams addressed Trivy-generated tickets. Mean time to detect a committed secret dropped from never (no scanning) to under 30 seconds via pre-commit hooks.
Lessons Learned
Running Trivy in filesystem mode with all scanners enabled (vuln, secret, misconfig, license) in a single pass is significantly more efficient than running multiple specialized tools, but you must tune the secret detection rules to reduce false positives for your specific codebase. Pre-commit hooks must be fast (under 5 seconds for changed files) or developers will disable them, so scan only changed files at commit time and save full scans for CI.
◈ Architecture Diagram
┌───────────────────────────────────────────────────────┐
│ Developer Workstation │
│ ┌───────────────────────────────────────────────┐ │
│ │ Pre-commit Hook │ │
│ │ trivy fs --scanners secret (changed files) │ │
│ │ ✓ No secrets → commit allowed │ │
│ │ ✗ Secret found → commit blocked │ │
│ └───────────────────────────┬───────────────────┘ │
└──────────────────────────────┼────────────────────────┘
▼
┌───────────────────────────────────────────────────────┐
│ CI Pipeline (GitHub Actions) │
│ trivy fs --scanners vuln,secret,misconfig,license │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Vulns │ │ Secrets │ │ Misconfig│ │ License │ │
│ │ go.sum │ │ .env │ │ k8s yaml │ │ GPL ✗ │ │
│ │ lock.json│ │ API keys │ │ Terraform│ │ MIT ✓ │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │
│ │ │
│ PR Comment + Block/Warn │
└───────────────────────┬───────────────────────────────┘
▼
┌───────────────────────────────────────────────────────┐
│ Security Data Platform + Jira │
│ Team Scorecards │ Vuln Tracking │ Auto-Tickets │
└───────────────────────────────────────────────────────┘💬 Comments
Context
Deutsche Bank's trading platform runs in a strictly air-gapped environment processing 2.5 million trades daily. BaFin (German Federal Financial Supervisory Authority) and the ECB require continuous compliance with CIS benchmarks for all container and Kubernetes infrastructure, with quarterly audit evidence submission.
Problem
Deutsche Bank's trading platform operated in a fully air-gapped network segment with no internet connectivity, which was a regulatory requirement for systems processing financial market data. Their container infrastructure ran 800+ pods across 5 Kubernetes clusters, all behind an air gap that prevented standard vulnerability scanning tools from downloading updated vulnerability databases or reaching cloud-based scanning services. The compliance team was required to demonstrate adherence to CIS Docker Benchmark and CIS Kubernetes Benchmark standards, with evidence refreshed quarterly. Previously, compliance checks were performed manually by a dedicated team of 6 auditors who used CIS-CAT Pro assessment tool on individual nodes, a process that took 3 weeks per quarterly cycle and produced PDF reports that were difficult to aggregate and trend over time. The manual process was also error-prone: during one audit, the team discovered that 3 Kubernetes nodes had been missed entirely because they were added between the start and end of the assessment window. Container image compliance was even more challenging because the bank used a private registry that mirrored approved images from the internet through a controlled transfer process, but there was no scanning of images after they entered the air-gapped environment. The compliance team could not verify whether mirrored images contained vulnerabilities because their scanning tools required internet connectivity for database updates. Furthermore, the bank's regulatory obligations required them to demonstrate that compliance checks were continuous rather than point-in-time, which the quarterly manual audit could not satisfy.
Solution
Deutsche Bank implemented Trivy in their air-gapped environment with a carefully designed database update workflow. They set up an internet-connected staging environment where a cron job ran trivy image --download-db-only daily to download the latest vulnerability database, which was then packaged and transferred to the air-gapped environment through their approved data transfer process (encrypted USB media with dual-custody chain of custody). Inside the air gap, they hosted the Trivy vulnerability database in a private OCI registry (Harbor), and all Trivy instances were configured with --db-repository pointing to this internal registry and --skip-db-update to prevent any attempted external connections. For CIS compliance, they deployed the Trivy Operator configured with compliance scanning capabilities that continuously assessed all Kubernetes workloads against CIS Docker Benchmark 1.6.0 and CIS Kubernetes Benchmark 1.8.0. The operator produced ComplianceReport custom resources that captured the pass/fail status of each CIS check for every workload, node, and cluster configuration. They built a compliance aggregation service that collected ComplianceReports from all 5 clusters and generated the evidence artifacts required by BaFin in their specific format, including trend data showing compliance posture over time. Automated remediation was implemented for common findings: when the operator detected a container running as root or without read-only root filesystem, it created a Jira ticket with the specific Deployment or StatefulSet to fix and the required pod security context changes. For quarterly audits, the compliance team could now generate comprehensive reports in minutes by querying the ComplianceReport CRDs, replacing the 3-week manual assessment process. The reports included historical compliance trends, current violation details, remediation timelines, and risk acceptance documentation for any exceptions.
Commands
trivy image --download-db-only --db-repository ghcr.io/aquasecurity/trivy-db # Download DB on internet-connected system
trivy image --skip-db-update --db-repository harbor.internal.db.com/trivy/trivy-db:2 --offline-scan registry.internal/trading-engine:v8.1.0 # Air-gapped image scan
trivy kubernetes --compliance k8s-cis-1.8 --report all # Run CIS Kubernetes Benchmark 1.8 compliance check
trivy kubernetes --compliance docker-cis-1.6.0 --report summary # CIS Docker Benchmark summary
trivy image --compliance docker-cis-1.6.0 --skip-db-update registry.internal/trading-engine:v8.1.0 # CIS compliance check on specific image
kubectl get compliancereports -A -o json | jq '[.items[] | {cluster: .metadata.labels.cluster, passed: .status.summary.passCount, failed: .status.summary.failCount}]' # Aggregate compliance across clustersOutcome
Quarterly compliance assessment time reduced from 3 weeks of manual auditing to 45 minutes of automated report generation. Continuous compliance monitoring achieved for the first time, satisfying BaFin's requirement for ongoing assurance rather than point-in-time snapshots. CIS benchmark compliance rate improved from 71% to 96% through automated detection and remediation tracking.
Lessons Learned
Air-gapped Trivy deployments require a well-documented and tested database update procedure because stale vulnerability databases create a false sense of security. The dual-registry approach (one internet-facing for DB downloads, one air-gapped for scanning) adds operational overhead but is the only reliable pattern for regulated environments. CIS compliance scanning generates a large volume of findings initially, so prioritizing critical and high-severity findings while establishing a realistic remediation timeline prevents team burnout.
◈ Architecture Diagram
┌──────────────────────┐ ┌──────────────────────┐
│ Internet Zone │ │ Air-Gapped Zone │
│ ┌────────────────┐ │ USB │ ┌────────────────┐ │
│ │ trivy download │ │ ──────→ │ │ Harbor Registry│ │
│ │ --db-only │ │ (daily) │ │ (trivy-db) │ │
│ │ (cron daily) │ │ │ └───────┬────────┘ │
│ └────────────────┘ │ │ │ │
└──────────────────────┘ │ ▼ │
│ ┌────────────────┐ │
│ │ Trivy Operator │ │
│ │ --skip-db-update│ │
│ │ --offline-scan │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │Compliance │ │
│ │Reports (CRDs) │ │
│ │● CIS K8s 1.8 │ │
│ │● CIS Docker 1.6│ │
│ │● VulnReports │ │
│ └───────┬────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ BaFin Audit │ │
│ │ Report (auto) │ │
│ │ Trend: ↑ 96% │ │
│ └────────────────┘ │
└──────────────────────┘💬 Comments