--- name: container-scanning description: Scan container images for vulnerabilities using Trivy, Grype, and cloud-native tools. Identify security issues in base images, packages, and configurations. Use when implementing container security, building secure images, or meeting compliance requirements. license: MIT metadata: author: devops-skills version: "1.0" --- # Container Scanning Scan container images for vulnerabilities and security misconfigurations. ## When to Use This Skill Use this skill when: - Building container images - Implementing container security gates - Scanning registry images - Meeting compliance requirements - Hardening container deployments ## Prerequisites - Container runtime (Docker, Podman) - Container images to scan - Scanning tool installation ## Tool Comparison | Tool | License | Speed | Features | |------|---------|-------|----------| | Trivy | OSS | Fast | Comprehensive, IaC | | Grype | OSS | Fast | Accurate, SBOM | | Clair | OSS | Medium | Registry integration | | Snyk Container | Commercial | Fast | Fix suggestions | | Docker Scout | Commercial | Fast | GitHub integration | ## Trivy ### Installation ```bash # Linux curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # macOS brew install trivy # Docker docker pull aquasec/trivy ``` ### Image Scanning ```bash # Scan local image trivy image myapp:latest # Scan remote image trivy image nginx:1.25 # JSON output trivy image --format json -o results.json myapp:latest # Filter by severity trivy image --severity HIGH,CRITICAL myapp:latest # Ignore unfixed vulnerabilities trivy image --ignore-unfixed myapp:latest # Exit code on vulnerability trivy image --exit-code 1 --severity CRITICAL myapp:latest ``` ### Filesystem Scanning ```bash # Scan project directory trivy fs /path/to/project # Scan Dockerfile trivy config Dockerfile # Scan Kubernetes manifests trivy config k8s/ ``` ### Configuration ```yaml # trivy.yaml timeout: 10m severity: - HIGH - CRITICAL ignore-unfixed: true exit-code: 1 vulnerability: type: - os - library scan: file-patterns: - "Dockerfile" - "*.yaml" ``` ### CI Integration ```yaml # GitHub Actions name: Container Security on: push: branches: [main] pull_request: jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Run Trivy uses: aquasecurity/trivy-action@master with: image-ref: 'myapp:${{ github.sha }}' format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH' exit-code: '1' - name: Upload results uses: github/codeql-action/upload-sarif@v3 with: sarif_file: 'trivy-results.sarif' ``` ## Grype ### Installation ```bash # Linux/macOS curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin # Homebrew brew install grype ``` ### Usage ```bash # Scan image grype myapp:latest # Scan from SBOM grype sbom:./sbom.json # JSON output grype myapp:latest -o json > results.json # Filter severity grype myapp:latest --fail-on high # Scan directory grype dir:/path/to/project ``` ### Configuration ```yaml # .grype.yaml check-for-app-update: false fail-on-severity: high output: "json" scope: "Squashed" ignore: - vulnerability: CVE-2023-12345 reason: "False positive" expires: "2024-12-31" ``` ## Docker Scout ### Usage ```bash # Enable Docker Scout docker scout quickview myapp:latest # Full CVE report docker scout cves myapp:latest # Compare images docker scout compare myapp:v1 myapp:v2 # Recommendations docker scout recommendations myapp:latest ``` ### CI Integration ```yaml - name: Docker Scout uses: docker/scout-action@v1 with: command: cves image: ${{ env.IMAGE_NAME }} sarif-file: scout-results.sarif summary: true ``` ## Registry Integration ### Amazon ECR ```bash # Enable scan on push aws ecr put-image-scanning-configuration \ --repository-name myapp \ --image-scanning-configuration scanOnPush=true # Get scan findings aws ecr describe-image-scan-findings \ --repository-name myapp \ --image-id imageTag=latest # Start manual scan aws ecr start-image-scan \ --repository-name myapp \ --image-id imageTag=latest ``` ### Azure ACR ```bash # Enable Defender for Containers az security pricing create \ --name Containers \ --tier Standard # View scan results in Azure Portal or: az acr repository show \ --name myregistry \ --image myapp:latest ``` ### Google Artifact Registry ```bash # Enable vulnerability scanning gcloud artifacts repositories update myrepo \ --location=us-central1 \ --enable-vulnerability-scanning # View vulnerabilities gcloud artifacts docker images describe \ us-central1-docker.pkg.dev/project/myrepo/myapp:latest \ --show-package-vulnerability ``` ## Admission Controllers ### OPA Gatekeeper ```yaml apiVersion: templates.gatekeeper.sh/v1beta1 kind: ConstraintTemplate metadata: name: k8sallowedrepos spec: crd: spec: names: kind: K8sAllowedRepos validation: openAPIV3Schema: properties: repos: type: array items: type: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8sallowedrepos violation[{"msg": msg}] { container := input.review.object.spec.containers[_] satisfied := [good | repo = input.parameters.repos[_]; good = startswith(container.image, repo)] not any(satisfied) msg := sprintf("container <%v> has an invalid image repo <%v>", [container.name, container.image]) } ``` ### Kyverno ```yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-image-scan spec: validationFailureAction: enforce rules: - name: check-vulnerabilities match: resources: kinds: - Pod verifyImages: - image: "*" attestations: - predicateType: cosign.sigstore.dev/attestation/vuln/v1 conditions: - all: - key: "{{ scanner.result.summary.criticalCount }}" operator: Equals value: "0" ``` ## Scanning Policies ### Policy Definition ```yaml # scan-policy.yaml policies: - name: critical-vulnerabilities description: Block images with critical CVEs severity: CRITICAL action: block - name: high-vulnerabilities description: Warn on high severity CVEs severity: HIGH action: warn max_count: 5 - name: age-policy description: Block images older than 30 days max_age_days: 30 action: block - name: base-image description: Only allow approved base images allowed_bases: - alpine:3.18 - ubuntu:22.04 - python:3.11-slim ``` ## Common Issues ### Issue: False Positives **Problem**: Scanner reports non-exploitable vulnerabilities **Solution**: Use ignore files, validate with context ### Issue: Slow Scans **Problem**: Scanning takes too long **Solution**: Use caching, scan incrementally, optimize image layers ### Issue: Unfixed Vulnerabilities **Problem**: No patch available for CVE **Solution**: Update base image, implement compensating controls ## Best Practices - Scan in CI/CD pipeline - Use minimal base images (Alpine, distroless) - Update base images regularly - Implement admission control - Track vulnerabilities over time - Set severity thresholds - Document accepted risks - Use multi-stage builds ## Related Skills - [docker-management](../../../devops/containers/docker-management/) - Container basics - [container-hardening](../../hardening/container-hardening/) - Security hardening - [kubernetes-hardening](../../hardening/kubernetes-hardening/) - K8s security