bicep
bicep copied to clipboard
"Unable to evaluate template language function 'extensionResourceId'" when referencing role definition property
Bicep version
- Bicep CLI version 0.10.61 (8f44805506)
- vscode Bicep extension version v0.10.61
- az cli versions
{
"azure-cli": "2.40.0",
"azure-cli-core": "2.40.0",
"azure-cli-telemetry": "1.0.8",
"extensions": {
"account": "0.2.3",
"authV2": "0.1.1",
"ssh": "1.1.2"
}
}
Describe the bug Referencing properties from an existing role definition and passing that property to a module fails.
For this use case, I want to iterate assignable scopes for a role to allow reading individual secrets in a key vault. The intention is to create reusable modules to be able to read individual secrets in a key vault.
I have created a role definition that looks like this:
{
"assignableScopes": [
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret1",
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret2",
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret3",
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret4",
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret5",
"/subscriptions/xxx/resourcegroups/rg-01-xxx-xxx-euw-dev/providers/Microsoft.KeyVault/vaults/kv-01-xxx-xxx-dev/secrets/secret6"
],
"description": "Allows reading specific secrets in the xxx key vault in mgmt group xxx",
"id": "/subscriptions/xxx/providers/Microsoft.Authorization/roleDefinitions/xxx",
"name": "xxx",
"permissions": [
{
"actions": [],
"dataActions": [
"Microsoft.KeyVault/vaults/secrets/getSecret/action",
"Microsoft.KeyVault/vaults/secrets/readMetadata/action"
],
"notActions": [],
"notDataActions": []
}
],
"roleName": "Limitied xxx secret reader",
"roleType": "CustomRole",
"type": "Microsoft.Authorization/roleDefinitions"
}
I then in a later step in a workflow retrieve the role using the existing
keyword and iterate the assignable scopes for a single principal. When retrieving the assignable scopes, bicep fails with:
Unable to evaluate template language function 'extensionResourceId': function requires exactly two multi-segmented arguments. The first must be the parent resource id while the second must be resource type including resource provider namespace. Current function arguments '/providers/Microsoft.Management/managementGroups/ESD,Microsoft.Authorization/roleDefinitions,/subscriptions/xxx/providers/Microsoft.Authorization/roleDefinitions/xxx'.
To Reproduce Steps to reproduce the behaviour:
1. Create a custom role with multiple assignable secret scopes This step works, just intended to be able to reproduce.
targetScope = 'subscription'
param subscriptionId string
param resourceGroupName string
param keyVaultName string
param allowedSecrets array
var keyVaultScope = '/subscriptions/${subscriptionId}/resourcegroups/${resourceGroupName}/providers/Microsoft.KeyVault/vaults/${keyVaultName}'
var assignableScopes = [for secretName in allowedSecrets: '${keyVaultScope}/secrets/${secretName}']
var roleName = 'Limitied ${keyVaultName} secret reader'
// Permissions based on Key Vault Secrets User
// https://www.azadvertizer.net/azrolesadvertizer/4633458b-17de-408a-b874-0445c86b69e6.html
resource key_vault_secrets_user_role_definition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
name: '4633458b-17de-408a-b874-0445c86b69e6'
}
resource role_definition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' = {
name: guid(roleName)
properties: {
roleName: roleName
description: 'Allows reading specific secrets in the ${keyVaultName} key vault'
assignableScopes: assignableScopes
permissions: key_vault_secrets_user_role_definition.properties.permissions
}
}
output roleDefinitionId string = role_definition.id
2. Assign the role to a single principal
main.bicep
targetScope = 'managementGroup'
param secretReaderRoleDefinitionId string // This is the output from above declared definition
param subscriptionId string
param resourceGroupName string
param keyVaultName string
resource secretReaderRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
name: secretReaderRoleDefinitionId
}
module regressionTestSecretReader 'module.bicep' = {
name: 'secret-reader-role-assignment'
scope: resourceGroup(subscriptionId, resourceGroupName)
params: {
secretReaderRoleDefinitionId: secretReaderRoleDefinitionId
assignableScopes: secretReaderRoleDefinition.properties.assignableScopes
managementGroupName: managementGroup().name
keyVaultName: keyVaultName
}
}
// Lots of other assignments done on the management group level
module.bicep
targetScope = 'resourceGroup'
param secretReaderRoleDefinitionId string
param assignableScopes array = []
param managementGroupName string
param keyVaultName string
var regressionTestSPObjectId = managementGroupName == 'ES' ? 'abc' : 'xyz'
// Full scope looks like this:
// '/subscriptions/<sub>/resourcegroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/<secret>'
// Hence 8 is the secret name
var secretNames = [for scope in assignableScopes: split(scope, '/')[8]]
resource secretResources 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' existing = [for secret in secretNames: {
name: '${keyVaultName}/${secret}'
}]
// Iterating the secretResources array is not supported, so we iterate the scope which they are based
resource regressionTestKeyVaultReaderAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for (scope, index) in assignableScopes: {
name: guid(managementGroupName, regressionTestSPObjectId, scope)
scope: secretResources[index] // Access by index and apply this role assignment to all assignable scopes
properties: {
principalId: regressionTestSPObjectId
roleDefinitionId: secretReaderRoleDefinitionId
}
}]
3. Run the deployment
az deployment mg create --name 'role-assignments-deployment-local' \
--location 'westeurope' \
--management-group-id mgmtgroup \
--template-file ./role-assignments/main.bicep \
--parameters secretReaderRoleDefinitionId="/subscriptions/<same-as-role-definition-and-kv>/providers/Microsoft.Authorization/roleDefinitions/<role-def-id>" \
--parameters resourceGroupName="my-rg" \
--parameters subscriptionId="some-as-role-def-and-kv" \
--parameters keyVaultName="my-kv"
4. Error output
{"code": "InvalidTemplate", "message": "Deployment template validation failed: 'The template resource 'secret-reader-role-assignment' at line '26' and column '5' is not valid: Unable to evaluate template language function 'extensionResourceId': function requires exactly two multi-segmented arguments. The first must be the parent resource id while the second must be resource type including resource provider namespace. Current function arguments '/providers/Microsoft.Management/managementGroups/ESD,Microsoft.Authorization/roleDefinitions,/subscriptions/xxx/providers/Microsoft.Authorization/roleDefinitions/xxx'. Please see https://aka.ms/arm-template-expressions/#extensionresourceid for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.", "additionalInfo": [{"type": "TemplateViolation", "info": {"lineNumber": 26, "linePosition": 5, "path": "properties.template.resources[0]"}}]}
Additional context
Compile to ARM
bicep build main.bicep
Error seems to originate from row 42 in the compiled template, the only mention of extensionResourceId
.
"assignableScopes": {
"value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/roleDefinitions', parameters('secretReaderRoleDefinitionId')), '2018-01-01-preview').assignableScopes]"
},
Docs clearly state that the failing function accepts 3 arguments.
Removing the first argument from this parameter (managementGroup().id
) gives an invalid template according to vscode:
"assignableScopes": {
"value": "[reference(extensionResourceId('Microsoft.Authorization/roleDefinitions', parameters('secretReaderRoleDefinitionId')), '2018-01-01-preview').assignableScopes]"
},
The function 'extensionResourceId' takes at least 3 arguments.