Terug naar overzicht
Security

Stop met het Opslaan van Secrets in je CI/CD Pipelines: Workload Identity Federation met Azure DevOps

Stop met het Opslaan van Secrets in je CI/CD Pipelines: Workload Identity Federation met Azure DevOps

Het Geheime Probleem met Secrets

Elke CI/CD-pipeline moet communiceren met cloudresources—deployen naar Azure, container images pushen, secrets lezen uit Key Vault. Jarenlang was het standaardantwoord simpel en gevaarlijk: maak een service principal aan, genereer een client secret, plak het als een pipeline-variabele en klaar.

Dat secret staat nu in je pipeline-configuratie, mogelijk in je repository-geschiedenis, en zeker op elke build agent die de job ooit heeft uitgevoerd. Het verloopt niet automatisch. Het heeft geen binding met de identiteit van de pipeline die het gebruikt. En als het lekt—en secrets lekken—weet je het vaak pas als de schade al is aangericht.

Microsoft heeft een beter antwoord: Workload Identity Federation. Geen secrets opgeslagen, geen rotatieproblemen. Een cryptografisch verifieerbare identiteit voor je pipeline, ondersteund door Azure Entra ID (voorheen Azure Active Directory).

Hoe We Hier Kwamen: Een Korte Geschiedenis van Credentials

Om de oplossing te begrijpen, helpt het de evolutie van het probleem te kennen.

Fase 1: Gebruikersnaam en Wachtwoord

De oorspronkelijke aanpak. Een serviceaccount met een gebruikersnaam en wachtwoord, opgeslagen als pipeline-secrets. Eenvoudig in te stellen, rampzalig te onderhouden. Wachtwoordrotatie breekt pipelines. Wachtwoorden delen tussen teams elimineert auditeerbaarheid. Één gecompromitteerde build agent stelt elke service bloot waartoe dat account toegang had.

Fase 2: Client Secrets (App Registraties)

Azure introduceerde App Registraties met client secrets als een stap vooruit. Je maakt een service principal aan, kent het een rol toe op je Azure-resources, genereert een client secret en slaat het op in je pipeline als AZURE_CLIENT_SECRET. Beter dan wachtwoorden—het is gebonden aan een specifieke applicatie-identiteit met specifieke machtigingen. Maar je slaat nog steeds een langlevende credential op die handmatig geroteerd moet worden, en er is geen manier om te verifiëren dat de entiteit die dat secret presenteert daadwerkelijk je Azure DevOps-pipeline is.

Fase 3: Azure Key Vault

De logische volgende stap: stop met het opslaan van secrets in pipeline-variabelen en haal ze op uit Key Vault tijdens runtime. Dit verbetert het secretsbeheer aanzienlijk—gecentraliseerde rotatie, auditlogs, toegangsbeleid. Maar er is een addertje: om toegang te krijgen tot Key Vault heeft je pipeline nog steeds een credential nodig. Je hebt het probleem verplaatst, niet opgelost. Je hebt een secret nodig om de secrets te krijgen.

Fase 4: Workload Identity Federation

Het moderne antwoord. Je Azure DevOps-pipeline presenteert een kortlevend, cryptografisch ondertekend token dat is uitgegeven door Azure DevOps zelf. Azure Entra ID verifieert dit token aan de hand van een vooraf geconfigureerde vertrouwensrelatie. Als het token overeenkomt—de juiste organisatie, het juiste project, de juiste pipeline—wordt toegang verleend. Er wordt nooit een secret opgeslagen of verzonden. De credential kan niet worden gerepliceerd of gestolen omdat deze alleen bestaat voor de duur van de job.

Aanpak Opgeslagen Secret? Rotatie Vereist? Pipeline-Gebonden?
Gebruikersnaam/Wachtwoord Ja Handmatig Nee
Client Secret Ja Handmatig (1-2 jaar) Nee
Key Vault + Secret Ja (bootstrap secret) Gedeeltelijk geautomatiseerd Nee
Workload Identity Federation Nee Geen Ja

Hoe Workload Identity Federation Werkt

