Implementing Image Scanning in CI/CD Pipelines
Implementing Image Scanning in CI/CD Pipelines
Integration of security scanning into CI/CD pipelines shifts security left, catching vulnerabilities before image distribution. Early scanning reduces remediation costs and prevents vulnerable images from reaching production. However, scanning adds build time and may block deployments, requiring careful implementation to balance security with development velocity.
Pipeline scanning strategies must accommodate different risk tolerances and deployment urgencies. Fail-fast approaches block builds immediately upon finding vulnerabilities. Threshold-based policies allow low-severity vulnerabilities while blocking critical ones. Asynchronous scanning permits deployment while scanning continues, suitable for development environments. Organizations should implement different strategies for different pipeline stages.
# Example: Multi-stage scanning pipeline with Trivy
# .gitlab-ci.yml
stages:
- build
- scan-quick
- test
- scan-deep
- deploy
variables:
IMAGE_NAME: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
TRIVY_VERSION: "0.45.0"
GRYPE_VERSION: "0.65.0"
# Build stage
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build
--build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
--build-arg VCS_REF=$CI_COMMIT_SHA
-t $IMAGE_NAME .
- docker push $IMAGE_NAME
only:
- branches
- merge_requests
# Quick scan for rapid feedback
security-scan-quick:
stage: scan-quick
image: aquasec/trivy:$TRIVY_VERSION
script:
# Quick scan for critical vulnerabilities only
- trivy image
--severity CRITICAL
--exit-code 1
--no-progress
--format table
--timeout 5m
$IMAGE_NAME
allow_failure: false
only:
- branches
- merge_requests
# Deep scan with multiple tools
security-scan-deep:
stage: scan-deep
image: alpine:latest
before_script:
- apk add --no-cache curl bash
# Install multiple scanners
- curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v$TRIVY_VERSION
- curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v$GRYPE_VERSION
script:
# Trivy comprehensive scan
- |
trivy image
--severity HIGH,CRITICAL,MEDIUM
--format json
--output trivy-report.json
--vuln-type os,library
--ignorefile .trivyignore
$IMAGE_NAME
# Grype scan for comparison
- |
grype $IMAGE_NAME
-o json
--file grype-report.json
--fail-on high
# Custom vulnerability analysis
- |
python3 <<EOF
import json
import sys
# Load scan results
with open('trivy-report.json', 'r') as f:
trivy_results = json.load(f)
with open('grype-report.json', 'r') as f:
grype_results = json.load(f)
# Analyze and correlate results
critical_vulns = []
high_vulns = []
for result in trivy_results.get('Results', []):
for vuln in result.get('Vulnerabilities', []):
if vuln['Severity'] == 'CRITICAL':
critical_vulns.append(vuln)
elif vuln['Severity'] == 'HIGH':
high_vulns.append(vuln)
# Generate summary report
print("=== Vulnerability Summary ===")
print(f"Critical: {len(critical_vulns)}")
print(f"High: {len(high_vulns)}")
# Check against policy
if len(critical_vulns) > 0:
print("\nBuild FAILED: Critical vulnerabilities found")
for vuln in critical_vulns[:5]: # Show first 5
print(f"- {vuln['VulnerabilityID']}: {vuln['PkgName']} {vuln['InstalledVersion']}")
sys.exit(1)
if len(high_vulns) > 10:
print("\nBuild FAILED: Too many high severity vulnerabilities")
sys.exit(1)
print("\nBuild PASSED: Within acceptable vulnerability thresholds")
EOF
artifacts:
reports:
container_scanning: trivy-report.json
paths:
- trivy-report.json
- grype-report.json
expire_in: 1 week
only:
- main
- develop
# License compliance scanning
license-scan:
stage: scan-deep
image: docker:latest
services:
- docker:dind
script:
# Extract and analyze licenses
- docker run --rm -v /var/run/docker.sock:/var/run/docker.sock
licensefinder/license_finder
/bin/bash -c "
cd /app &&
license_finder report --format json > licenses.json &&
license_finder action_items
"
# Check for problematic licenses
- |
if grep -E "(GPL|AGPL|SSPL)" licenses.json; then
echo "WARNING: Copyleft licenses detected"
exit 1
fi
artifacts:
paths:
- licenses.json
allow_failure: true
Scan result management requires processes for vulnerability assessment and remediation tracking. Not all vulnerabilities pose equal risk - environmental factors affect exploitability. Vulnerability management platforms help track remediation progress across multiple images and deployments. Integration with ticketing systems ensures accountability for vulnerability remediation.