Strengthening Container Security with Anchore Grype: A Complete Guide for Cloud AI Platforms
⏱️ Estimated reading time: 15 min
Container security is increasingly critical on cloud AI platforms. Anchore Grype is an open-source vulnerability scanner with 10.1k stars on GitHub that rapidly detects security vulnerabilities in container images and filesystems. This guide covers everything from Grype’s core features to practical usage on cloud AI platforms.
Anchore Grype Overview
Core Features
- Broad support: Scans container images, filesystems, and SBOMs
- Multiple package managers: Java, Python, Go, JavaScript, Ruby, Rust, and more
- Real-time vulnerability DB: Integrates NVD, OSV, Chainguard, Alpine, and others
- Flexible output: JSON, Table, CycloneDX, SARIF, and more
- CI/CD integration: Supports GitHub Actions, GitLab CI, and Jenkins
Test Environment
Environment used for this guide:
- macOS Sequoia 15.0 (Darwin 25.0.0)
- Grype 0.94.0
- Go 1.24.4
- Syft 1.27.1 (SBOM generation)
- Supported DB schema: v6
Installation and Basic Setup
Installation on macOS
# Install via Homebrew
brew install grype
# Check version
grype version
Installation on Other Platforms
# Linux (script)
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# Run via Docker
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
anchore/grype:latest <image-name>
# Install via Go
go install github.com/anchore/grype@latest
Basic Usage
1. Scanning a Container Image
# Scan the Alpine image
grype alpine:latest
# Sample output
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY EPSS% RISK
libcrypto3 3.5.0-r0 apk CVE-2025-4575 Medium 6.42 < 0.1
libssl3 3.5.0-r0 apk CVE-2025-4575 Medium 6.42 < 0.1
busybox 1.37.0-r18 apk CVE-2024-58251 Low 3.55 < 0.1
2. Different Output Formats
# JSON format (for API integration)
grype alpine:latest -o json
# CycloneDX SBOM
grype alpine:latest -o cyclonedx
# SARIF (static analysis tool standard)
grype alpine:latest -o sarif
3. Filtering by Severity
# Show only Critical vulnerabilities
grype alpine:latest --fail-on critical
# Fail the build on High or above
grype alpine:latest --fail-on high
4. Scanning a Local Directory
# Scan the current directory
grype dir:.
# Scan a specific path
grype dir:/path/to/project
Cloud AI Platform Use Cases
1. CI/CD Pipeline Integration
GitHub Actions Workflow
name: Container Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker Image
run: docker build -t myapp:$`github.sha` .
- name: Run Grype Vulnerability Scan
uses: anchore/scan-action@v3
id: scan
with:
image: myapp:$`github.sha`
fail-build: true
severity-cutoff: high
- name: Upload Scan Results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: $
GitLab CI Configuration
stages:
- build
- security
- deploy
variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
security_scan:
stage: security
image: anchore/grype:latest
script:
- grype $IMAGE_NAME --fail-on high -o json > grype-report.json
- grype $IMAGE_NAME --fail-on high -o sarif > grype-report.sarif
artifacts:
reports:
dependency_scanning: grype-report.json
paths:
- grype-report.json
- grype-report.sarif
expire_in: 1 week
only:
- merge_requests
- main
2. Kubernetes Integration
Admission Controller Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: grype-policy
data:
policy.yaml: |
rules:
- name: no-critical-vulnerabilities
description: Block images with critical vulnerabilities
match:
- severity: Critical
action: deny
- name: warn-high-vulnerabilities
match:
- severity: High
action: warn
Pod Security Policy
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: grype-scanned-only
spec:
annotations:
security.alpha.kubernetes.io/grype-scanned: "required"
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
runAsUser:
rule: MustRunAsNonRoot
3. Automated Security Monitoring
Schedule-Based Scan Script
#!/bin/bash
# scheduled_security_scan.sh
REGISTRY="your-registry.com"
IMAGES=(
"ai-model-api:latest"
"data-processor:v1.2.0"
"ml-pipeline:prod"
"inference-service:stable"
)
REPORT_DIR="/var/log/grype-reports"
DATE=$(date +%Y%m%d-%H%M%S)
mkdir -p "$REPORT_DIR"
for image in "${IMAGES[@]}"; do
echo "Scanning $REGISTRY/$image..."
# Generate JSON report
grype "$REGISTRY/$image" -o json > "$REPORT_DIR/grype-$image-$DATE.json"
# Check Critical/High vulnerability counts
CRITICAL_COUNT=$(grype "$REGISTRY/$image" -o json | jq '.matches[] | select(.vulnerability.severity == "Critical") | .vulnerability.id' | wc -l)
HIGH_COUNT=$(grype "$REGISTRY/$image" -o json | jq '.matches[] | select(.vulnerability.severity == "High") | .vulnerability.id' | wc -l)
# Send Slack alert
if [ "$CRITICAL_COUNT" -gt 0 ] || [ "$HIGH_COUNT" -gt 5 ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"Security Alert: $image has $CRITICAL_COUNT critical and $HIGH_COUNT high vulnerabilities\"}" \
"$SLACK_WEBHOOK_URL"
fi
done
4. Cloud-Native Security Pipeline
Tekton Pipeline Configuration
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: secure-ai-deployment
spec:
params:
- name: image-url
- name: security-threshold
default: "high"
tasks:
- name: build-image
taskRef:
name: kaniko
params:
- name: IMAGE
value: $(params.image-url)
- name: security-scan
taskRef:
name: grype-scan
runAfter:
- build-image
params:
- name: IMAGE
value: $(params.image-url)
- name: FAIL_ON
value: $(params.security-threshold)
- name: deploy-if-secure
taskRef:
name: kubectl-deploy
runAfter:
- security-scan
when:
- input: $(tasks.security-scan.results.scan-status)
operator: in
values: ["passed"]
5. Security Metrics and Dashboard
Prometheus Metrics Collection
# grype_exporter.py
import subprocess
import json
import time
from prometheus_client import start_http_server, Gauge, Counter
# Define Prometheus metrics
vulnerability_count = Gauge('grype_vulnerabilities_total',
'Total vulnerabilities found',
['image', 'severity'])
scan_duration = Gauge('grype_scan_duration_seconds',
'Duration of vulnerability scan',
['image'])
scan_counter = Counter('grype_scans_total',
'Total number of scans performed',
['image', 'status'])
def scan_image(image_name):
start_time = time.time()
try:
# Run Grype scan
result = subprocess.run([
'grype', image_name, '-o', 'json'
], capture_output=True, text=True, check=True)
# Parse results
scan_data = json.loads(result.stdout)
vulnerabilities = scan_data.get('matches', [])
# Count by severity
severity_counts = {}
for vuln in vulnerabilities:
severity = vuln['vulnerability']['severity']
severity_counts[severity] = severity_counts.get(severity, 0) + 1
# Update metrics
for severity, count in severity_counts.items():
vulnerability_count.labels(image=image_name, severity=severity).set(count)
scan_duration.labels(image=image_name).set(time.time() - start_time)
scan_counter.labels(image=image_name, status='success').inc()
return True
except subprocess.CalledProcessError as e:
scan_counter.labels(image=image_name, status='failed').inc()
print(f"Scan failed for {image_name}: {e}")
return False
if __name__ == '__main__':
start_http_server(8000)
images_to_monitor = [
'ai-model-api:latest',
'data-processor:v1.2.0',
'ml-pipeline:prod'
]
while True:
for image in images_to_monitor:
scan_image(image)
time.sleep(3600) # Scan every hour
Grafana Dashboard Configuration
{
"dashboard": {
"title": "Container Security Dashboard",
"panels": [
{
"title": "Critical Vulnerabilities",
"type": "stat",
"targets": [
{
"expr": "sum(grype_vulnerabilities_total{severity=\"Critical\"})"
}
]
},
{
"title": "Vulnerability Trends",
"type": "graph",
"targets": [
{
"expr": "grype_vulnerabilities_total",
"legendFormat": " - "
}
]
},
{
"title": "Scan Performance",
"type": "graph",
"targets": [
{
"expr": "grype_scan_duration_seconds",
"legendFormat": ""
}
]
}
]
}
}
Advanced Configuration and Optimization
1. Vulnerability Ignore Rules
# .grype.yaml
ignore:
- vulnerability: CVE-2024-12345
fix-state: unknown
package:
name: example-package
version: "1.0.0"
- vulnerability: CVE-2024-67890
vex-status: not_affected
vex-justification: vulnerable_code_not_present
2. Custom Matching Rules
# .grype.yaml
match:
java:
using-cpes: true
python:
using-cpes: false
golang:
using-cpes: false
always-use-cpe-for-stdlib: true
3. External Source Integration
# .grype.yaml
external-sources:
enable: true
maven:
search-maven-upstream: true
base-url: 'https://search.maven.org/solrsearch/select'
rate-limit: 300ms
Zsh Alias Configuration
Useful aliases for convenience:
# Basic scans
alias grype-alpine="grype alpine:latest"
alias grype-ubuntu="grype ubuntu:latest"
# Output formats
alias grype-json="grype -o json"
alias grype-table="grype -o table"
# Severity-based filtering
alias grype-critical="grype --fail-on critical"
alias grype-high="grype --fail-on high"
# For CI/CD use
alias grype-ci="grype --fail-on high -o json"
# Container-specific scan function
grype-container() {
echo "Starting container security scan: $1"
grype "$1" -o table
grype "$1" -o json > "grype-scan-$(echo $1 | tr ':/' '-')-$(date +%Y%m%d-%H%M%S).json"
echo "Scan complete. JSON report saved."
}
Performance Optimization Strategies
1. Caching Strategy
# Set vulnerability DB cache location
export GRYPE_DB_CACHE_DIR="/var/cache/grype"
# Periodic DB update
grype db update
# Check DB status
grype db status
2. Parallel Scanning
#!/bin/bash
# parallel_scan.sh
images=(
"alpine:latest"
"ubuntu:20.04"
"node:18"
"python:3.9"
)
for image in "${images[@]}"; do
(
echo "Scanning $image..."
grype "$image" -o json > "scan-$(echo $image | tr ':/' '-').json"
echo "Completed $image"
) &
done
wait
echo "All scans completed!"
3. Aggregating Scan Results
# aggregate_results.py
import json
import glob
from collections import defaultdict
def aggregate_scan_results():
results = defaultdict(lambda: defaultdict(int))
for file_path in glob.glob("grype-scan-*.json"):
with open(file_path, 'r') as f:
data = json.load(f)
image_name = file_path.split('-')[2] # Extract image name
for match in data.get('matches', []):
severity = match['vulnerability']['severity']
results[image_name][severity] += 1
return dict(results)
# Example usage
summary = aggregate_scan_results()
for image, severities in summary.items():
print(f"\n{image}:")
for severity, count in severities.items():
print(f" {severity}: {count}")
Actual Test Results
Alpine Linux image scan results:
- Vulnerabilities found: 8
- Medium: 2 (OpenSSL-related)
- Low: 6 (BusyBox-related)
- Scan time: approximately 3 seconds
- Report size: 26KB (JSON)
Ubuntu 20.04 image scan results:
- Vulnerabilities found: 40+
- Critical: 1
- Medium: 5
- Low: 30+
- Scan time: approximately 8 seconds
Troubleshooting
Common Problem Fixes
# DB update issues
grype db update --verbose
# Network-related issues
grype --config timeout=30s alpine:latest
# Insufficient memory
export GRYPE_DB_MAX_MEMORY=2GB
Log Analysis
# Run in debug mode
grype alpine:latest -vv
# Save to a log file
grype alpine:latest --log-file grype.log
Conclusion
Anchore Grype is an essential tool for hardening container security on cloud AI platforms. As a validated open-source project with 10.1k stars, it provides a comprehensive security solution covering everything from CI/CD pipeline integration to production-stage monitoring.
Core Value
- Rapid vulnerability detection: Full image scan in seconds
- Automation-friendly: Seamless CI/CD pipeline integration
- Scalable architecture: Enterprise-scale support
- Practical output: Developer-friendly reports
Impact of Adoption
Security hardening: Block vulnerabilities before production deployment Developer productivity: Automated security validation Compliance: Adherence to security standards Operational efficiency: 24/7 automated monitoring
Security on cloud AI platforms is not optional. Start strengthening your container security today with Anchore Grype.
Additional Resources: