Search code examples
azure-pipelinesworkload-identity

Azure Pipelines: Logging in using Workload Identity Federation


In my CI-pipeline I need to log in to azure key vault to check that my code, which handles keys, works correctly.

I have created a Workload Identity, called my_workload_identity, and given it reader-access to the key vault. I am not sure how to use it though.

Things I have tried:

I have found a possible way here:

az login --federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)" --service-principal -u $AZURE_CLIENT_ID -t $AZURE_TENANT_ID

That seems to get a token back, but when used in a AzureCLI@2

- task: AzureCLI@2
  displayName: 'az login'
  inputs:
    azureSubscription: 'my_workload_identity'
    scriptType: bash
    scriptLocation: 'inlineScript'
    inlineScript: |
      az login --debug --federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)" --service-principal -u $AZURE_CLIENT_ID -t $AZURE_TENANT_ID
    addSpnToEnvironment: true

it hangs forever. Later on I found out that it deletes the token by running az account clear anyway.

Then I tried running it in a bash-task:

- bash: |
      az login --debug --federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)" --service-principal -u $AZURE_CLIENT_ID -t $AZURE_TENANT_ID

That also hangs forever and doesn't even seem to get a token back.

What is the correct way to authenticate using Workload Identity Federation in Azure Pipelines?

Edit for clarification:

Using AzureCLI@2 works, but only for the duration of that task. I am looking for a way for all (subsequent) tasks to be able to use the federated identity.


Solution

  • when trying to access the Azure resources from pipelines in Azure DevOps, it is recommended creating and using an Azure Resource Manager service connection (ARM service connection) in Azure DevOps.

    To create an ARM service connection with workload identity federation, you can follow the steps below:

    1. In the Azure DevOps project where you pipeline is in, go to "Project Settings" > "Service connections" to create the new ARM service connection.

      enter image description here

    2. Select "Azure Resource Manager" > select "Workload Identity federation (manual)" if you have a Service Principal existing. Give a customized name to the service connection to complete Step 1. Click "Next" to open Step 2.

      enter image description here

    3. Open Azure Portal on a new tab/window of the browser. go to "Microsoft Entra ID" > "App registrations", find and open the Service Principal. The go to "Certificates & secrets" > "Federated credentials" tab to add a new credential.

      enter image description here

    4. Fill in the required information on the new credential.

      • Federated credential scenario: Other issuer
      • Issuer: Copy from Step 2 on the new service connection window.
      • Subject identifier: Copy from Step 2 on the new service connection window.
      • Name: A customized name of the new credential.

      enter image description here

    5. Back to the new service connection window to complete Step 2.

      enter image description here

    After completing above steps, in the pipelines, you can use this ARM service connection on the AzureCLI@2, AzurePowerShell@5 and other Azure related tasks to connect to Azure.

    For more details, you also can reference the documentation "Connect to Azure by using an Azure Resource Manager service connection".


    EDIT:

    If you want to persist the workload identity federation token from the AzureCLI@2 task and use the same token in the subsequent tasks within the same job, you can set the credential as the pipeline variables in the Azure CLI task.

    You can follow the steps below:

    1. Enable the option 'addSpnToEnvironment' (Access service principal details in script) on the AzureCLI@2 task.

    2. Then use a PowerShell, Bash or CmdLine task to execute the az login command with the credential by referencing the pipeline variables.

    steps:
    - task: AzureCLI@2
      displayName: 'Azure CLI '
      inputs:
        azureSubscription: ArmServiceConnection
        addSpnToEnvironment: true
        scriptType: bash
        scriptLocation: inlineScript
        inlineScript: |
         echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$servicePrincipalId" 
         echo "##vso[task.setvariable variable=ARM_ID_TOEKN]$idToken"
         echo "##vso[task.setvariable variable=ARM_TENANT_ID]$tenantId"
    
    
    - bash: |
       az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOEKN)
      displayName: 'Login Azure'
    
    - Some subsequent tasks . . .
    

    With above configurations, the subsequent tasks can directly use the credential without az login again.

    Related documeation: