azureazure-resource-managerazure-bicep

Azure Bicep - Referencing a variable that cannot be calculated at the start


I need to:

The data factory is created in a separate module from the "main" bicep. This is to prevent the "main" template being so large it is difficult to work with - one of the main benefits of bicep over arm templates. Same goes for creation of the function app.

For the role assignment I have:

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
  name: guid(storageAccount.id, contributorRoleId, adfDeploy.outputs.dfId)

VSCode then presents the following "problem":

This expression is being used in an assignment to the "name" property of the "Microsoft.Authorization/roleAssignments" type, which requires a value that can be calculated at the start of the deployment. Properties of adfDeploy which can be calculated at the start include "name".

I can't compose the storageAccount Id from a string (subscription/rg/resource etc.) because the subscription id is also determined at runtime since the same main bicep is called for deployment to multiple subscriptions.

Is there any way to achieve what's needed without pulling back the creation of the data factory and function apps to the "main" bicep?


Solution

  • You could create a generic module for storage role assignment:

    // storage-account-role-assignment.bicep
    param storageAccountName string
    param principalId string
    param roleId string
    
    // Get a reference to the storage account
    resource storageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {
      name: storageAccountName
    }
    
    // Grant permissions to the storage account
    resource storageAccountAppRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' =  {
      name: guid(storageAccount.id, roleId, principalId)
      scope: storageAccount
      properties: {
        roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId)
        principalId: principalId
      }
    }
    

    Then invoke this module from where you are creating data factory or function app:

    // function-app.bicep
    ...
    resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
      name: functionAppName
      kind: 'functionapp'
      identity: {
        type: 'SystemAssigned'
      }
      ...
    }
    
    // Create role assignment
    module roleAssignment 'storage-account-role-assignment.bicep' = {
      name: 'function-storage-account-role-assignment'
      scope: resourceGroup()
      params:{
        storageAccountName: storageAccountName
        roleId: '<role-id>'
        principalId: functionApp.identity.principalId
      }
    }
    
    // data-factory.bicep
    ...
    resource dataFactory 'Microsoft.DataFactory/factories@2018-06-01' = {
      name: name
      identity: {
        type: 'SystemAssigned'
      }
      ...
    }
    
    // Create role assignment
    module roleAssignment 'storage-account-role-assignment.bicep' = {
      name: 'data-facory-storage-account-role-assignment'
      scope: resourceGroup()
      params:{
        storageAccountName: storageAccountName
        roleId: '<role-id>'
        principalId: dataFactory.identity.principalId
      }
    }