Reputation: 306
I feel like I'm stuck in a catch 22 with how Microsoft has implemented this functionality in the Container App templates. The issue, it seems to me, is that is actually validates the secret access as part of the template deploment... which creates the issue of the Managed Identity (system) not actually yet existing since the app hasn't been created, thus no way to assign that identity RBAC to the Keyvault, thus validation failes.
Am I missing something here, or is the process really going to require 2 templates... 1 with no secret references, just to "create" the thing, and then a second to actually properly configure it now that the managed identity is availabe?
The following field(s) are either invalid or missing. Field 'configuration.secrets' is invalid with details: 'Invalid value: "mysecret-name":
Unable to get value using Managed identity system for secret mysecret-name. Error: unable to fetch secret 'mysecret-name' using Managed identity 'system'';.
"configuration": {
"secrets": [
{
"name": "mysecret-name",
"keyVaultUrl": "[concat('https://',variables('vaultname'),'.vault.azure.net/secrets/mysecret')]",
"identity": "system"
}
]
}
Upvotes: 1
Views: 1671
Reputation: 12044
It is important to validate what strategy are you using to access the KeyVault.
It can be RBAC
or Access Policy
.
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = {
name: keyVaultName
location: location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
enableRbacAuthorization: true
}
}
Using enableRbacAuthorization: true
you will need to grant the RBAC Role Assignment, possible using:
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: managedIdentityName
location: location
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(managedIdentity.id, 'KeyVaultSecretsUser')
scope: keyVault
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6') // Key Vault Secrets User
principalId: managedIdentity.properties.principalId
principalType: 'ServicePrincipal'
}
}
There you are using the RBAC, but also, you can use the Access Policy:
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = {
name: keyVaultName
location: location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
accessPolicies: [] // Managed Identity will be assigned separately
}
}
Which could require an implementation like:
name: 'poc-aca-kv'
location: resourceGroup().location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: managedIdentity.properties.principalId // Assign permissions to the Managed Identity
permissions: {
secrets: [
'get'
'list'
'read'
]
}
}
]
}
}
Now, depending of your implementation (RBAC or access policies), now you can use it:
resource secretref 'Microsoft.KeyVault/vaults/secrets@2024-04-01-preview' existing = {
name: 'DatabaseConnectionString'
parent: keyVault
}
resource secretref2 'Microsoft.KeyVault/vaults/secrets@2024-04-01-preview' existing = {
name: 'DatabaseConnectionString'
parent: keyVault
}
And the container app as:
resource containerApp 'Microsoft.App/containerApps@2024-10-02-preview' = {
dependsOn: [roleAssignment]
name: containerAppName
location: location
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
properties: {
managedEnvironmentId: environment.id
configuration: {
secrets: [
{
name: 'apikey'
keyVaultUrl: secretref.properties.secretUri
identity: managedIdentity.id
}
{
name: 'apikey'
keyVaultUrl: secretref2.properties.secretUri
identity: managedIdentity.id
}
]
}
template: {
containers: [
{
name: containerAppName
image: containerAppImage
env: [
{
name: 'db'
secretRef: 'db'
}
{
name: 'apikey'
secretRef: 'apikey'
}
]
}
]
scale: {
maxReplicas: 1
minReplicas: 0
}
}
}
}
Upvotes: 0
Reputation: 1
I had this error when experimenting in the Azure Portal, trying to create a secret with a Key Vault reference in a Container App. For me the solution for this error was to go back to the Key Vault. There I created a new Role Assignment: I assigned the role Key Vault Secrets User to the Managed Identy I created in the Container App (under tab 'Identity': turn on System assigned managed identity).
After that, I was able to add a new secret to the Container App with a Key Vault reference.
I did all of this in the Azure Portal, so I have no idea how to do this in a template, sorry.
Upvotes: 0
Reputation: 187
One alternative is to do a nested deployment with the principalID as output to the main/master template, but i guess then yes, you do need "two" templates
ex:
output webAppMSI string = webApp.identity.principalId
or use bicep modules, here is a good sample:
https://blog.johnfolberth.com/chicken-and-the-egg-how-to-handle-bicep-interdependencies/
Upvotes: 0
Reputation: 29736
Using a user-assigned managed identity will solve your problem:
Using Bicep, that would look like that:
key vault role assignment module:
// key-vault-role-assignment.bicep
param keyVaultName string
param principalId string
param principalType string = 'ServicePrincipal'
param roleIds array
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyVaultName
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for roleId in roleIds: {
name: guid(subscription().subscriptionId, resourceGroup().name, keyVaultName, roleId, principalId)
scope: keyVault
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId)
principalId: principalId
principalType: principalType
}
}]
and your main template:
// main.bicep
param location string = resourceGroup().location
param identityName string
param keyVaultName string
param containerAppEnvName string
param containerAppName string
// Create the identity
resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: identityName
location: location
}
// Grant KV RBAC to the identity
module kvRbac 'key-vault-role-assignment.bicep' = {
name: '${identityName}-${keyVaultName}-rbac'
params: {
keyVaultName: keyVaultName
principalId: identity.properties.principalId
roleIds: [ '4633458b-17de-408a-b874-0445c86b69e6' ] // Key vault secret user
}
}
// Create the container app env
resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
name: containerAppEnvName
...
}
// Create the container app and assigned the identity
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
name: containerAppName
location: location
dependsOn: [
kvRbac
]
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${identity.id}': {}
}
}
properties: {
environmentId: containerAppEnv.id
workloadProfileName: 'Consumption'
configuration: {
...
secrets: [
{
name: 'applicationinsights-connection-string'
keyVaultUrl: 'https://${keyVaultName}${environment().suffixes.keyvaultDns}/secrets/mysecret'
identity: identity.id
}
]
}
...
}
}
Az CLI / Az Powershell supports natively bicep but you could always generate the related ARM template using az bicep build
:
az bicep build --file main.bicep
Upvotes: 2