Container Image Scanning
Why Image Scanning Matters
Container images are the fundamental unit of deployment in Kubernetes. Every running workload is built from an image, and that image may contain:
- Known vulnerabilities (CVEs) in OS packages or application dependencies
- Malware injected through compromised base images or supply chain attacks
- Misconfigurations such as running as root, exposing unnecessary ports, or including secrets
- Outdated packages with known exploits
A single vulnerable image deployed to your cluster can serve as an entry point for attackers to escalate privileges, move laterally, or exfiltrate data. Image scanning is your first automated line of defense.
CKS Exam Relevance
Trivy is the primary image scanning tool on the CKS exam. You must be able to install it, scan images, filter by severity, interpret results, and use different output formats. Expect at least one question involving Trivy.
Image Scanning Pipeline
Trivy Overview
Trivy is an open-source, comprehensive security scanner developed by Aqua Security. It is fast, easy to use, and covers multiple scanning targets.
What Trivy Can Scan
| Target | Description | Command Prefix |
|---|---|---|
| Container Images | OS packages and language dependencies | trivy image |
| Filesystems | Local project directories | trivy fs |
| Git Repositories | Remote repositories | trivy repo |
| Kubernetes | Running cluster resources | trivy k8s |
| Configuration Files | IaC misconfigurations | trivy config |
| SBOM | Software Bill of Materials | trivy sbom |
What Trivy Detects
| Scanner | Description |
|---|---|
| Vulnerabilities (vuln) | Known CVEs in OS packages and libraries |
| Misconfigurations (misconfig) | IaC issues in Dockerfiles, Kubernetes manifests, Terraform |
| Secrets (secret) | Hardcoded passwords, API keys, tokens |
| Licenses (license) | Software license compliance issues |
Installing Trivy
Exam Note
Trivy will be pre-installed on the CKS exam environment. However, knowing how to install it helps during practice.
Install on Ubuntu/Debian
# Add the Trivy repository
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb \
$(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy -yInstall via Binary
# Download the latest release
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | \
sh -s -- -b /usr/local/bin v0.50.0
# Verify installation
trivy versionScanning Container Images
Basic Image Scan
trivy image nginx:1.25Sample Output:
nginx:1.25 (debian 12.4)
=========================
Total: 142 (UNKNOWN: 0, LOW: 82, MEDIUM: 46, HIGH: 12, CRITICAL: 2)
┌─────────────────────┬────────────────┬──────────┬────────────────────┬───────────────┬──────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├─────────────────────┼────────────────┼──────────┼────────────────────┼───────────────┼──────────────────────────────────────┤
│ libssl3 │ CVE-2024-0727 │ CRITICAL │ 3.0.11-1~deb12u2 │ 3.0.13-1 │ openssl: denial of service via null │
│ │ │ │ │ │ dereference │
├─────────────────────┼────────────────┼──────────┼────────────────────┼───────────────┼──────────────────────────────────────┤
│ libexpat1 │ CVE-2023-52425 │ CRITICAL │ 2.5.0-1 │ 2.6.0-1 │ expat: parsing large tokens can │
│ │ │ │ │ │ trigger a denial of service │
├─────────────────────┼────────────────┼──────────┼────────────────────┼───────────────┼──────────────────────────────────────┤
│ curl │ CVE-2024-0853 │ HIGH │ 7.88.1-10+deb12u5 │ 7.88.1-10+ │ curl: OCSP verification bypass with │
│ │ │ │ │ deb12u6 │ TLS session reuse │
├─────────────────────┼────────────────┼──────────┼────────────────────┼───────────────┼──────────────────────────────────────┤
│ libc6 │ CVE-2024-2961 │ HIGH │ 2.36-9+deb12u4 │ 2.36-9+ │ glibc: buffer overflow in iconv() │
│ │ │ │ │ deb12u7 │ │
└─────────────────────┴────────────────┴──────────┴────────────────────┴───────────────┴──────────────────────────────────────┘Filter by Severity
In the CKS exam, you are often asked to find only CRITICAL or HIGH vulnerabilities:
# Show only CRITICAL and HIGH vulnerabilities
trivy image --severity CRITICAL,HIGH nginx:1.25Common Mistake
The --severity flag uses comma-separated values with NO spaces: CRITICAL,HIGH -- not CRITICAL, HIGH.
Sample Output:
nginx:1.25 (debian 12.4)
=========================
Total: 14 (HIGH: 12, CRITICAL: 2)
┌─────────────────────┬────────────────┬──────────┬────────────────────┬───────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │
├─────────────────────┼────────────────┼──────────┼────────────────────┼───────────────┤
│ libssl3 │ CVE-2024-0727 │ CRITICAL │ 3.0.11-1~deb12u2 │ 3.0.13-1 │
│ libexpat1 │ CVE-2023-52425 │ CRITICAL │ 2.5.0-1 │ 2.6.0-1 │
│ curl │ CVE-2024-0853 │ HIGH │ 7.88.1-10+deb12u5 │ 7.88.1-10+ │
│ ... │ │ │ │ deb12u6 │
└─────────────────────┴────────────────┴──────────┴────────────────────┴───────────────┘Filter Only Fixable Vulnerabilities
# Show only vulnerabilities that have a fix available
trivy image --ignore-unfixed nginx:1.25This is useful for actionable remediation -- only showing CVEs where an upgraded package version exists.
Scan Only for Specific Types
# Scan for OS vulnerabilities only (skip language-specific)
trivy image --vuln-type os nginx:1.25
# Scan for language library vulnerabilities only
trivy image --vuln-type library python:3.11
# Scan for both (default behavior)
trivy image --vuln-type os,library nginx:1.25Understanding Severity Levels
Trivy uses standardized CVSS-based severity classifications:
| Severity | CVSS Score | Meaning | Action Required |
|---|---|---|---|
| CRITICAL | 9.0 - 10.0 | Easily exploitable, severe impact | Immediate fix required |
| HIGH | 7.0 - 8.9 | Significant risk, likely exploitable | Fix as soon as possible |
| MEDIUM | 4.0 - 6.9 | Moderate risk, may require conditions | Plan remediation |
| LOW | 0.1 - 3.9 | Minimal risk, difficult to exploit | Fix when convenient |
| UNKNOWN | N/A | Not yet scored | Investigate manually |
Exam Strategy
On the CKS exam, you will typically need to identify images with CRITICAL or HIGH vulnerabilities. Use --severity CRITICAL,HIGH to quickly filter results.
Output Formats
Trivy supports multiple output formats for different use cases.
Table Format (Default)
trivy image nginx:1.25
# Default human-readable table outputJSON Format
trivy image --format json nginx:1.25
# Save to file
trivy image --format json -o results.json nginx:1.25Sample JSON output (abbreviated):
{
"Results": [
{
"Target": "nginx:1.25 (debian 12.4)",
"Class": "os-pkgs",
"Type": "debian",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2024-0727",
"PkgName": "libssl3",
"InstalledVersion": "3.0.11-1~deb12u2",
"FixedVersion": "3.0.13-1",
"Severity": "CRITICAL",
"Title": "openssl: denial of service via null dereference"
}
]
}
]
}Template Format
# Use a custom Go template
trivy image --format template \
--template '{{range .Results}}{{range .Vulnerabilities}}{{.VulnerabilityID}} {{.Severity}} {{.PkgName}}{{"\n"}}{{end}}{{end}}' \
nginx:1.25Sample Output:
CVE-2024-0727 CRITICAL libssl3
CVE-2023-52425 CRITICAL libexpat1
CVE-2024-0853 HIGH curl
CVE-2024-2961 HIGH libc6SARIF Format (for CI/CD Integration)
trivy image --format sarif -o trivy-results.sarif nginx:1.25Scanning for Misconfigurations
Trivy can scan Kubernetes manifests and Dockerfiles for security misconfigurations:
Scan Kubernetes Manifests
trivy config /path/to/k8s-manifests/Sample Output:
Dockerfile (dockerfile)
========================
Tests: 23 (SUCCESSES: 19, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 1)
HIGH: Specify at least 1 USER command in Dockerfile
═══════════════════════════════════════════════════
Running containers with 'root' user can lead to a container escape situation.
MEDIUM: Add HEALTHCHECK instruction in your Dockerfile
═══════════════════════════════════════════════════════
HEALTHCHECK instruction allows Docker to test the application health.
deployment.yaml (kubernetes)
============================
Tests: 28 (SUCCESSES: 22, FAILURES: 6, EXCEPTIONS: 0)
Failures: 6 (HIGH: 3, MEDIUM: 2, LOW: 1)
HIGH: Container 'app' should set 'securityContext.runAsNonRoot' to true
═══════════════════════════════════════════════════════════════════════
HIGH: Container 'app' should set 'securityContext.readOnlyRootFilesystem' to true
═════════════════════════════════════════════════════════════════════════════════Scan a Dockerfile
trivy config --file-patterns "dockerfile:Dockerfile.prod" .Scanning Running Containers in Kubernetes
Trivy can scan images of running containers in a Kubernetes cluster:
# Scan all images in the cluster
trivy k8s --report summary cluster
# Scan a specific namespace
trivy k8s --namespace default --report summary
# Scan and get detailed vulnerability info
trivy k8s --report all --namespace productionSample Summary Output:
Summary Report for kubernetes cluster
══════════════════════════════════════
Workload Assessment
┌───────────┬──────────────────────┬───────────────┬────────────────┬────────────────┐
│ Namespace │ Resource │ Critical │ High │ Medium │
├───────────┼──────────────────────┼───────────────┼────────────────┼────────────────┤
│ default │ Deploy/nginx │ 2 │ 12 │ 46 │
│ default │ Deploy/redis │ 0 │ 3 │ 18 │
│ kube-sys │ Deploy/coredns │ 0 │ 1 │ 5 │
└───────────┴──────────────────────┴───────────────┴────────────────┴────────────────┘Scanning a Tar Archive Image
If you have a saved image archive:
# Save an image to a tar file
docker save nginx:1.25 -o nginx.tar
# Scan the tar archive
trivy image --input nginx.tarExam Scenario
In the CKS exam, you may be asked to scan an image that is available as a tar file on the node. Use trivy image --input <file.tar> for this.
CI/CD Integration
Exit Codes for Pipeline Gates
Trivy returns non-zero exit codes when vulnerabilities are found, making it ideal for CI/CD gates:
# Exit with code 1 if CRITICAL vulnerabilities are found
trivy image --exit-code 1 --severity CRITICAL nginx:1.25
# Different exit codes for different severities
trivy image --exit-code 0 --severity MEDIUM,LOW \
--exit-code 1 --severity CRITICAL,HIGH nginx:1.25GitHub Actions Example
name: Security Scan
on: push
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: trueJenkins Pipeline Example
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'docker build -t myapp:${BUILD_NUMBER} .'
}
}
stage('Security Scan') {
steps {
sh '''
trivy image \
--exit-code 1 \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--format json \
-o trivy-report.json \
myapp:${BUILD_NUMBER}
'''
}
post {
always {
archiveArtifacts artifacts: 'trivy-report.json'
}
}
}
}
}Advanced Trivy Usage
Using a Trivy Cache
Trivy downloads vulnerability databases on first run. In air-gapped environments:
# Download the DB manually
trivy image --download-db-only
# Skip DB update (use cached)
trivy image --skip-db-update nginx:1.25
# Specify cache directory
trivy image --cache-dir /tmp/trivy-cache nginx:1.25Ignoring Specific CVEs
Create a .trivyignore file to suppress known false positives:
# .trivyignore
# Suppress specific CVEs with optional comments
CVE-2024-0727
CVE-2023-52425 # Accepted risk: not exploitable in our config# Trivy will automatically read .trivyignore in the current directory
trivy image nginx:1.25
# Or specify a custom ignore file
trivy image --ignorefile /path/to/.trivyignore nginx:1.25Scanning Specific Image Layers
# Show which layer introduced each vulnerability
trivy image --list-all-pkgs nginx:1.25Quick Reference: Common Trivy Commands
| Command | Purpose |
|---|---|
trivy image <image> | Scan a container image |
trivy image --severity CRITICAL,HIGH <image> | Filter by severity |
trivy image --ignore-unfixed <image> | Show only fixable CVEs |
trivy image --format json -o out.json <image> | JSON output to file |
trivy image --input image.tar | Scan a saved image archive |
trivy image --exit-code 1 <image> | Exit with error if vulns found |
trivy fs /path | Scan a filesystem |
trivy config /path | Scan for misconfigurations |
trivy k8s --report summary cluster | Scan a Kubernetes cluster |
trivy image --skip-db-update <image> | Use cached vulnerability DB |
Key Takeaways
Summary
- Trivy is the go-to tool for the CKS exam -- know its commands cold
- Severity filtering with
--severity CRITICAL,HIGHis essential for exam tasks - JSON output with
--format json -o file.jsonis useful for programmatic analysis - Exit codes enable automated pipeline gates (
--exit-code 1) - Misconfiguration scanning with
trivy configextends beyond just CVEs - Image archives can be scanned with
--inputflag - Always check for fixed versions --
--ignore-unfixedshows actionable items only
Common Exam Pitfalls
- Forgetting the
--severityflag syntax (comma-separated, no spaces) - Not knowing the
--inputflag for tar archives - Confusing
trivy image(CVEs) withtrivy config(misconfigurations) - Not filtering by severity when the question asks for specific severity levels