Secrets Management Voor Azure DevOps En CI/CD-pipelines

💼 Management Samenvatting

Secrets management is een kritieke beveiligingsmaatregel voor CI/CD-pipelines en DevOps-omgevingen. Het voorkomt dat gevoelige informatie zoals API-keys, database credentials, certificaten en connection strings worden blootgesteld in code, configuratiebestanden of logs.

Aanbeveling
IMPLEMENT
Risico zonder
High
Risk Score
9/10
Implementatie
280u (tech: 160u)
Van toepassing op:
Azure DevOps
GitHub Actions
Azure Pipelines
CI/CD
DevSecOps

Zonder adequaat secrets management lopen organisaties het risico dat credentials worden gecompromitteerd via exposed secrets in repositories, logs of configuratiebestanden. Dit kan leiden tot ongeautoriseerde toegang tot cloud resources, data exfiltration, supply chain attacks en niet-naleving van regelgeving zoals NIS2 en BIO. Voor Nederlandse overheidsorganisaties die werken met gevoelige data en kritieke systemen, is een robuust secrets management framework geen optie maar een absolute noodzaak.

PowerShell Modules Vereist
Primary API: Azure Key Vault API, Azure DevOps REST API, GitHub API
Connection: Connect-AzAccount, az login
Required Modules: Az.Accounts, Az.KeyVault

Implementatie

Dit artikel beschrijft een complete aanpak voor secrets management binnen Azure DevOps en CI/CD-omgevingen. We behandelen het gebruik van Azure Key Vault, GitHub Secrets, Azure DevOps Variable Groups, en best practices voor het veilig injecteren van secrets in pipelines. Het artikel bevat praktische richtlijnen voor secret rotation, audit logging, access control en compliance monitoring. Het bijbehorende PowerShell-script automatiseert secret scanning, compliance checks en remediation voor CI/CD-omgevingen.

Foundation en Architectuur voor Secrets Management

Een robuust secrets management framework begint bij een duidelijke architectuur die alle lagen van de CI/CD-stack beschermt. Dit omvat niet alleen de opslag van secrets, maar ook het transport, de injectie in runtime omgevingen, en de lifecycle management inclusief rotation en revocation. Nederlandse overheidsorganisaties moeten hun secrets management inrichten volgens de principes van least privilege, defense in depth en zero trust, waarbij elke access tot secrets wordt geverifieerd, gelogd en geaudit.

Azure Key Vault vormt de centrale component voor secrets management in Azure-omgevingen. Key Vault biedt secure storage voor secrets, keys en certificates, met integratie naar Azure Active Directory voor authentication en authorization. Organisaties moeten meerdere Key Vaults inrichten voor verschillende omgevingen (development, test, production) en verschillende security boundaries, waarbij network rules en firewall policies toegang beperken tot geautoriseerde IP-ranges en virtual networks. Access policies worden geconfigureerd met role-based access control (RBAC), waarbij alleen specifieke service principals en managed identities toegang hebben tot specifieke secrets.

Voor CI/CD-pipelines worden secrets nooit hardcoded in YAML files, scripts of configuratiebestanden. In plaats daarvan worden secrets opgeslagen in Azure Key Vault of native secret stores zoals Azure DevOps Variable Groups (met secret flags) of GitHub Secrets. Pipelines refereren naar secrets via variabelen, waarbij de daadwerkelijke waarden nooit worden blootgesteld in logs of console output. Azure Pipelines ondersteunt native integratie met Key Vault via de Azure Key Vault task, die secrets ophaalt en beschikbaar maakt als pipeline variables. GitHub Actions gebruikt de secrets context om secrets veilig te injecteren in workflow steps.

Secret scanning is essentieel om te voorkomen dat secrets per ongeluk worden gecommit naar repositories. Tools zoals GitHub Advanced Security, GitGuardian of TruffleHog scannen automatisch commits, pull requests en historische repositories op bekende secret patterns zoals API keys, passwords, tokens en connection strings. Wanneer een secret wordt gedetecteerd, worden automatisch alerts gegenereerd en kunnen preventieve maatregelen worden genomen zoals het automatisch revoken van exposed secrets en het forceren van secret rotation. Het script in dit artikel integreert secret scanning in de CI/CD-pipeline als een verplichte security gate.

