Docker Image Security Scanning
Trivy, Cosign, admission controllers.
Container Image Security Scanning
Container images inherit vulnerabilities from their base images and dependencies. A single unpatched CVE can expose your entire infrastructure. Integrating security scanning into your CI/CD pipeline catches vulnerabilities before they reach production.
Why Scanning Matters
- 80% of container images contain at least one known vulnerability
- Base images like
ubuntu:22.04may have 50+ CVEs at any given time - Application dependencies (npm, pip, Maven) introduce additional risk
- Compliance frameworks (SOC 2, ISO 27001) require vulnerability management
Trivy: The Go-To Scanner
Trivy is the most popular open-source scanner, supporting OS packages, language dependencies, and IaC misconfigurations:
# Scan a local image
trivy image myapp:latest
# Scan with severity filter
trivy image --severity HIGH,CRITICAL myapp:latest
# Output as JSON for CI/CD processing
trivy image --format json --output results.json myapp:latest
# Fail CI if critical vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL myapp:latestGitHub Actions Integration
name: Build and Scan
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
- name: Upload scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarifImage Signing with Cosign
Verify that images in production came from your CI/CD pipeline:
# Sign an image after building
cosign sign --key cosign.key myregistry/myapp:v1.0.0
# Verify before deployment
cosign verify --key cosign.pub myregistry/myapp:v1.0.0Admission Controllers
Prevent unscanned or unsigned images from being deployed:
# Using Kyverno policy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-signature
spec:
validationFailureAction: enforce
rules:
- name: verify-signature
match:
resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "myregistry/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----Scanning Strategy
- Build time — Scan during CI/CD, fail pipeline on CRITICAL CVEs
- Registry — Enable automatic scanning in ECR/GCR (catches new CVEs in existing images)
- Runtime — Use Falco or Sysdig for runtime threat detection
- Scheduled — Re-scan all production images weekly for newly discovered CVEs
Reducing Vulnerabilities
- Use minimal base images — Alpine, distroless, or scratch
- Multi-stage builds — Remove build tools from production images
- Pin versions — Use specific tags and digests, not
:latest - Update regularly — Rebuild images weekly to pick up base image security patches
- Remove unnecessary packages — Every package is a potential attack vector
Eazy SaaS Tip: We integrate Trivy scanning into every CI/CD pipeline we build, with Slack notifications for new CRITICAL CVEs. Combined with weekly base image updates, this keeps our clients' container fleet vulnerability-free.