I want to create a key vault that will store a TLS certificate. This key vault needs to be accessible from Azure pipeline tasks, which will retrieve the said certificate and bind it to their apps. Microsoft mentions:

By default, 'Microsoft.Azure.WebSites' Resource Provider (RP) doesn't have access to the Key Vault specified in the template hence you need to authorize it by executing the following PowerShell commands before deploying the template:

Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId AZURE_SUBSCRIPTION_ID
Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get

This works for my key vault when I do it manually. However, I want to automate this as part of my master pipeline. I've tried defining this task:

- task: AzurePowerShell@5
  displayName: 'Set key vault policy'
  inputs:
    azureSubscription: …
    azurePowerShellVersion: 'LatestVersion'
    ScriptType: 'InlineScript'
    Inline: |
      Set-AzKeyVaultAccessPolicy -VaultName … -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get

But it fails:

##[error]Operation returned an invalid status code 'Forbidden'

I've also noticed that this service principal for "Microsoft Azure App Service" isn't even available to my task; the following prints a blank:

 $azureAppServicePrincipal = Get-AzADServicePrincipal -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd
 Write-Output "azureAppServicePrincipalId = $($azureAppServicePrincipal.Id)"

Is there a way of making this service principal accessible to my pipeline?

2

There are 2 answers

4
Levi Lu-MSFT On BEST ANSWER

When i tested with parameter Set-AzKeyVaultAccessPolicy -ServicePrincipalName other-service-principal. I get the same error.

You can use ObjectId and add the -BypassObjectIdValidation parameter in Set-AzKeyVaultAccessPolicy command as workaround. See the Note on this document.

When using a service principal to grant access policy permissions, you must use the -BypassObjectIdValidation parameter.

Set-AzKeyVaultAccessPolicy -VaultName myvault -ObjectId "ObjectId" -PermissionsToSecrets get -BypassObjectIdValidation 

The Object id is the ObjectId resides in Managed application in local directory

enter image description here

You can also use below Az cli command in the Azure CLI task

az keyvault set-policy -n levikeyv --secret-permissions get --object-id "object-id"

For the command Get-AzADServicePrincipal was not returning any results. It is probably the service principal associated with your ARM connection service donot have the Read Directory Data permission in the Microsoft Grap

You can try go to the Api permissions of your service principal app and add the proper permission. It may require your Admin's consent. See this thread and this for information.

enter image description here

0
14207973 On

Levi Lu's answer set me on the right track, but I'm adding my own answer to clarify the exact requirements.

To be able to access the service principal for "Microsoft Azure App Service" (abfa0a7c-a6b6-4736-8310-5855508787cd), you need two things:

  1. Your subscription must have the "Microsoft.Web" resource provider registered. This often gets registered automatically when creating a new subscription, but sometimes it doesn't.

Microsoft.Web


  1. The service principal associated with your ARM service connection (under which your pipeline runs) must have the "Directory.Read.All" permission from the Azure Active Directory Graph. Open your Azure DevOps project settings, click "Service Connections", open your service connection, and click "Manage Service Principal". Then go to "API permissions", click "Add a permission", scroll down and click "Azure Active Directory Graph", "Application permissions", and add "Directory.Read.All". Click "Grant admin consent". If this button is greyed out, you need to get an AAD admin to do this step for you.

Manage Service Principal


Add permission


Directory.Read.All


Grant consent


Granted consent


Importantly, you must pick the "Directory.Read.All" permission from Azure Active Directory Graph, despite this API being marked as legacy and on a deprecation path. Picking the said permission from Microsoft Graph instead will not work. That said, it's not a bad idea to add the permission from both APIs, in case the requirement eventually switches from one to the other. Something else I found bizarre is that the permission, once it has been granted and consumed, continues to work even after it gets revoked. To get the task to fail again (for the sake of testing), I needed to create a new tenant (Azure Active Directory).

With those two in place, you can grant permission for the "Microsoft Azure App Service" service principal to your key vault through this task (substitute $env:keyVaultName accordingly):

- task: AzurePowerShell@5
  displayName: 'Grant key vault access to service principal'
  inputs:
    azureSubscription: '${{ parameters.armConnection }}'
    azurePowerShellVersion: 'LatestVersion'
    ScriptType: 'InlineScript'
    Inline: |              
    if (!(Get-AzADServicePrincipal -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd)) {
        throw "Current account cannot retrieve service principal `"abfa0a7c-a6b6-4736-8310-5855508787cd`" (Microsoft Azure App Service)."
    }
    Write-Host "Granting access to service principal `"abfa0a7c-a6b6-4736-8310-5855508787cd`" (Microsoft Azure App Service) on vault `"$($env:keyVaultName)`"..."
    Set-AzKeyVaultAccessPolicy -VaultName $env:keyVaultName -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets Get,List -PermissionsToCertificates Get,List

Update May 2022:

Microsoft seem to have broken this. The Azure Active Directory Graph API is greyed out, despite that Set-AzKeyVaultAccessPolicy still uses it.

enter image description here

The Microsoft CLI team is in the process of migrating from the Azure Active Directory Graph API to the Microsoft Graph API. Until that is released, the best workaround seems to be to give Application administrator permissions to the service principal, as explained in this answer.