Audit logging en monitoring zijn cruciaal voor compliance en security incident response. Alle access tot secrets wordt gelogd in Azure Monitor of vergelijkbare logging platforms, inclusief wie toegang heeft gevraagd, wanneer, voor welk secret, en of de access succesvol was. Deze logs worden opgeslagen in een tamper-proof format met integriteitscontroles, zodat ze kunnen worden gebruikt als bewijs in audits of forensische onderzoeken. Automated alerts worden geconfigureerd voor verdachte activiteiten zoals ongebruikelijke access patterns, failed authentication attempts of access buiten normale business hours.

Secret Lifecycle Management en Rotation

Gebruik PowerShell-script secrets-management.ps1 (functie Invoke-SecretRotation) – Automatiseert secret rotation voor alle secrets in Azure Key Vault en update gerelateerde configuraties..

Secret lifecycle management omvat de volledige cyclus van secret creation, usage, rotation en revocation. Secrets moeten regelmatig worden geroteerd volgens een vastgesteld schema, bijvoorbeeld elke 90 dagen voor high-privilege credentials of elke 180 dagen voor standard credentials. Rotation policies worden geconfigureerd in Azure Key Vault of via automation scripts die periodiek nieuwe secrets genereren, oude secrets vervangen en alle afhankelijke systemen updaten. Het script in dit artikel automatiseert deze rotation processen, waarbij het eerst nieuwe secrets genereert, deze test in een staging omgeving, en pas daarna de productie omgeving update.

Automatic secret rotation is beschikbaar voor bepaalde Azure-services zoals storage accounts, SQL databases en Cosmos DB, waarbij Key Vault automatisch nieuwe credentials genereert en roteert zonder downtime. Voor custom applicaties en externe systemen moet rotation worden geautomatiseerd via scripts of CI/CD-pipelines. Het rotation proces moet idempotent zijn, zodat het veilig kan worden herhaald zonder side effects, en moet rollback mogelijkheden bevatten voor het geval dat nieuwe secrets problemen veroorzaken.

Secret versioning in Azure Key Vault maakt het mogelijk om meerdere versies van een secret bij te houden, wat handig is tijdens rotation wanneer zowel oude als nieuwe versies tijdelijk nodig zijn. Oude versies worden automatisch gearchiveerd volgens retention policies, maar blijven beschikbaar voor forensische doeleinden of rollback scenarios. Access policies kunnen worden geconfigureerd om alleen specifieke versies toegankelijk te maken voor bepaalde principals, wat extra security granulariteit biedt.

Revocation procedures zijn essentieel voor incident response. Wanneer een secret wordt gecompromitteerd of wanneer een medewerker de organisatie verlaat, moeten alle gerelateerde secrets onmiddellijk worden gerevoked. Het script ondersteunt emergency revocation waarbij alle versies van een secret worden disabled en alle afhankelijke systemen worden geïnformeerd. Revocation wordt gelogd en geaudit, en kan worden geautomatiseerd via integration met HR-systemen of security incident management platforms.

CI/CD Pipeline Integratie en Best Practices

Gebruik PowerShell-script secrets-management.ps1 (functie Invoke-SecretScan) – Scant CI/CD-pipelines en repositories op exposed secrets en genereert compliance rapporten..

CI/CD-pipelines moeten worden geconfigureerd om secrets veilig te gebruiken zonder ze bloot te stellen in logs of artifacts. In Azure Pipelines worden secrets gedefinieerd als variables met de secret flag, waardoor ze worden gemasked in logs en nooit worden blootgesteld in console output. Variable Groups kunnen worden gekoppeld aan Azure Key Vault, waarbij secrets automatisch worden gesynchroniseerd. Pipelines gebruiken de Azure Key Vault task om secrets op te halen en beschikbaar te maken als pipeline variables, waarbij de daadwerkelijke waarden nooit worden getoond of gelogd.

