Supply Chain Security für Azure DevOps: SBOMs, Signing und Attestation
Ein praxisorientierter Leitfaden zur Absicherung der Software Supply Chain in Azure DevOps mit SBOM-Generierung, Artifact Signing, SLSA-Framework-Compliance und Dependency Scanning.
Der SolarWinds-Angriff hat gezeigt, dass die Kompromittierung einer einzigen Build-Pipeline auf Tausende von Organisationen kaskadieren kann. Supply Chain Security ist nicht mehr optional — sie ist eine grundlegende Anforderung für jede Software-Organisation. Regulierungsbehörden (DORA, NIS2, US Executive Order 14028) schreiben nun spezifische Supply-Chain-Kontrollen vor, einschließlich SBOMs, Provenance Attestation und Dependency Management.
Dieser Leitfaden behandelt die praktische Implementierung von Supply-Chain-Security-Kontrollen in Azure DevOps, mit Pipeline-YAML-Beispielen, die Sie an Ihre Umgebung anpassen können.
Das Supply-Chain-Bedrohungsmodell
Bevor Sie Kontrollen implementieren, verstehen Sie, wogegen Sie sich verteidigen:
Dependency Confusion: Ein Angreifer veröffentlicht ein bösartiges Paket mit demselben Namen wie Ihr internes Paket in einer öffentlichen Registry. Wenn Ihr Build-System zuerst öffentliche Registries prüft, zieht es die bösartige Version.
Kompromittierte Upstream-Abhängigkeiten: Eine legitime Open-Source-Bibliothek wird kompromittiert (durch Übernahme des Maintainer-Accounts, bösartigen Pull Request oder Typosquatting). Ihr Build-System zieht die kompromittierte Version.
Build-System-Kompromittierung: Ein Angreifer erhält Zugang zu Ihrer Build-Pipeline und injiziert bösartigen Code während des Build-Prozesses, nach dem Source-Code-Review aber vor der Artefakt-Erstellung.
Artifact Tampering: Ein erstelltes Artefakt wird nach der Erstellung, aber vor dem Deployment modifiziert. Ohne Signing und Verification bleibt die Modifikation unerkannt.
SBOM-Generierung
CycloneDX in Azure DevOps Pipelines
CycloneDX bietet Tooling für die meisten Ökosysteme. Hier ist eine Pipeline-Konfiguration, die SBOMs für eine .NET-Anwendung generiert:
# azure-pipelines.yml — SBOM-Generierungsstufe
stages:
- stage: Build
jobs:
- job: BuildAndSBOM
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '8.x'
- script: |
dotnet restore
dotnet build --configuration Release --no-restore
displayName: 'Anwendung bauen'
- script: |
dotnet tool install --global CycloneDX
dotnet CycloneDX $(Build.SourcesDirectory)/src/MyApp.csproj \
--output $(Build.ArtifactStagingDirectory) \
--filename sbom.cyclonedx.json \
--json \
--include-project-references \
--set-version $(Build.BuildNumber)
displayName: 'CycloneDX SBOM generieren'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/sbom.cyclonedx.json'
ArtifactName: 'sbom'Für Container-Images verwenden Sie Syft, das umfassende SBOMs einschließlich OS-Packages erstellt:
- script: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
syft $(containerRegistry)/$(imageRepository):$(tag) \
--output cyclonedx-json=$(Build.ArtifactStagingDirectory)/container-sbom.cyclonedx.json
displayName: 'Container-SBOM generieren'SBOM-Speicherung und -Abfrage
Speichern Sie SBOMs neben den Artefakten, die sie beschreiben. Für Container-Images hängen Sie das SBOM als OCI Artifact Reference an:
- script: |
oras attach $(containerRegistry)/$(imageRepository):$(tag) \
--artifact-type application/vnd.cyclonedx+json \
$(Build.ArtifactStagingDirectory)/container-sbom.cyclonedx.json
displayName: 'SBOM an Container-Image anhängen'Für abfragbares Vulnerability Tracking über alle SBOMs integrieren Sie diese in Dependency-Track oder GUAC (Graph for Understanding Artifact Composition). Dies ermöglicht die Beantwortung von: "Welche unserer deployed Anwendungen verwenden log4j Version X?"
Artifact Signing
Container Image Signing mit Notation
Notation (vom Notary Project) ist das empfohlene Signing-Tool für OCI Artifacts in Azure-Umgebungen:
- stage: Sign
dependsOn: Build
jobs:
- job: SignArtifacts
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
# Notation installieren
curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.1.0/notation_1.1.0_linux_amd64.tar.gz
tar xzf notation.tar.gz -C /usr/local/bin notation
# Azure Key Vault Plugin installieren
notation plugin install --url https://github.com/Azure/notation-azure-kv/releases/download/v1.2.0/notation-azure-kv_1.2.0_linux_amd64.tar.gz
# Container-Image mit Key-Vault-Zertifikat signieren
notation sign $(containerRegistry)/$(imageRepository):$(tag) \
--plugin azure-kv \
--id $(signingKeyId) \
--plugin-config self_signed=false
displayName: 'Container-Image mit Notation signieren'
env:
AZURE_CLIENT_ID: $(servicePrincipalId)
AZURE_TENANT_ID: $(tenantId)
AZURE_CLIENT_SECRET: $(servicePrincipalKey)Das Signing-Zertifikat sollte in Azure Key Vault gespeichert sein mit:
- HSM-gesichertem Key (Key Vault Premium oder Managed HSM)
- Zugriff beschränkt auf den Build-Service-Principal
- Automatisierte Zertifikatsrotation mit 12-monatiger Gültigkeit
Signaturverifikation beim Deployment
Verifizieren Sie Signaturen vor dem Deployment:
- stage: Deploy
dependsOn: Sign
jobs:
- job: VerifyAndDeploy
steps:
- script: |
notation verify $(containerRegistry)/$(imageRepository):$(tag) \
--trust-policy ./trust-policy.json \
--trust-store ./trust-store
if [ $? -ne 0 ]; then
echo "##vso[task.logissue type=error]Signaturverifikation fehlgeschlagen. Deployment abgebrochen."
exit 1
fi
displayName: 'Container-Signatur verifizieren'SLSA Framework Compliance
SLSA Level 1: Provenance
Generieren Sie Build Provenance, die dokumentiert, wie ein Artefakt gebaut wurde:
- script: |
cat > $(Build.ArtifactStagingDirectory)/provenance.json << PROVENANCE
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "$(containerRegistry)/$(imageRepository)",
"digest": { "sha256": "$(imageDigest)" }
}
],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": {
"buildType": "https://dev.azure.com/pipeline/v1",
"externalParameters": {
"repository": "$(Build.Repository.Uri)",
"ref": "$(Build.SourceBranch)"
}
},
"runDetails": {
"builder": {
"id": "https://dev.azure.com/$(System.TeamFoundationCollectionUri)"
},
"metadata": {
"invocationId": "$(Build.BuildUri)",
"startedOn": "$(System.PipelineStartTime)"
}
}
}
}
PROVENANCE
displayName: 'SLSA Provenance generieren'SLSA Level 2: Hosted Build Service
Azure DevOps Hosted Agents erfüllen die SLSA-Level-2-Anforderung eines gehosteten Build Service. Stellen Sie sicher:
- Alle Production-Builds laufen auf Microsoft-hosted Agents (nicht self-hosted)
- Pipeline-Definitionen sind in der Versionskontrolle gespeichert (YAML Pipelines, nicht Classic Editor)
- Build Logs werden für die Compliance-Aufbewahrungsfrist aufbewahrt
SLSA Level 3: Hardened Build Platform
Level 3 erfordert:
- Nicht fälschbare Provenance: Verwenden Sie Azure DevOps Service Connections mit Workload Identity Federation
- Isolierte Builds: Jeder Build läuft in einer frischen, ephemeren Umgebung (Hosted Agents bieten dies)
- Parameterlose Builds: Das Pipeline-YAML definiert den Build vollständig
- Fixierte Abhängigkeiten: Alle Abhängigkeiten referenzieren exakte Versionen oder Digests
Dependency Scanning und Management
Azure Artifacts als Private Registry
Konfigurieren Sie Azure Artifacts Feeds mit Upstream Sources als Proxy für öffentliche Registries:
<!-- nuget.config — Azure Artifacts Feed mit Upstream verwenden -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="MyOrgFeed" value="https://pkgs.dev.azure.com/myorg/_packaging/approved-packages/nuget/v3/index.json" />
</packageSources>
</configuration>Dependency Scanning in Pipelines
Integrieren Sie Dependency Scanning als Build Gate:
- task: AdvancedSecurity-Dependency-Scanning@1
displayName: 'Abhängigkeiten auf Schwachstellen scannen'
# Oder mit Snyk
- script: |
npx snyk test --severity-threshold=high --json > snyk-results.json
if [ $? -ne 0 ]; then
echo "##vso[task.logissue type=error]Hohe oder kritische Schwachstellen gefunden"
exit 1
fi
displayName: 'Snyk Dependency Scan'Die sichere Pipeline: Das Gesamtbild
Eine vollständige sichere Pipeline-Stufenabfolge:
- Source — Code aus der Versionskontrolle mit Branch Protection und erforderlichen Reviews
- Dependencies — Aufgelöst aus dem Private Feed mit Upstream-Proxy, gescannt auf Schwachstellen
- Build — Ausgeführt auf Hosted Agents, SBOM parallel zu Artefakten generiert
- Test — Unit-, Integrations- und Security-Tests (SAST, DAST)
- Sign — Artefakte signiert mit Key-Vault-gesichertem Zertifikat
- Attest — SLSA Provenance generiert und angehängt
- Store — Artefakte in Registry gepusht mit SBOM und Provenance
- Verify — Signatur und Provenance vor Deployment verifiziert
- Deploy — Admission Controller verifiziert Signatur vor Container-Ausführung
Jeder Schritt produziert Evidenz, die in Ihr Compliance-Reporting und Ihren Audit Trail einfließt.
Fazit
Supply Chain Security ist kein einzelnes Tool oder Prozess — es ist eine geschichtete Verteidigung, die von Dependency Management über Build-Integrität bis zur Deployment-Verifikation reicht. Die hier beschriebenen Kontrollen entsprechen SLSA, DORA, NIS2 und dem NIST Secure Software Development Framework.
Beginnen Sie mit SBOM-Generierung und Dependency Scanning — diese bieten sofortige Sichtbarkeit. Fügen Sie dann Artifact Signing und Provenance hinzu, um in Richtung SLSA Level 3 zu arbeiten.
Wenn Sie Hilfe bei der Konzeption und Implementierung einer sicheren Software Supply Chain für Ihre Azure DevOps-Umgebung benötigen, kontaktieren Sie uns unter mbrahim@conceptualise.de. Wir helfen Engineering-Teams, Supply Chain Security in ihre Pipelines einzubauen, ohne die Developer Velocity zu zerstören.
Themen