azure-devopsazure-resource-managerazure-keyvaultazure-service-principalserviceconnection

Service Connection permissions error when trying to access Azure Key vault secrets from within an Azure DevOps pipeline with the task AzureKeyVault@2


In my devops pipeline, I have this task:

- task: AzureKeyVault@2
  displayName: 'Fetch secrets from KeyVault used in Deploy stage'
  inputs:
    azureSubscription: '$(AzureServiceConnectionName)'
    KeyVaultName: '$(AzureKeyVaultName)'
    SecretsFilter: '*'  # Fetch all secrets
    RunAsPreJob: true
# Note: all the variables above are correctly resolving.

RunAsPreJob is set to ´true´ because I want to be able to use some secrets as variables in a few tasks after this one (but inside the same job, of course).

The problem is that when it tries to run as a pre-job, it throws the error:

Pre-job: Fetch secrets from KeyVault used in Deploy stage

View raw log

Starting: Fetch secrets from KeyVault used in Deploy stage
==============================================================================
Task         : Azure Key Vault
Description  : Download Azure Key Vault secrets
Version      : 2.249.1
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/deploy/azure-key-vault
==============================================================================
SubscriptionId: <not-the-actual-value>.
Key vault name: <not-the-actual-value>.
Downloading secrets using: https://<not-the-actual-value>.vault.azure.net/secrets?maxresults=25&api-version=2016-10-01.
##[error]Get secrets failed. Error: Client address is not authorized and caller is not a trusted service.
Client address: <not-the-actual-value>
Caller: appid=***;oid=<not-the-actual-value>;iss=https://sts.windows.net/<not-the-actual-value>/
Vault: <not-the-actual-value>;location=westeurope. The specified Azure service connection needs to have Get, List secret management permissions on the selected key vault. To set these permissions, download the ProvisionKeyVaultPermissions.ps1 script from build/release logs and execute it, or set them from the Azure portal..
Uploading /home/vsts/work/1/ProvisionKeyVaultPermissions.ps1 as attachment
Finishing: Fetch secrets from KeyVault used in Deploy stage

I have successfully run that script which added this to the keyvault's access policies: enter image description here

Then I re-ran the pipeline but the error still remains... I also added this access policy manually to key vault and re-ran the pipeline to no avail...

Additionally, attempting a workaround, I tried adding a Variable group linked to the key vault: enter image description here as you can see, with no success...

I am a bit lost by now and without any more clues to what might the problem be.

Note: I have run this keyvault task with RunAsPreJob: false in the past and it went ok.


Solution

  • Ultimately, what solves this permissions error is what was said in the comments: the IP of the agent has to be added to the key vault's firewall. So I added it, fetched the secrets and afterwards removed the IP, like this:

    - task: AzureCLI@2
            displayName: 'Allow agent IP'
            inputs:
              azureSubscription: '$(AzureServiceConnectionName)'
              scriptType: 'bash'
              scriptLocation: 'inlineScript'
              inlineScript: |
                # Get the agent's public IP
                ip=$(curl -s http://ipinfo.io/json | jq '.ip' | tr -d '"')
    
                # Add the IP to the Key Vault network rule
                az keyvault network-rule add \
                  --name "$(AzureKeyVaultName)" \
                  --resource-group "$(AzureResourceGroupName)" \
                  --ip-address $ip
    
                # Set the IP as a pipeline variable
                echo "##vso[task.setvariable variable=agentIP]$ip"
    
          - task: AzureKeyVault@2
            displayName: 'Fetch secrets from Azure KeyVault'
            inputs:
              azureSubscription: '$(AzureServiceConnectionName)'
              KeyVaultName: '$(AzureKeyVaultName)'
              SecretsFilter: '*'  # Fetch all secrets
              RunAsPreJob: false
    
          - task: AzureCLI@2
            displayName: 'Remove agent IP from KeyVault Firewall'
            inputs:
              azureSubscription: '$(AzureServiceConnectionName)'
              scriptType: 'bash'
              scriptLocation: 'inlineScript'
              inlineScript: |
                az keyvault network-rule remove \
                  --name "$(AzureKeyVaultName)" \
                  --resource-group "$(AzureResourceGroupName)" \
                  --ip-address $(agentIP)
    

    Unfortunately, I couldn't make this work with RunAsPreJob: true like I intended at first... so I had to run the task with RunAsPreJob: false. This meant that I had to put all of the subsequent tasks that needed to access any key vault variables in the same job.