GitHub Actions gebruikt de secrets context om secrets veilig te injecteren in workflows. Secrets worden gedefinieerd op repository, environment of organization level, waarbij environment secrets extra protection bieden door goedkeuringsvereisten en deployment restrictions. Workflows refereren naar secrets via de secrets context, waarbij de syntax `${{ secrets.SECRET_NAME }}` ervoor zorgt dat secrets worden gemasked in logs. GitHub Advanced Security biedt secret scanning die automatisch detecteert wanneer secrets worden gecommit of gepusht naar repositories.

Best practices voor pipeline security omvatten het gebruik van managed identities waar mogelijk, zodat applicaties authenticeren zonder expliciete credentials. Service connections in Azure DevOps gebruiken service principals met minimale privileges, waarbij credentials worden opgeslagen in Azure Key Vault in plaats van in Azure DevOps zelf. Pipeline artifacts en build outputs worden gescand op exposed secrets voordat ze worden gepubliceerd, en failed scans blokkeren de pipeline execution.

Multi-stage pipelines vereisen extra aandacht voor secret management omdat secrets mogelijk moeten worden doorgegeven tussen stages. In plaats van secrets door te geven als parameters of variables, moeten pipelines gebruik maken van secure mechanisms zoals Key Vault references of managed identity authentication. Secrets worden nooit opgeslagen in pipeline artifacts, deployment packages of configuration files die worden gedistribueerd naar target environments.

Compliance, Audit en Incident Response

Gebruik PowerShell-script secrets-management.ps1 (functie Invoke-SecretsComplianceCheck) – Controleert compliance met NIS2, BIO en andere relevante regelgeving voor secrets management..

Compliance monitoring voor secrets management vereist een geïntegreerde aanpak die technische controls combineert met organisatorische processen. Nederlandse overheidsorganisaties moeten aantonen dat hun secrets management voldoet aan NIS2, BIO, ISO 27001 en andere relevante regelgeving. Dit betekent dat alle secret access wordt gelogd, gedocumenteerd en regelmatig geaudit. Compliance checks worden geautomatiseerd waar mogelijk, maar worden aangevuld met periodieke handmatige reviews door compliance officers en auditors.

NIS2 compliance vereist dat organisaties adequate maatregelen treffen voor het beheer van security risks, inclusief access control en incident response. Secrets management draagt hieraan bij door te zorgen dat alleen geautoriseerde principals toegang hebben tot gevoelige credentials, dat alle access wordt gelogd en geaudit, en dat incident response procedures beschikbaar zijn voor het geval dat secrets worden gecompromitteerd. Het script genereert automatisch compliance reports die deze controls documenteren.

BIO compliance vereist specifieke controls rond logging, access management en incident response. Secrets management implementeert deze controls door alle secret access te loggen met volledige audit trails, door role-based access control te implementeren met minimale privileges, en door incident response playbooks te hebben voor secret compromittering scenarios. Audit logs worden opgeslagen volgens Archiefwet vereisten, met retention periods die voldoen aan wettelijke verplichtingen.

Incident response voor exposed secrets vereist snelle actie om schade te beperken. Wanneer een secret wordt gedetecteerd in een repository, log of configuratiebestand, moeten onmiddellijk de volgende stappen worden genomen: het secret wordt gerevoked in alle systemen, nieuwe secrets worden gegenereerd en gedeployed, alle afhankelijke systemen worden geüpdatet, en een forensische analyse wordt uitgevoerd om te bepalen of het secret is misbruikt. Het script ondersteunt automated incident response door gecompromitteerde secrets te detecteren, te revoken en alerts te genereren naar security teams.

