⏱️ 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: