- security
- l1
- topic-pack
- security-scanning --- Portal | Level: L1: Foundations | Topics: Security Scanning | Domain: Security
Security Scanning - Primer¶
Why This Matters¶
Every container image you deploy carries hundreds of dependencies, each a potential attack vector. The average container image has 50-200 known vulnerabilities at any point in time. Security scanning finds them before attackers do. Without automated scanning in your CI/CD pipeline, you are deploying blind — shipping known-vulnerable code to production and hoping nobody notices.
Core Concepts¶
1. Container Image Scanning with Trivy¶
Who made it: Trivy was created by Teppei Fukuda at Aqua Security and open-sourced in 2019. The name "Trivy" comes from the word "trivial" — reflecting the goal of making security scanning trivially easy. It quickly displaced older tools like Clair and Anchore Engine as the default choice because it requires zero setup: download the binary, point it at an image, and get results. Aqua Security (founded 2015 in Israel) maintains it as a CNCF-hosted open source project.
Trivy is the de facto standard for container image scanning — fast, accurate, and easy to integrate:
# Scan a local image
trivy image myapp:latest
# Scan with severity filter (only HIGH and CRITICAL)
trivy image --severity HIGH,CRITICAL myapp:latest
# Scan and fail if vulnerabilities found (for CI gates)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
# Scan a remote image without pulling
trivy image --remote docker.io/library/nginx:1.25
# JSON output for automation
trivy image --format json --output results.json myapp:latest
# Scan a Dockerfile (misconfiguration detection)
trivy config Dockerfile
# Scan a filesystem (IaC files, Terraform, Kubernetes manifests)
trivy fs --security-checks vuln,config ./
Reading Trivy output:
myapp:latest (debian 12.4)
Total: 23 (HIGH: 18, CRITICAL: 5)
┌──────────────┬────────────────┬──────────┬────────────────┬───────────────┐
│ Library │ Vulnerability │ Severity │ Installed Ver │ Fixed Ver │
├──────────────┼────────────────┼──────────┼────────────────┼───────────────┤
│ libssl3 │ CVE-2024-0727 │ CRITICAL │ 3.0.11-1 │ 3.0.13-1 │
│ curl │ CVE-2023-46218 │ HIGH │ 7.88.1-10+deb12│ 7.88.1-10+deb │
└──────────────┴────────────────┴──────────┴────────────────┴───────────────┘
2. Software Bill of Materials (SBOM)¶
Name origin: CVE stands for Common Vulnerabilities and Exposures. The system was launched in 1999 by the MITRE Corporation, funded by the US federal government. The numbering format is CVE-YYYY-NNNNN, where YYYY is the year the ID was assigned (not necessarily the year the vulnerability was discovered). SBOM stands for Software Bill of Materials — the term was borrowed from manufacturing, where a BOM lists every component in a physical product.
An SBOM is a complete inventory of every component in your software — the ingredient list:
# Generate SBOM with Trivy (SPDX format)
trivy image --format spdx-json --output sbom.json myapp:latest
# Generate SBOM (CycloneDX format)
trivy image --format cyclonedx --output sbom.xml myapp:latest
# Scan an existing SBOM for vulnerabilities
trivy sbom sbom.json
# Generate SBOM with syft (alternative tool)
syft myapp:latest -o spdx-json > sbom.json
SBOMs answer: "What exactly is in this image?" — critical for incident response when a new CVE drops and you need to know which of your 200 services are affected.
3. CVE Databases and Vulnerability Prioritization¶
Not all vulnerabilities are equal. Prioritize using:
Priority Matrix:
P0 (Fix now): CRITICAL + exploitable + network-reachable + in production
P1 (Fix this week): HIGH + in production OR CRITICAL + not yet deployed
P2 (Fix this sprint): HIGH + not network-reachable
P3 (Track): MEDIUM with no known exploit
P4 (Accept risk): LOW, informational
Key databases:
| Database | URL | Coverage |
|---|---|---|
| NVD (NIST) | nvd.nist.gov | All published CVEs |
| GitHub Advisory | github.com/advisories | Language ecosystems |
| OSV | osv.dev | Open source focused |
| Red Hat Security | access.redhat.com/security | RHEL-specific |
# Check if a specific CVE affects your image
trivy image --vuln-type os myapp:latest | grep CVE-2024-0727
# Ignore accepted risks with .trivyignore
cat .trivyignore
CVE-2023-44487 # HTTP/2 rapid reset — mitigated at LB level
CVE-2023-39325 # Go stdlib — not reachable in our code
4. CI/CD Integration¶
Gate deployments on scan results:
# GitHub Actions example
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: table
exit-code: 1
severity: CRITICAL,HIGH
ignore-unfixed: true
# GitLab CI example
scan:
stage: test
image: aquasec/trivy:latest
script:
- trivy image --exit-code 1 --severity CRITICAL ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
allow_failure: false
# Jenkins pipeline snippet
sh """
trivy image --exit-code 1 \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--format json \
--output trivy-results.json \
${IMAGE_NAME}:${BUILD_TAG}
"""
5. Runtime Scanning¶
Scanning at build time is not enough — new CVEs are published daily against images already in production:
# Scan all images running in a cluster
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | \
sort -u | while read img; do
echo "=== Scanning ${img} ==="
trivy image --severity CRITICAL "${img}"
done
# Trivy Operator — continuous scanning inside Kubernetes
helm install trivy-operator aquasecurity/trivy-operator \
--namespace trivy-system --create-namespace
# View vulnerability reports
kubectl get vulnerabilityreports -A
kubectl describe vulnerabilityreport -n production
6. Supply Chain Security¶
Verify that images have not been tampered with:
# Sign images with cosign
cosign sign --key cosign.key myregistry.io/myapp:v1.2.3
# Verify signatures before deployment
cosign verify --key cosign.pub myregistry.io/myapp:v1.2.3
# Enforce signatures in Kubernetes (admission controller)
# Kyverno policy example:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: check-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "myregistry.io/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Gotcha: The
.trivyignorefile suppresses warnings but does not make vulnerabilities disappear. Auditors will ask why entries are ignored. Always add a comment explaining the mitigation (e.g., "mitigated at LB level," "function not reachable in our code"). Uncommented ignores look like negligence in a SOC2 or PCI-DSS audit.Remember: The scanning pipeline mnemonic is BSRV: Build (scan image in CI), Sign (cosign), Run (Trivy Operator in-cluster), Verify (admission controller checks signatures). Miss any step and you have a gap: unsigned images, unscanned deployments, or drift between build-time and runtime state.
7. Base Image Hygiene¶
Reduce your attack surface before scanning finds problems:
# Bad: full OS image (hundreds of packages, huge attack surface)
FROM ubuntu:22.04
# Better: slim variant
FROM python:3.11-slim
# Best: distroless (almost nothing to exploit)
FROM gcr.io/distroless/python3-debian12
# Also good: Alpine (small but uses musl libc)
FROM alpine:3.19
# Compare image sizes and vulnerability counts
trivy image ubuntu:22.04 2>&1 | tail -1
# Total: 45 (UNKNOWN: 0, LOW: 30, MEDIUM: 10, HIGH: 4, CRITICAL: 1)
trivy image python:3.11-slim 2>&1 | tail -1
# Total: 12 (UNKNOWN: 0, LOW: 8, MEDIUM: 3, HIGH: 1, CRITICAL: 0)
trivy image gcr.io/distroless/python3-debian12 2>&1 | tail -1
# Total: 2 (UNKNOWN: 0, LOW: 2, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
8. Scanning Checklist¶
Pre-merge:
[ ] trivy image --exit-code 1 --severity CRITICAL
[ ] trivy config Dockerfile (check for misconfigurations)
[ ] No secrets in image layers (trivy fs --security-checks secret .)
Pre-deploy:
[ ] Image signed with cosign
[ ] SBOM generated and stored
[ ] No CRITICAL unfixed vulnerabilities
[ ] Base image updated within last 30 days
Ongoing:
[ ] Trivy Operator scanning running images weekly
[ ] New CVE alerts reviewed within 48 hours
[ ] Base images rebuilt monthly (picks up OS patches)
[ ] SBOM inventory maintained for incident response
Key Takeaway¶
Security scanning is a continuous process, not a one-time gate. Scan at build time in CI/CD (Trivy, exit-code 1 for CRITICAL), generate SBOMs for every release, run continuous scanning in production (Trivy Operator), sign images (cosign), and start with minimal base images. Prioritize vulnerabilities by exploitability and exposure, not just severity scores.
Wiki Navigation¶
Related Content¶
- Interview: CI Vuln Scan Failed (Scenario, L2) — Security Scanning
- Lab: Trivy Scan Remediation (CLI) (Lab, L1) — Security Scanning
- Runbook: CVE Response (Critical Vulnerability) (Runbook, L2) — Security Scanning
- Security Basics (Ops-Focused) (Topic Pack, L1) — Security Scanning
- Security Drills (Drill, L2) — Security Scanning
- Security Flashcards (CLI) (flashcard_deck, L1) — Security Scanning
- Skillcheck: Security (Expanded) (Assessment, L2) — Security Scanning