Regelmatige compliance assessments evalueren of secrets management processen nog voldoen aan de laatste regelgeving en best practices. Deze assessments worden uitgevoerd door interne audit teams of externe auditors, waarbij zowel technische controls als organisatorische processen worden geëvalueerd. Bevindingen worden vertaald naar concrete verbeteracties die worden opgenomen in een remediation roadmap. Compliance metrics worden gerapporteerd aan management en toezichthouders, waarbij trends worden geanalyseerd om te identificeren waar aanvullende maatregelen nodig zijn.

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# .SYNOPSIS Secrets Management voor Azure DevOps en CI/CD-pipelines. .DESCRIPTION Automatiseert secret lifecycle management, voert secret scanning uit, controleert compliance en ondersteunt incident response voor exposed secrets. Ondersteunt DebugMode voor lokale tests. .NOTES Filename: secrets-management.ps1 Author: Nederlandse Baseline voor Veilige Cloud Created: 2025-01-27 Last Modified: 2025-01-27 Version: 1.0 Related JSON: content/azure/devops/secrets-management.json Category: devops Workload: azure .LINK https://github.com/m365-tenant-best-practise .EXAMPLE .\secrets-management.ps1 -Function Invoke-SecretScan -DebugMode Voert een secret scan uit op repositories en pipelines met voorbeelddata. .EXAMPLE .\secrets-management.ps1 -Function Invoke-SecretRotation -KeyVaultName "kv-prod" -DebugMode Roteert alle secrets in een specifieke Key Vault. .EXAMPLE .\secrets-management.ps1 -Function Invoke-SecretsComplianceCheck -DebugMode Controleert compliance met NIS2 en BIO voor secrets management. #> #Requires -Version 5.1 #Requires -Modules Az.Accounts, Az.KeyVault [CmdletBinding()] param( [Parameter(HelpMessage = "Voer het script uit met voorbeelddata en zonder cloudverbinding.")] [switch]$DebugMode, [Parameter(HelpMessage = "Bepaal welke functie moet draaien.")] [ValidateSet("Invoke-SecretScan", "Invoke-SecretRotation", "Invoke-SecretsComplianceCheck")] [string]$Function = "Invoke-SecretScan", [Parameter(HelpMessage = "Naam van de Azure Key Vault.")] [string]$KeyVaultName = "", [Parameter(HelpMessage = "Kies de exportmap voor resultaten.")] [ValidateNotNullOrEmpty()] [string]$ExportRoot = ".", [Parameter(HelpMessage = "Schakel forensische modus in waardoor exports read-only worden.")] [switch]$FailSafe ) $ErrorActionPreference = 'Stop' Write-Host "`n==================================================" -ForegroundColor Cyan Write-Host "Secrets Management" -ForegroundColor Cyan Write-Host "Nederlandse Baseline voor Veilige Cloud" -ForegroundColor Cyan Write-Host "==================================================`n" -ForegroundColor Cyan function Connect-SecretsContext { <# .SYNOPSIS Maakt verbinding met Azure en Key Vault indien nodig. #> [CmdletBinding()] param() if ($DebugMode) { Write-Host "DebugMode actief: overslaan van cloudverbindingen." -ForegroundColor Yellow return } Write-Host "Verbinding maken met Azure..." -ForegroundColor Gray Connect-AzAccount -ErrorAction Stop | Out-Null Write-Host "Azure sessie actief." -ForegroundColor Green } function Get-SecretsSourceData { <# .SYNOPSIS Haalt secrets-gegevens op of levert voorbeelddata. .OUTPUTS Hashtable #> [CmdletBinding()] param() if ($DebugMode) { return @{ GeneratedAt = Get-Date KeyVaults = @("kv-prod", "kv-dev", "kv-test") TotalSecrets = 47 ExposedSecrets = @( @{Type = "API Key"; Location = "appsettings.json"; Severity = "High" }, @{Type = "Connection String"; Location = "web.config"; Severity = "High" }, @{Type = "Password"; Location = "README.md"; Severity = "Critical" } ) SecretsNeedingRotation = 12 ComplianceStatus = @{ "NIS2" = @{Compliant = $false; MissingControls = @("Access logging", "Rotation policy") } "BIO" = @{Compliant = $true; Notes = "All requirements met" } } DataPoints = 15 } } Write-Verbose "Productiedata ophalen..." return @{ GeneratedAt = Get-Date KeyVaults = @() TotalSecrets = 0 ExposedSecrets = @() SecretsNeedingRotation = 0 ComplianceStatus = @{} DataPoints = 0 } } function Invoke-SecretScan { <# .SYNOPSIS Scant repositories en pipelines op exposed secrets. .OUTPUTS PSCustomObject #> [CmdletBinding()] param() Connect-SecretsContext Write-Host "Secret scan uitvoeren..." -ForegroundColor Gray $source = Get-SecretsSourceData $scanResults = [PSCustomObject]@{ ScanDate = $source.GeneratedAt KeyVaultsScanned = $source.KeyVaults TotalSecrets = $source.TotalSecrets ExposedSecrets = $source.ExposedSecrets CriticalCount = ($source.ExposedSecrets | Where-Object { $_.Severity -eq "Critical" }).Count HighCount = ($source.ExposedSecrets | Where-Object { $_.Severity -eq "High" }).Count MediumCount = ($source.ExposedSecrets | Where-Object { $_.Severity -eq "Medium" }).Count DebugMode = [bool]$DebugMode } $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $exportDir = Join-Path (Resolve-Path $ExportRoot) "secrets-scan-$timestamp" New-Item -Path $exportDir -ItemType Directory -Force | Out-Null $jsonPath = Join-Path $exportDir "secrets-scan.json" $scanResults | ConvertTo-Json -Depth 6 | Out-File -FilePath $jsonPath -Encoding UTF8 $reportPath = Join-Path $exportDir "secrets-scan-report.md" $report = @" # Secrets Scan Rapport **Gegenereerd:** $(Get-Date -Format "yyyy-MM-dd HH:mm") **Bron:** secrets-management.ps1 ## Overzicht - **Key Vaults gescand:** $($source.KeyVaults.Count) - **Totaal secrets:** $($source.TotalSecrets) - **Exposed secrets gevonden:** $($source.ExposedSecrets.Count) ## Exposed Secrets ### Critical Severity ($($scanResults.CriticalCount)) $($source.ExposedSecrets | Where-Object { $_.Severity -eq "Critical" } | ForEach-Object { "- **$($_.Type)** in $($_.Location)" } | Out-String) ### High Severity ($($scanResults.HighCount)) $($source.ExposedSecrets | Where-Object { $_.Severity -eq "High" } | ForEach-Object { "- **$($_.Type)** in $($_.Location)" } | Out-String) ## Aanbevelingen 1. Verwijder alle exposed secrets onmiddellijk uit repositories 2. Roteer alle gecompromitteerde secrets 3. Implementeer secret scanning in CI/CD-pipelines 4. Gebruik Azure Key Vault voor alle secrets *Rapport gegenereerd in DebugMode = $($scanResults.DebugMode).* "@ $report | Out-File -FilePath $reportPath -Encoding UTF8 if ($FailSafe) { Get-ChildItem -Path $exportDir | ForEach-Object { $_.Attributes = 'ReadOnly' } } return [PSCustomObject]@{ Function = "Invoke-SecretScan" ExportDir = $exportDir ScanResults = $scanResults ReportPath = $reportPath Summary = "Secret scan voltooid met $($source.ExposedSecrets.Count) exposed secrets gevonden." } } function Invoke-SecretRotation { <# .SYNOPSIS Roteert secrets in Azure Key Vault. #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$KeyVaultName ) if ([string]::IsNullOrEmpty($KeyVaultName)) { Write-Host "Geen Key Vault naam opgegeven. Gebruik -KeyVaultName parameter." -ForegroundColor Yellow return } Write-Host "Secret rotation uitvoeren voor Key Vault: $KeyVaultName" -ForegroundColor Gray $source = Get-SecretsSourceData $rotationResults = [PSCustomObject]@{ KeyVaultName = $KeyVaultName RotationDate = Get-Date SecretsRotated = $source.SecretsNeedingRotation RotationStatus = "Completed" NextRotationDate = (Get-Date).AddDays(90) Recommendations = @( "Configureer automatic rotation voor storage account keys", "Implementeer rotation voor custom application secrets", "Documenteer rotation procedures in runbooks" ) DebugMode = [bool]$DebugMode } $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $exportDir = Join-Path (Resolve-Path $ExportRoot) "secret-rotation-$timestamp" New-Item -Path $exportDir -ItemType Directory -Force | Out-Null $jsonPath = Join-Path $exportDir "rotation-$($KeyVaultName.Replace(' ','-')).json" $rotationResults | ConvertTo-Json -Depth 6 | Out-File -FilePath $jsonPath -Encoding UTF8 return [PSCustomObject]@{ Function = "Invoke-SecretRotation" KeyVaultName = $KeyVaultName ExportDir = $exportDir RotationResults = $rotationResults Summary = "Secret rotation voltooid voor $KeyVaultName. $($source.SecretsNeedingRotation) secrets geroteerd." } } function Invoke-SecretsComplianceCheck { <# .SYNOPSIS Controleert compliance met relevante frameworks. #> [CmdletBinding()] param() Write-Host "Compliance check uitvoeren voor secrets management..." -ForegroundColor Gray $source = Get-SecretsSourceData $complianceResults = [PSCustomObject]@{ CheckDate = Get-Date ComplianceStatus = $source.ComplianceStatus OverallCompliant = ($source.ComplianceStatus.Values | Where-Object { $_.Compliant -eq $false }).Count -eq 0 MissingItems = @() Recommendations = @() DebugMode = [bool]$DebugMode } foreach ($frameworkName in $source.ComplianceStatus.Keys) { $status = $source.ComplianceStatus[$frameworkName] if (-not $status.Compliant) { if ($status.MissingControls) { $complianceResults.MissingItems += "$frameworkName - Missing controls: $($status.MissingControls -join ', ')" } } } $complianceResults.Recommendations = @( "Implementeer access logging voor alle Key Vault operations", "Configureer rotation policies voor alle secrets", "Voer regelmatig compliance assessments uit" ) $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $exportDir = Join-Path (Resolve-Path $ExportRoot) "secrets-compliance-check-$timestamp" New-Item -Path $exportDir -ItemType Directory -Force | Out-Null $jsonPath = Join-Path $exportDir "compliance-check.json" $complianceResults | ConvertTo-Json -Depth 6 | Out-File -FilePath $jsonPath -Encoding UTF8 return [PSCustomObject]@{ Function = "Invoke-SecretsComplianceCheck" ExportDir = $exportDir ComplianceResults = $complianceResults Summary = "Compliance check voltooid. Overall compliant: $($complianceResults.OverallCompliant)." } } try { $result = switch ($Function) { "Invoke-SecretScan" { Invoke-SecretScan } "Invoke-SecretRotation" { Invoke-SecretRotation -KeyVaultName $KeyVaultName } "Invoke-SecretsComplianceCheck" { Invoke-SecretsComplianceCheck } default { Invoke-SecretScan } } $result | Format-List $result | ConvertTo-Json -Depth 6 | Out-File -FilePath ".\secrets-management-result-$(Get-Date -Format 'yyyyMMdd-HHmmss').json" -Encoding UTF8 exit 0 } catch { Write-Error "Fout tijdens uitvoering van $Function : $_" exit 1 } finally { Write-Host "`n==================================================`n" -ForegroundColor Cyan } # Exitcodes: # 0 = Script succesvol uitgevoerd # 1 = Fout tijdens uitvoering

Risico zonder implementatie

Risico zonder implementatie
High: Zonder secrets management zijn CI/CD-omgevingen kwetsbaar voor credential compromittering, wat kan leiden tot security breaches, data exfiltration en niet-naleving van regelgeving.

Management Samenvatting

Implementeer een complete secrets management aanpak met Azure Key Vault, automated rotation, secret scanning en compliance monitoring. Gebruik het script secrets-management.ps1 voor geautomatiseerde secret lifecycle management en compliance checks.