De technische basis is de OpenID Connect (OIDC)-standaard. Azure DevOps fungeert als een identity provider (IdP) die ondertekende JWT-tokens kan uitgeven voor pipeline-runs. Azure Entra ID, geconfigureerd om Azure DevOps te vertrouwen als externe IdP, valideert deze tokens.

De stroom ziet er als volgt uit:

  1. Je pipeline-job start op een Azure DevOps-agent.
  2. De Azure DevOps-service geeft een kortlevend OIDC-token uit voor die specifieke job, ondertekend met de private sleutel van Azure DevOps.
  3. Je pipeline-taak presenteert dit token aan het token-eindpunt van Azure Entra ID.
  4. Entra ID verifieert de handtekening van het token met behulp van de publieke sleutels van Azure DevOps (opgehaald uit het OIDC discovery-document).
  5. Entra ID controleert de claims van het token aan de hand van de geconfigureerde Federated Credential op je app-registratie—komen de issuer, subject en audience overeen?
  6. Als alles overeenkomt, geeft Entra ID een toegangstoken uit voor de identiteit van je app-registratie.
  7. Je pipeline gebruikt dat toegangstoken om te communiceren met Azure-resources.

Het token dat Azure DevOps uitgeeft is geldig voor minuten, niet maanden. Het bevat claims die precies identificeren welke organisatie, welk project en welke pipeline het heeft gegenereerd. Je kunt het niet buiten die specifieke pipeline-context gebruiken en je kunt het niet opnieuw afspelen nadat het is verlopen.

Stap voor Stap Instellen

Er zijn twee manieren om workload identity federation voor Azure DevOps te configureren: via de Azure Portal voor volledige controle, of Azure DevOps dit automatisch laten regelen wanneer je een serviceverbinding aanmaakt. We behandelen eerst de handmatige aanpak—die geeft je een volledig begrip van wat er gebeurt.

Stap 1: Een App-Registratie Aanmaken in Entra ID

Ga in de Azure Portal naar Microsoft Entra ID → App-registraties → Nieuwe registratie. Geef het een betekenisvolle naam zoals sp-azuredevops-myproject. De redirect-URI is niet nodig voor dit scenario.

Noteer de Toepassings-ID (client) en de Map-ID (tenant). Je hebt deze later nodig.

Stap 2: Azure-Rollen Toewijzen

Je app-registratie heeft machtigingen nodig voor wat je pipeline moet doen. Ga naar de Azure-resource (abonnement, resourcegroep of specifieke resource) en ga naar Toegangsbeheer (IAM) → Roltoewijzing toevoegen.

Selecteer de juiste rol. Voor implementaties naar Azure App Service heb je mogelijk Contributor nodig. Voor het pushen naar Azure Container Registry heb je AcrPush nodig. Volg het principe van minimale bevoegdheden—wijs alleen toe wat de pipeline daadwerkelijk nodig heeft, zo beperkt mogelijk in scope.

# Azure CLI gebruiken om een rol toe te wijzen
az role assignment create \
  --assignee "" \
  --role "Contributor" \
  --scope "/subscriptions//resourceGroups/"

Stap 3: Een Federated Credential Configureren

Dit is de sleutelstap. Ga naar je App-registratie → Certificaten en secrets → Federatieve credentials → Credential toevoegen.

Selecteer Azure DevOps als het federatieve credential-scenario. Je configureert:

  • Organisatie: De naam van je Azure DevOps-organisatie (bijv. mijnbedrijf)
  • Project: De naam van je Azure DevOps-project
  • Entiteitstype: Branch, Tag, Pull Request of Environment
  • Ref: Voor een branch-entiteitstype, de branchnaam (bijv. main of refs/heads/main)

De combinatie van deze velden vormt de subject claim die Entra ID valideert. Een credential voor mijnbedrijf/mijnproject/refs/heads/main werkt alleen wanneer geactiveerd door de main-branch van dat specifieke project in die specifieke organisatie.

