-
Notifications
You must be signed in to change notification settings - Fork 759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unclear how to assign a role assignment to an arbitrary resource type/name in module #4607
Comments
If you are using this dynamically you can fall back to the native way to retrieve the resourceid, which is via resourceid() method. It takes the resource type and name as arguments. resourceId([subscriptionId], [resourceGroupName], resourceType, resourceName1, [resourceName2], ...) |
So looking at my roleAssignments module then: @minLength(1)
param roleIds array
@description('The name of the managed identity to assign the roles to')
param managedIdentityName string
@description('The type of the resource to scope to')
param resourceType string
@description('The ID of the resource to scope to')
param resourceId string
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
name: managedIdentityName
}
resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = [for roleId in roleIds: {
name: guid(subscription().subscriptionId, resourceGroup().location, roleId)
scope: ???
properties: {
roleDefinitionId: roleId
principalId: managedIdentity.id
}
}] roleAssignments.scope indicates that it accepts a resource or a tenant (and not a resourceId). The docs hereonly indicate how to do this with the name of the resource, but I can't use the name because I can't dynamically construct the resource type/API version from the parameters passed in. Looking at the docs you linked, it indicates the syntax for using resourceId, but the examples don't actually show using it, especially not in a context of creating a resource I can pass into the scope. Finally, I tried using reference:
But this isn't allowed either because I'm once again just passing an object into scope where it expects to see a tenant or resource. So when I need the resource reference and not just the ID, how can I get it when I have a string of the type/version and the string with the resource's ID? |
Here is your parent bicep param managedIdentityName string = 'myUAIName123'
param storageRoleIds array = [
//Storage Blob Data Contributor
'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
]
var storageAccountName = [
{
name: 'acu1brwaoad2sadiag'
}
]
module roleAssignments 'roleAssignments.bicep' = [for (account, index) in storageAccountName: {
name: 'storageRoleAssignments-${account.name}'
params: {
roleIds: storageRoleIds
managedIdentityName: managedIdentityName
resourceType: 'microsoft.storage/storageAccounts'
name: account.name
}
}] calls this module which has the official way to do this by using param roleIds array
param managedIdentityName string
param resourceType string
param name string
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' existing = {
name: name
}
resource mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
name: managedIdentityName
}
var guids = [for (roleId, index) in roleIds: guid(subscription().subscriptionId, resourceGroup().location, roleId, resource,name)]
resource rd 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = [for (roleId, index) in roleIds: {
name: roleId
}]
resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for (roleId, index) in roleIds: {
name: guids[index]
scope: storageAccount
properties: {
roleDefinitionId: rd[index].id
principalId: mi.properties.principalId
}
}] if you build that you will see it shows exactly what is in the docs BICEP: Obviously above works great, however it's not dynamic. Role assignments are actually extension types, that is like saying they extend the resources and can be applied at many scopes. e.g. extend on a subscription: extend on a resource group scope: extend on a resource scope e.g. keyvault: So those long resourceID's contain types and associated values for the types. values in bold below Mirosoft.KeyVault/vaults/akvr3vdqwnxd23hy/providers/Microsoft.Authorization/roleAssignments/5fa9ac3b-d2ab-55ab-bfad-cc5b43d30594 when we deploy these via ARM, we split these into the name and type (plus api version), so this becomes: name: akvr3vdqwnxd23hy/Microsoft.Authorization/5fa9ac3b-d2ab-55ab-bfad-cc5b43d30594
so what's nextGiven we need to be dynamic with generating the scope (we can't use the normal Bicep Scope) ... we can fall back to a 'deployment', which is just calling ARM directly, via bypassing Bicep. resource roleAssignments 'Microsoft.Resources/deployments@2021-04-01' = [for (roleId, index) in roleIds: {
name: 'roleassign-${roleId}'
properties: {
mode: 'Incremental'
template: {
'$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
resources: [
{
name: '${name}/Microsoft.Authorization/${guids[index]}'
type: '${resourceType}/providers/roleAssignments'
apiVersion: '2021-04-01-preview'
properties: {
roleDefinitionId: rd[index].id
principalId: mi.properties.principalId
}
}
]
}
}
}] OR using scope... which is a shortcut to create the name/type combination. Essentially the same. resource roleAssignments 'Microsoft.Resources/deployments@2021-04-01' = [for (roleId, index) in roleIds: {
name: 'roleassign-${roleId}'
properties: {
mode: 'Incremental'
template: {
'$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
resources: [
{
name: guids[index]
type: 'Microsoft.Authorization/roleAssignments'
scope: '${resourceType}/${name}'
apiVersion: '2021-04-01-preview'
properties: {
roleDefinitionId: rd[index].id
principalId: mi.properties.principalId
}
}
]
}
}
}] review the deployment in the portal Get-AzRoleAssignment -ObjectId 067e90f2-ea05-48f3-b9ed-d03cc39dc64c
RoleAssignmentId : /subscriptions/b8f402aa-20f7-4888-b45c-3cf086dad9c3/resourcegroups/ACU1-BRW-AOA-RG-D2/providers/microsoft.storage/storageAccounts/acu1brwaoad2sadiag/providers/Microsoft.Authorization/roleAssignments/3159335b-597d-5f30-b61a-18c8f9d6270d
Scope : /subscriptions/b8f402aa-20f7-4888-b45c-3cf086dad9c3/resourcegroups/ACU1-BRW-AOA-RG-D2/providers/microsoft.storage/storageAccounts/acu1brwaoad2sadiag
DisplayName : ACU1-BRW-AOA-D2-uaiStorageAccountOperator
SignInName :
RoleDefinitionName : Storage Blob Data Contributor
RoleDefinitionId : ba92f5b4-2d11-453d-a403-e96b0029c9fe
ObjectId : 067e90f2-ea05-48f3-b9ed-d03cc39dc64c
ObjectType : ServicePrincipal
CanDelegate : False |
Thank you very much for the detailed look at how to do this! It seems like there might be an opportunity then for a more dynamic component in Bicep so as to avoid bypassing it in favor of an ARM stand-in. Is something like this anywhere on the roadmap? The initial two ways I see of doing this would be:
|
Proposal #2246 will allow you to author a reusable module which applies a roleAssignment to a resource which is passed in as a parameter. Would that provide enough flexibility here? e.g. param inputResource resource
resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
name: ...
scope: inputResource
properties: {
roleDefinitionId: ...
principalId: ...
}
} So you could then call it with: resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' existing = {
name: name
}
module 'addAssignments.bicep' = {
name: 'addAssignments'
params: {
inputResource: storageAccount
}
} Proposal #2245 would allow you to simplify this further to: module 'addAssignments.bicep' = {
name: 'addAssignments'
params: {
inputResource: resource('Microsoft.Storage/storageAccounts@2021-04-01', name)
}
} |
Is your feature request related to a problem? Please describe.
I have the GUID of a principal as a parameter to which I need to assign several roles to resources I'm otherwise creating. I would like to scope the role assignment to a specific resource, but I'd also like to put this role assignment in a module so as not to duplicate it all over the place.
What I can't figure out is how to identify the resource in a manner that's acceptable to Bicep.
Here's what I'm starting with:
So the question is how to set the scope. This might be a load balancer, it might be a key vault - any number of things.
I've tried doing something like the following:
But this didn't work because "String interpolation isn't supported for specifying the resource type". Neither does this work:
This one gives the error "Expected a resource type string. Specify a valid resource type of format..."
So then I tried just passing in the resource as a parameter, but that doesn't work since 'resource' isn't a valid type. Given all that, how can I make a generic resource-typed role assignments module?
Thanks!
The text was updated successfully, but these errors were encountered: