Azure Managed Application Publisher / ISV Access to Azure Key Vault in Managed Resource Group in Customer Subscription
In this article, we look at a scenario where Azure Managed Application publisher (aka Independent Software Vendor or ISV) needs to be able to use their publisher identity to create/delete secrets (e.g. connection string) in Azure Key Vault that is in the Managed Resource Group (MRG) in the customer’s Azure subscription so that other resources (e.g. Web Apps, VMs) running in the MRG can use these secrets.
Challenge
Azure Key Vault resource and its data-plane access policies are tied to a specific Azure Active Directory tenant (i.e. there is a tenantId property in Azure Key Vault resource) and resources deployed in the managed resource group in the customer subscription need to be able to use the secrets in Azure Key Vault. Therefore, Azure Key Vault must be tied to the customer’s tenant.
This means that publisher identity is not able to perform Azure Key Vault data-plane operations like create/delete/list/read secrets.
It is a bit of a “catch 22” situation:
- Customer cannot access the Key Vault in the Managed Resource Group (MRG) in their subscription because Azure Managed Application has a Deny assignment on the MRG (which is the correct default behavior)
- Publisher cannot access the Key Vault in the Managed Resource Group because the Key Vault is tied to the customer’s Azure AAD tenant (this is the challenge)
Potential Approaches
Publisher can “proxy” access to the Azure Key Vault data-plane API in the Managed Resource Group (MRG) through either of:
- Identity of the Managed Application resource itself (i.e. listing its tokens)
- User-Assigned Managed Identity of other resources in the MRG (i.e. VM, container instance, Logic App, etc.)
Publisher can also set secrets in the end-customer’s Azure Key Vault using ARM control-plane APIs by using Microsoft.KeyVault/vaults/secrets write action which publisher’s identity can perform via ARM if it has “Contributor” or “Key Vault Contributor” role on the Azure Key Vault resource. This create-key-vault-secret ARM template shows how publisher (or Azure Lighthouse provider) can create the secret using ARM template deployment
Pseudocode for data-plane Managed Identity “proxy” approach
Below is the pseudocode of the “proxy” approach using Managed Application identity.
Step 1: In createUiDefinition.json add a step with Microsoft.ManagedIdentity.IdentitySelector control and have it always select “System Assigned = On” (example)
Step 2: After the application deploys, use publisher identity to get the principalId of the Managed Application’s System-Assigned Identity
az rest --method GET --uri /subscriptions/{CUSTOMER_SUBSCRIPTION_ID}/resourceGroups/{MANAGED_APP_RG}/providers/Microsoft.Solutions/applications/{MANAGED_APP_NAME}?api-version=2019–07–01 --query identity.principalId -o tsv
Step 3: Use publisher identity to modify Azure Key Vault access policies by adding the principalId of the Managed Application identity to the allowed list (including only the permissions that the publisher needs — e.g. set)
az keyvault set-policy --secret-permissions list get set delete --object-id PRINCIPAL_ID_OF_THE_MANAGED_APP_SYSTEM_ASSIGNED_IDENTITY --name KEYVAULT_NAME
Step 4: Use publisher identity to get Managed Application access token (as described here) for calling Azure Key Vault data-plane REST API
az rest --method POST --uri /subscriptions/{CUSTOMER_SUBSCRIPTION_ID}/resourceGroups/{MANAGED_APP_RG}/providers/Microsoft.Solutions/applications/{MANAGED_APP_NAME}/listTokens?api-version=2019–07–01 --headers Content-Type=application/json — body "{authorizationAudience: 'https://vault.azure.net'}" -o json
Step 5: Use Azure Key Vault data-plane REST API to set/get/list tokens by passing the access token obtained above in the Authorization header
curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer {ACCESS_TOKEN}" https://KEYVAULT_NAME.vault.azure.net/secrets/secret1?api-version=7.1 -d "{\"value\": \"secret1_value\"}"
Currently, steps 2 and 3 cannot be performed in the mainTemplate.json of the Managed Application itself because we cannot get its identity.principalId via the reference() function since reference() implies a dependsOn and causes a deadlock on itself. Therefore, steps 2 and 3 show how to obtain the principalId and change the Key Vault access policy imperatively after the deployment completes (i.e. publisher can configure web hook notification for managed apps).
Thank you!
Please leave feedback and questions below or on Twitter https://twitter.com/ArsenVlad