Best Practice: Vulnerability & Patch Management
Kontext
Bekannte Schwachstellen (CVEs) sind der am einfachsten zu exploitierende Angriffsvektor – weil die Angriffsmethoden öffentlich dokumentiert sind und automatisierte Exploits existieren. Gleichzeitig ist Patch Management oft der am meisten vernachlässigte Sicherheitsbereich, weil es keine neuen Features liefert und Aufwand erzeugt.
Die Konsequenz: Log4Shell (CVE-2021-44228) war 12 Tage nach Public Disclosure in breiter Ausnutzung. Organisationen ohne strukturiertes Patch Management konnten betroffene Systeme nicht einmal identifizieren – geschweige denn patchen.
Typische Versäumnisse:
-
Container-Images basieren auf Ubuntu 18.04 LTS – seit Jahren End-of-Life
-
ECR Image Scanning deaktiviert – bekannte CVEs in Produktion unbemerkt
-
Kein SBOM-Prozess – bei neuen CVEs ist unklar, welche Systeme betroffen sind
-
Dependabot-PRs werden ignoriert – 200 offene Security-Updates
-
Kein SLA für Patches – Priorisierung erfolgt nach Gefühl, nicht nach Schweregrad
Zugehörige Controls
-
WAF-SEC-070 – Vulnerability & Patch Management
-
WAF-SEC-110 – Supply Chain Security & SBOM
Container-Sicherheit
ECR Image Scanning
Amazon ECR bietet zwei Scanning-Modelle:
| Modus | Technologie | Empfehlung |
|---|---|---|
Basic Scanning |
Clair; Open-Source CVE-Datenbank |
Mindestanforderung; nur für Low-Risk-Workloads |
Enhanced Scanning |
Amazon Inspector; AWS Security Hub Integration; kontinuierliches Scanning auch nach Push |
Pflicht für Produktions-Workloads; CVE-Findings in Security Hub sichtbar |
resource "aws_ecr_repository" "payment_service" {
name = "payment-service"
image_tag_mutability = "IMMUTABLE" # Tags können nicht überschrieben werden
image_scanning_configuration {
scan_on_push = true # Automatisches Scanning bei jedem Push
}
encryption_configuration {
encryption_type = "KMS"
kms_key = aws_kms_key.ecr_cmk.arn
}
tags = {
owner = "payment-team"
environment = "production"
workload = "payment-service"
}
}
# Lifecycle Policy: Alte Images automatisch löschen
resource "aws_ecr_lifecycle_policy" "payment_service" {
repository = aws_ecr_repository.payment_service.name
policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Behalte nur die letzten 10 Images pro Tag"
selection = {
tagStatus = "tagged"
countType = "imageCountMoreThan"
countNumber = 10
}
action = { type = "expire" }
},
{
rulePriority = 2
description = "Lösche untagged Images nach 7 Tagen"
selection = {
tagStatus = "untagged"
tagPrefixList = []
countType = "sinceImagePushed"
countUnit = "days"
countNumber = 7
}
action = { type = "expire" }
}
]
})
}
Trivy und Grype in der CI-Pipeline
Lokales Scanning vor dem Push verhindert, dass CVE-behaftete Images überhaupt ins Registry gelangen:
# GitHub Actions Workflow – Container Security Scanning
name: Container Build & Scan
on:
push:
paths: ['Dockerfile', 'src/**']
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker Image
run: docker build -t payment-service:${{ github.sha }} .
- name: Scan with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: payment-service:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1 # Pipeline schlägt bei CRITICAL/HIGH fehl
- name: Upload Trivy Results to Security Hub
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
- name: Scan with Grype (zweite Meinung)
run: |
grype payment-service:${{ github.sha }} \
--fail-on critical \
--output json \
> grype-results.json
Basis-Image-Strategie
-
Distroless Images verwenden – kein Shell, kein Paketmanager, minimale Angriffsfläche
-
Spezifische Tags pinnen – niemals
FROM ubuntu:latest; immerFROM ubuntu:22.04@sha256:abc123 -
Base Image Aktualisierung automatisieren – Renovate oder Dependabot für Dockerfiles konfigurieren
# Gutes Beispiel: Distroless, spezifischer Digest
FROM gcr.io/distroless/java21-debian12:nonroot@sha256:a1b2c3d4e5f6...
# Schlechtes Beispiel: Mutable Tag, viele Pakete
# FROM openjdk:latest
AMI-Patching-Strategie
Bake vs. In-Place
| Strategie | Vorgehen | Empfehlung |
|---|---|---|
Bake (Immutable) |
Neue AMI-Version mit Patches erstellen; Launch Template aktualisieren; Rolling Update der Auto Scaling Group; alte Instanzen terminieren |
Empfohlen für alle Produktions-Workloads; vollständige Reproduzierbarkeit; kein Konfigurationsdrift |
In-Place (SSM Patch Manager) |
Bestehende Instanzen via SSM Run Command patchen; Patch Groups konfigurieren; Maintenance Windows definieren |
Akzeptabel für Workloads, die keine Immutability unterstützen; höheres Drift-Risiko |
EC2 Image Builder für automatisierte AMI-Erstellung
resource "aws_imagebuilder_image_pipeline" "payment_base" {
name = "payment-service-base-ami"
image_recipe_arn = aws_imagebuilder_image_recipe.payment_base.arn
infrastructure_configuration_arn = aws_imagebuilder_infrastructure_configuration.main.arn
schedule {
schedule_expression = "cron(0 2 ? * SUN *)" # Jeden Sonntag 02:00 Uhr
pipeline_execution_start_condition = "EXPRESSION_MATCH_ONLY"
}
image_tests_configuration {
image_tests_enabled = true
timeout_minutes = 60
}
}
Dependency-Scanning und SBOM
Was ist ein SBOM?
Ein Software Bill of Materials (SBOM) ist eine vollständige Liste aller Software- Komponenten und deren Versionen in einem Artefakt. Bei einer neuen CVE-Meldung erlaubt ein SBOM sofortige Antwort auf die Frage: „Sind wir betroffen?"
Ohne SBOM dauert die Antwort auf diese Frage Tage – mit SBOM Minuten.
SBOM-Generierung in der CI-Pipeline
- name: Generiere SBOM mit Syft
run: |
syft payment-service:${{ github.sha }} \
-o spdx-json=sbom.spdx.json \
-o cyclonedx-json=sbom.cyclonedx.json
- name: Speichere SBOM als Artifact
uses: actions/upload-artifact@v4
with:
name: sbom-${{ github.sha }}
path: |
sbom.spdx.json
sbom.cyclonedx.json
retention-days: 365 # Compliance: SBOM für 1 Jahr aufbewahren
- name: Attestation mit Cosign (SLSA L2)
run: |
cosign attest \
--predicate sbom.spdx.json \
--type spdxjson \
payment-service:${{ github.sha }}
Dependabot und Renovate Konfiguration
# .github/dependabot.yml
version: 2
updates:
# Python-Abhängigkeiten
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
security-patches:
patterns: ["*"]
update-types: ["patch"]
# Docker-Basis-Images
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
CVE-Priorisierung
Das Priorisierungsmodell
Ein CVSS-Score allein ist kein ausreichendes Priorisierungskriterium. Die Kombination aus Score, Exploitability und Kontext liefert das korrekte Bild:
| CVE-Klasse | CVSS-Score | Patch-SLA | Priorisierungskriterien |
|---|---|---|---|
Critical |
9.0–10.0 |
< 24 Stunden |
CVSS ≥ 9.0 ODER aktiv ausgenutzt (CISA KEV) ODER RCE auf Produktionssystem |
High |
7.0–8.9 |
< 7 Tage |
CVSS 7.0–8.9 ODER erreichbarer Service exponiert ODER bekannte PoC-Exploits |
Medium |
4.0–6.9 |
< 30 Tage |
CVSS 4.0–6.9; nicht direkt erreichbar ODER erfordert lokalen Zugriff |
Low |
0.1–3.9 |
< 90 Tage |
Geringe Ausnutzungswahrscheinlichkeit; kein bekannter Exploit; erfordert Kombination |
Informational |
n/a |
Best Effort |
Konfigurationsempfehlungen; kein direkt ausnutzbarer Bug |
CISA Known Exploited Vulnerabilities (KEV)
Die CISA KEV-Liste enthält CVEs, die aktiv in Angriffen eingesetzt werden. CVEs auf dieser Liste sollten unabhängig vom CVSS-Score als Critical behandelt werden:
# Prüfe, ob aktuelle CVEs in der CISA KEV-Liste sind
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json \
| jq '.vulnerabilities[] | select(.cveID == "CVE-2021-44228")'
Monitoring und Messung
-
Amazon Inspector: Kontinuierliches Scanning von EC2, ECR und Lambda
-
AWS Security Hub: Aggregiert Inspector, GuardDuty, Macie Findings
-
GitHub Security Advisories: Dependabot-Alerts für Abhängigkeiten
-
Patch Compliance Dashboard: SSM Patch Manager Compliance-Berichte
-
Mean Time to Patch (MTTP): Metric pro Severity-Level – Ziel: SLA einhalten
-
wafpass:
wafpass check --pillar security --controls WAF-SEC-070,WAF-SEC-110