egib
egib

Reputation: 31

Role Assignment multiple Azure Functions to the same storage account in an ARM template

I've been trying to update an ARM template which creates a stack of resources on Azure.

I am trying to add the functions as Reader and Data Access assignments to the storage account. Adding only one works just fine, although even that took a while to get it working. When I try to add multiple my template won't even validate, because of this error : "code":"InvalidTemplate","message":"Deployment template validation failed: 'The resource 'Microsoft.Storage/storageAccounts/strgegitestv2qaeu/providers/Microsoft.Authorization/roleAssignments/3273386b-cde7-5e43-a242-a64d4ed23bee' at line '208' and column '9' is defined multiple times in a template. Please see https://aka.ms/arm-template/#resources for usage details.'.","additionalInfo":[{"type":"TemplateViolation","info":{"lineNumber":208,"linePosition":9,"path":"properties.template.resources[1]"}}]}

Now I believe I understand why that is, I'm basically calling the same roleAssignment multiple times, when what I believe I should do is create a GUID for each function service identity and call those. Problem is I'm not sure how to do that exactly, can't find enough information in the documentation or anywhere online. This is a snippet of my ARM template :

"variables": {
"storageAccountName": "[concat('strg', variables('commonId'))]",
"readeranddataaccess": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'c12c1c16-33a1-487b-954d-41c89c60f349')]",
"servicekeyoperatorrole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '81a9662b-bebf-436f-a333-f67b29880f12')]",
"TestVariable": "[concat(variables('storageAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]"
}

"resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2020-08-01-preview",
            "name": "[variables('storageAccountName')]",
            "location": "[variables('location')]",
            "sku": {
                "name": "Standard_RAGRS",
                "tier": "Standard"
            },
            "kind": "StorageV2",
            "properties": {
                "minimumTlsVersion": "TLS1_2",
                "allowBlobPublicAccess": true,
                "allowSharedKeyAccess": true,
                "networkAcls": {
                    "bypass": "AzureServices",
                    "virtualNetworkRules": [],
                    "ipRules": [],
                    "defaultAction": "Allow"
                },
                "supportsHttpsTrafficOnly": true,
                "encryption": {
                    "services": {
                        "file": {
                            "keyType": "Account",
                            "enabled": true
                        },
                        "blob": {
                            "keyType": "Account",
                            "enabled": true
                        }
                    },
                    "keySource": "Microsoft.Storage"
                },
                "accessTier": "Hot"
            },"resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2020-08-01-preview",
            "name": "[variables('storageAccountName')]",
            "location": "[variables('location')]",
            "sku": {
                "name": "Standard_RAGRS",
                "tier": "Standard"
            },
            "kind": "StorageV2",
            "properties": {
                "minimumTlsVersion": "TLS1_2",
                "allowBlobPublicAccess": true,
                "allowSharedKeyAccess": true,
                "networkAcls": {
                    "bypass": "AzureServices",
                    "virtualNetworkRules": [],
                    "ipRules": [],
                    "defaultAction": "Allow"
                },
                "supportsHttpsTrafficOnly": true,
                "encryption": {
                    "services": {
                        "file": {
                            "keyType": "Account",
                            "enabled": true
                        },
                        "blob": {
                            "keyType": "Account",
                            "enabled": true
                        }
                    },
                    "keySource": "Microsoft.Storage"
                },
                "accessTier": "Hot"
            },
{
            "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[concat(variables('TestVariable'))]",
            "properties": {
                "roleDefinitionId": "[variables('readeranddataaccess')]",
                "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functioName1')), '2018-02-01', 'Full').identity.principalId]",
                "principalType": "ServicePrincipal"
            }
        },
        {
            "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[concat(variables('TestVariable'))]",
            "properties": {
                "roleDefinitionId": "[variables('readeranddataaccess')]",
                "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functionName2')), '2018-02-01', 'Full').identity.principalId]",
                "principalType": "ServicePrincipal"
            }
        },
        {
            "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[concat(variables('TestVariable'))]",
            "properties": {
                "roleDefinitionId": "[variables('readeranddataaccess')]",
                "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functionName3')), '2018-02-01', 'Full').identity.principalId]",
                "principalType": "ServicePrincipal"
            }
        },
        {
            "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[concat(variables('TestVariable'))]",
            "properties": {
                "roleDefinitionId": "[variables('readeranddataaccess')]",
                "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functionName4')), '2018-02-01', 'Full').identity.principalId]",
                "principalType": "ServicePrincipal"
            }
        }


If that is indeed the issue how can I create a GUID for each of the SystemManaged Identities of my Functions and call them to the "name" of my RoleAssignments?

Upvotes: 0

Views: 525

Answers (1)

bmoore-msft
bmoore-msft

Reputation: 8727

The name of your roleAssignment needs to be unique in the tenant - based on the principal, role and scope of the assignment. In your case you can do something like this:

guid(resourceId('Microsoft.Web/sites', variables('functionName1')), resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), variables('readanddataaccess'))

Note that the variables('functionName1') would match the principal - so functionName1, functionName2, ... as needed for each roleAssignment.

That help?


Ok, try this (this is relatively new and meant to simplify that segmenting problem):

"variables": {
    "raNameFunctionApp1": "[guid(resourceId('Microsoft.Web/sites', variables('functionName1')), resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), variables('readanddataaccess'))]"
},
...
{
    "scope": "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
    "type": "Microsoft.Authorization/roleAssignments",
    "apiVersion": "2020-04-01-preview",
    "name": "[variables('raNameFunctionApp1'))]",
    "properties": {
        "roleDefinitionId": "[variables('readeranddataaccess')]",
        "principalId": "[reference(resourceId('Microsoft.Web/sites', variables('functionName1')), '2018-02-01', 'Full').identity.principalId]",
        "principalType": "ServicePrincipal"
    }
},

Upvotes: 1

Related Questions