Je kunt meerdere federatieve credentials aanmaken voor dezelfde app-registratie—één voor main, één voor release/*, één voor de production-omgeving. Dit geeft je gedetailleerde controle over welke pipeline-contexten welke identiteit kunnen aannemen.

// De resulterende federatieve credential-configuratie
{
  "name": "azuredevops-myproject-main",
  "issuer": "https://vstoken.dev.azure.com/<organization-id>",
  "subject": "sc://mijnbedrijf/mijnproject/main",
  "audiences": ["api://AzureADTokenExchange"]
}

Stap 4: De Azure DevOps Serviceverbinding Aanmaken

Ga in Azure DevOps naar Projectinstellingen → Serviceverbindingen → Nieuwe serviceverbinding → Azure Resource Manager.

Selecteer Workload Identity Federation (handmatig) en vul in:

  • Abonnements-ID en Abonnementsnaam
  • Service Principal-ID: De Toepassings-ID (client) uit Stap 1
  • Tenant-ID: Je Map-ID (tenant)

Geef de serviceverbinding een betekenisvolle naam en sla op. Azure DevOps verifieert de verbinding door een OIDC-token op te vragen en te proberen te authenticeren bij Entra ID. Als Stap 3 correct is geconfigureerd, slaagt de verificatie onmiddellijk—zonder secrets.

Het Automatische Alternatief

Als je de voorkeur geeft, kan Azure DevOps de federatieve credential-configuratie automatisch afhandelen. Selecteer bij het aanmaken van een nieuwe serviceverbinding Workload Identity Federation (automatisch). Azure DevOps maakt de app-registratie aan, wijst de rol toe en configureert de federatieve credential namens jou, waarvoor alleen de juiste machtigingen op je Azure-abonnement nodig zijn. Dit is het snelste pad voor nieuwe projecten.

Workload Identity Gebruiken in Je Pipeline

Zodra de serviceverbinding is geconfigureerd, is het gebruik ervan in je pipeline identiek aan het gebruik van een op secret gebaseerde verbinding—maar dan zonder het secret.

Basis Deployment Pipeline

trigger:
  - main

pool:
  vmImage: ubuntu-latest

variables:
  azureSubscription: 'my-workload-identity-connection'
  resourceGroupName: 'rg-myapp-prod'
  appName: 'app-myapp-prod'

stages:
  - stage: Deploy
    jobs:
      - job: DeployToAzure
        steps:
          - task: AzureCLI@2
            displayName: 'Deployen naar Azure App Service'
            inputs:
              azureSubscription: $(azureSubscription)
              scriptType: bash
              scriptLocation: inlineScript
              inlineScript: |
                az webapp deployment source config-zip \
                  --resource-group $(resourceGroupName) \
                  --name $(appName) \
                  --src ./app.zip

De AzureCLI@2-taak vraagt automatisch een OIDC-token op van Azure DevOps, wisselt dit in voor een Entra ID-toegangstoken en configureert de Azure CLI-sessie. Je script wordt uitgevoerd met de identiteit van je app-registratie. Er wordt niets opgeslagen, niets geroteerd en niets kan worden gestolen van de agent nadat de job is voltooid.

Container Image Pipeline met ACR

trigger:
  branches:
    include:
      - main
      - 'release/*'

pool:
  vmImage: ubuntu-latest

variables:
  azureSubscription: 'my-workload-identity-connection'
  containerRegistry: 'mijnbedrijfacr.azurecr.io'
  imageRepository: 'myapp'
  tag: $(Build.BuildId)

stages:
  - stage: BuildAndPush
    jobs:
      - job: Build
        steps:
          - task: Docker@2
            displayName: 'Image bouwen en pushen'
            inputs:
              command: buildAndPush
              repository: $(imageRepository)
              dockerfile: '**/Dockerfile'
              containerRegistry: $(azureSubscription)
              tags: |
                $(tag)
                latest

Lezen uit Key Vault (Geen Bootstrap Secret Nodig)

Met workload identity kun je nu Key Vault-secrets ophalen vanuit je pipeline zonder enige bootstrap-credential. De pipeline authenticeert via federatie en leest vervolgens secrets voor de runtimeconfiguratie van je applicatie.

