I'm experiencing an issue when I try to use an User Assigned Managed Identity to obtain a custom TLS/SSL certificate for my API Management instance from Azure Key Vault, as described here: Obtain a custom TLS/SSL certificate for the API Management instance from Azure Key Vault. The difference with the documentation is that my Key Vault has network access rules enabled. Specifically the combination of User Assigned Managed Identity and the key vault's firewall is troublesome.
Steps:
- Create vnet + subnet for APIM
- Create User Assigned Managed Identity
- Create key vault. Allow network access from APIM's subnet and create GET/LIST access policies on secrets for the User Assigned Managed Identity
- Generate self-signed certificate and import it in the key vault
- Deploy APIM (Developer SKU, internal vnet mode, with user assigned managed identity, with custom hostname configuration using ssl certificate from key vault)
Error
This results in the following error message. The message is misleading as given identity does have GET permissions.
Failed to access KeyVault Secret https://kv-xxx.vault.azure.net/secrets/gateway-certificate/58542d0de4094c60856f97482a9b2e69 using Managed Service Identity (http://aka.ms/apimmsi) of Api Management service. Check if Managed Identity of Type: UserAssigned, ClientId: 2fa6db22-xxxx-xxxx-xxxx-xxxxxxxxxxxx and ObjectId: 91f8fa07-xxxx-xxxx-xxxx-xxxxxxxxxxxx has GET permissions on secrets in the KeyVault Access Policies.
Success scenarios
As mentioned, it seems to be specifically this combination of a user assigned managed identity and a key vault with network access rules that is troublesome. The following does work:
- system assigned managed identity + firewall on key vault
- user assigned managed identity + no firewall on key vault
Deployment
I deploy my resources with Bicep, but I get the same issue via the Portal.
The bicep module for APIM:
@description('Name of APIM service')
param apimName string
@description('Location')
param location string = resourceGroup().location
@allowed([
'Basic'
'Consumption'
'Developer'
'Isolated'
'Premium'
'Standard'
])
@description('SKU name of APIM')
param skuName string
@description('Capacity of the SKU (number of deployed units of the SKU)')
param skuCapacity int
@description('Id of the subnet')
param subnetId string
@description('Publisher email')
param publisherEmail string
@description('Publisher name')
param publisherName string
@description('Id of the managed identity')
param managedIdentityId string
@description('Client id of the managed identity')
param managedIdentityClientId string
@description('Reference to the Key Vault certificate')
param certificateKeyVaultId string
@description('Reference to the Key Vault certificate')
@secure()
param certificateKeyVaultPassword string
@description('Hostname of the gateway')
param gatewayHostname string
resource apim 'Microsoft.ApiManagement/service@2021-08-01' = {
name: apimName
location: location
sku: {
capacity: skuCapacity
name: skuName
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentityId}': {}
}
}
properties: {
hostnameConfigurations: [
{
type: 'Proxy'
hostName: gatewayHostname
defaultSslBinding: true
certificateSource: 'KeyVault'
identityClientId: managedIdentityClientId
keyVaultId: certificateKeyVaultId
certificatePassword: certificateKeyVaultPassword
}
]
publisherEmail: publisherEmail
publisherName: publisherName
virtualNetworkConfiguration: {
subnetResourceId: subnetId
}
virtualNetworkType: 'Internal'
}
}
Links:
- https://github.com/MicrosoftDocs/azure-docs/issues/86983
- https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-integrate-internal-vnet-appgateway#set-up-custom-domain-names-in-api-management
- https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity#use-ssl-tls-certificate-from-azure-key-vault-ua