steps:
  - task: AzureKeyVault@2
    displayName: 'Applicatiesecrets ophalen'
    inputs:
      azureSubscription: 'my-workload-identity-connection'
      KeyVaultName: 'kv-myapp-prod'
      SecretsFilter: 'DatabaseConnectionString,ApiKey,SigningCertificate'
      RunAsPreJob: true

  - script: |
      echo "Deployen met opgehaalde configuratie..."
      # DatabaseConnectionString, ApiKey, SigningCertificate zijn nu
      # beschikbaar als pipeline-variabelen
    displayName: 'Applicatie deployen'

Omgevingsgebonden Implementaties

Een van de krachtigste patronen is het combineren van workload identity met Azure DevOps-omgevingen. Je kunt een federatieve credential configureren die gebonden is aan een specifieke omgeving, zodat alleen implementaties naar de production-omgeving (met goedkeuringspoorten en controles) de productie-identiteit kunnen aannemen.

stages:
  - stage: Production
    jobs:
      - deployment: DeployProduction
        environment: production  # Activeert goedkeuringspoorten
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureCLI@2
                  displayName: 'Deployen naar Productie'
                  inputs:
                    # De federatieve credential van deze serviceverbinding is
                    # gebonden aan het 'production'-omgevingsentiteitstype
                    azureSubscription: 'production-workload-identity-connection'
                    scriptType: bash
                    scriptLocation: inlineScript
                    inlineScript: |
                      az webapp deploy --resource-group rg-prod \
                        --name app-prod --src-path ./release.zip

De federatieve credential voor deze serviceverbinding is aangemaakt met entiteitstype Environment en waarde production. Zelfs als iemand handmatig een pipeline-run activeert en de omgevingsgoedkeuring omzeilt, zal de subject claim van het OIDC-token niet overeenkomen en zal authenticatie mislukken. Beveiliging wordt afgedwongen op de credential-laag, niet alleen op de pipeline-laag.

Beveiligingsoverwegingen en Best Practices

Beperk je Federatieve Credentials Nauwkeurig

Vermijd het aanmaken van federatieve credentials met te brede subject claims. In plaats van één credential voor alle branches, maak je aparte credentials aan voor:

  • main-branch → productie-implementatie-identiteit
  • refs/heads/release/* → staging-implementatie-identiteit
  • Pull requests → alleen-lezen validatie-identiteit
  • production-omgeving → productiegebonden identiteit

Gebruik Aparte App-Registraties per Omgeving

Deel geen enkele app-registratie tussen productie, staging en ontwikkeling. Maak aparte registraties aan met aparte roltoewijzingen. Dit zorgt ervoor dat een compromittering in ontwikkeling nooit kan escaleren naar productietoegang, en je kunt elke identiteit onafhankelijk auditeren en intrekken.

Pas het Principe van Minimale Bevoegdheden Toe op Roltoewijzingen

Hoe smaller de rol en scope, hoe beter. Als je pipeline alleen implementeert naar één resourcegroep, wijs de rol dan niet toe op abonnementsniveau. Als het alleen container images hoeft te pushen, wijs dan geen Contributor toe—gebruik AcrPush op het specifieke register.

# Goed: Gebonden aan specifieke resource, minimale rol
az role assignment create \
  --assignee "" \
  --role "AcrPush" \
  --scope "/subscriptions//resourceGroups//providers/Microsoft.ContainerRegistry/registries/"

# Slecht: Brede scope, te ruime rol
az role assignment create \
  --assignee "" \
  --role "Owner" \
  --scope "/subscriptions/"

Monitoren en Auditeren

Workload identity-authenticatiegebeurtenissen verschijnen in de Entra ID-aanmeldingslogboeken onder Aanmeldingen van service-principals. Stel diagnostische instellingen in om deze logboeken naar je SIEM of Log Analytics-werkruimte te routeren. Je ziet elke tokenuitwisseling, welke pipeline deze heeft geactiveerd en of deze is geslaagd of mislukt.

Bestaande Serviceverbindingen Migreren

Azure DevOps maakt migratie eenvoudig. Voor elke bestaande serviceverbinding die een client secret gebruikt, kun je deze ter plekke converteren:

  1. Ga naar Projectinstellingen → Serviceverbindingen.
  2. Selecteer de bestaande verbinding en klik op Bewerken.
  3. Als de verbinding is aangemaakt met de automatische optie, zie je een Converteren-knop die deze automatisch migreert naar workload identity federation.
  4. Azure DevOps maakt de federatieve credential aan op de bestaande app-registratie en werkt de serviceverbinding bij—geen nieuwe service principal nodig.

Voor handmatig aangemaakt verbindingen moet je een federatieve credential toevoegen aan de bestaande app-registratie en het authenticatietype wijzigen in de instellingen van de serviceverbinding. De roltoewijzingen van de app-registratie blijven ongewijzigd.

"Workload Identity Federation is niet alleen een beveiligingsverbetering—het is een onderhoudsverbetering. Geen 'de pipeline brak omdat iemand vergat het secret te roteren.' Geen noodupdates om 2 uur 's nachts omdat een credential verlopen was. Het probleem van credentialbeheer verdwijnt simpelweg."

Veelvoorkomende Problemen Oplossen

AADSTS70021: Geen overeenkomend federatief identiteitsrecord gevonden

Deze fout betekent dat de subject claim in het OIDC-token niet overeenkomt met enige federatieve credential op je app-registratie. Controleer of:

  • De naam van de organisatie in de federatieve credential precies overeenkomt met je Azure DevOps-organisatie (hoofdlettergevoelig).
  • De projectnaam precies overeenkomt.
  • Het entiteitstype en de ref overeenkomen met de trigger die de pipeline heeft gestart (format branchnaam: refs/heads/main vs main).

AADSTS700016: Toepassing niet gevonden in de map

De app-registratie bestaat niet in de tenant, of de client-ID is onjuist. Verifieer of de Toepassings-ID (client) in de serviceverbinding overeenkomt met de app-registratie in de juiste Entra ID-tenant.

AuthorizationFailed: De client heeft geen autorisatie

De app-registratie is correct geverifieerd, maar mist de benodigde Azure RBAC-rol op de doelresource. Controleer roltoewijzingen op de resource, resourcegroep of het abonnement. Houd er rekening mee dat de propagatie van roltoewijzingen na aanmaak enkele minuten kan duren.

Verificatie van Serviceverbinding Mislukt Tijdens Instelling

Azure DevOps voert een testauthenticatie uit tijdens het aanmaken van een serviceverbinding. Als dit mislukt bij de handmatige instelling, verifieer dan de issuer-URL van de federatieve credential. Het juiste issuer-format voor Azure DevOps is https://vstoken.dev.azure.com/<organization-id>, waarbij de organisatie-ID de GUID is (niet de weergavenaam). Vind de organisatie-ID in Azure DevOps onder Organisatie-instellingen → Overzicht.

Waarom Dit Verder Gaat dan Beveiliging

Workload Identity Federation verandert iets fundamenteels in hoe je denkt over pipeline-credentials. Met client secrets is elke pipeline een potentieel aanvalsoppervlak—een plek waar een credential kan lekken, op het verkeerde moment kan verlopen of ongepast kan worden gedeeld. Met federatie ís de credential de pipeline. De authenticatie is de uitvoeringscontext.

Dit sluit aan bij hoe moderne beveiligingskaders denken over identiteit: niet als iets wat je bezit (een secret dat je opslaat), maar als iets wat je bent (een verifieerbare, beperkte context). Je CI/CD-pipeline is een identiteit. Die moet als zodanig worden geverifieerd.

Microsofts aanbeveling is duidelijk: gebruik workload identity federation voor alle nieuwe Azure DevOps-serviceverbindingen en migreer bestaande. De beveiligingsverbetering is significant, de operationele onderhoudslast daalt naar bijna nul en het auditspoor wordt schoner en betrouwbaarder.

Begin met een niet-productie pipeline. Configureer de federatieve credential, maak de serviceverbinding aan en voer een implementatie uit. Zodra je een succesvolle pipeline-run ziet zonder secrets in de configuratie, begrijp je waarom dit de juiste aanpak is—en wil je alles migreren.

#Azure DevOps #Security #Workload Identity Federation #Azure #CI/CD #Entra ID