Apply Azure RBAC to a resource using ARM
Asked Answered
A

5

12

Is there a way to apply RBAC rules at the resource level via ARM? I was able to follow this Microsoft guide to add a user/role at the resource group level, but not at the resource. In particular, I am trying to add a new reader role to AppInsights via ARM. However, when I adjust the scope, the template just fails with this error:

"error": {
"code": "InvalidCreateRoleAssignmentRequest",
"message": "The request to create role assignment '{guid}' is not valid. Role assignment scope '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/Microsoft.Insights/components/{resourceGroupName}' must match the scope specified on the URI  '/subscriptions/{resourceGroupName}/resourcegroups/{resourceGroupName}'."
  }

I am left wondering what the scope variable is for if it cannot be changed. Is there some other place I should be modifying the scope to get this working?

Thanks in advance!

Acker answered 14/9, 2018 at 23:54 Comment(1)
henrybeen.nl/…Hans
H
10

The key is to drop the scope property, and instead nest the role assignment under the desired resource by using Microsoft.FooResource/BarSubType/providers/roleAssignments as the type, and using the following format for the name: {resourceName}/Microsoft.Authorization/{uniqueRoleAssignmentGuid}. Note that the GUID should be stable but unique to this role assignment, one easy option is guid(subscription().subscriptionId, 'some-sub-identifier-if-you-wish').

Here is a template that shows you how to apply RBAC to a single resource, using a user-assigned managed identity defined in the same template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": { 
      "storageAccountName": { "type": "string" },
      "userAssignedIdentityName": { "type": "string" }
  },
  "variables": {
    "ContributorRoleDefinition": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
  },
  "resources": [
    {
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
      "name": "[parameters('userAssignedIdentityName')]",
      "location": "[resourceGroup().location]",
      "apiVersion": "2018-11-30"
    },
    {
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[parameters('storageAccountName')]",
      "location": "[resourceGroup().location]",
      "apiVersion": "2016-12-01",
      "sku": { "name": "Standard_LRS" },
      "kind": "Storage",
      "resources": [
          {
              "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
              "apiVersion": "2017-05-01",
              "name": "[concat(parameters('storageAccountName'), '/Microsoft.Authorization/', guid(subscription().subscriptionId, 'foo'))]",
              "properties": {
                "roleDefinitionId": "[variables('ContributorRoleDefinition')]",
                "principalId": "[reference(parameters('userAssignedIdentityName'), '2018-11-30').principalId]"
              },
              "dependsOn": [
                  "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
                  "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]"
              ]
         }
      ]
    }
  ]
}

Source: https://www.henrybeen.nl/creating-an-authorization-rule-using-an-arm-template/

Hans answered 22/5, 2019 at 18:28 Comment(2)
For me this is the right solution but its more clear to read the henrybeen example. The key is the name and the scope.Nickolas
Correct answer but as @Nickolas suggests: just read the answer by henrybeenCristacristabel
P
1

You apply RBAC rules at the resource level via an ARM and there is example template that applies RBAC rules at Azure VM here:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "principalId": {
            "type": "string",
            "metadata": {
                "description": "Principal ID associated with the subscription ID"
            }
        },
        "virtualMachineName": {
            "type": "string",
            "metadata": {
                "description": "Name of the virtual machine"
            }
        },
        "builtInRoleType": {
            "type": "string",
            "metadata": {
                "description": "Built In Role Type for the Virtual Machine"
            },
            "allowedValues": [
                "Owner",
                "Contributor",
                "Reader",
                "Virtual Machine Contributor"
            ]
        },
        "guid": {
            "type": "string",
            "metadata": {
                "description": "A new GUID used to identify the role"
            }
        },
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]",
            "metadata": {
                "description": "Location for all resources."
            }
        }
    },
    "variables": {
        "Owner": "[concat('/subscriptions/',subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
        "Contributor": "[concat('/subscriptions/',subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
        "Reader": "[concat('/subscriptions/',subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
        "Virtual Machine Contributor": "[concat('/subscriptions/',subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'd73bb868-a0df-4d4d-bd69-98a00b01fccb')]",
        "resourceName": "[concat(parameters('virtualMachineName'), '/Microsoft.Authorization/', parameters('guid'))]"
    },
    "resources": [
        {
            "type": "Microsoft.Compute/virtualMachines/providers/roleAssignments",
            "apiVersion": "2017-05-01",
            "name": "[variables('resourceName')]",
            "properties": {
                "roleDefinitionId": "[variables(parameters('builtInRoleType'))]",
                "principalId": "[parameters('principalId')]"
            }
        }
    ]
}

Hope this will help you.

Podophyllin answered 17/9, 2018 at 3:21 Comment(9)
Interesting. So you are saying that we can apply apply at the resource level, but it looks like the type and name fields have to change quite a bit in the ARM template. Could you help me in finding the appropriate resource type and name that would apply an RBAC to an AppInsight resource?Acker
You can try to change like this "type": "microsoft.insights/components/providers/roleAssignments" for the resource.Podophyllin
I get an error when just changing the type: Deployment template validation failed: 'The template resource {guid} for type 'microsoft.insights/components/providers/roleAssignments' at line '1' and column '7721' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see aka.ms/arm-template/#resources for usage details.'.Acker
The guid is the subscription id which the ApplicationInsight in.Podophyllin
Same error. The roleDefinitionId and principalId definitive work. Still can't find a type and name that work. Here is where I am at: { "type": "microsoft.insights/components/providers/roleAssignments", "apiVersion": "2017-05-01", "name": "[subscription().subscriptionId]", "properties": { "roleDefinitionId": "[variables('MonitoringReaderAzureSecurityGroup')]", "principalId": "[variables('AppInsightsReadOnlyPrincipalId')]" }, "dependsOn": [ "[resourceId('Microsoft.Insights/components/', parameters('websiteName'))]" ] }Acker
You can also follow the example here. You can change the scope into a parameter to input your ApplicationInsight Id.Podophyllin
Added "scope": "[resourceId('Microsoft.Insights/components/', parameters('websiteName'))]". I received the same error as posted in the original question. I also linked that same example in the documentation. So we have come full circle and are back to where I started... The scope variable doesn't work as you or I anticipated. It is either 'scope' is broken here or we are still missing something....Acker
@DilipRaghunathan That's great if it can help you.Podophyllin
@Acker the problem with the template in your comment above is the name. It has to be of the form [concat(parameters('appInsightsResourceName'), '/Microsoft.Authorization/', guid(...))]. Note that guid(...) should be stable but unique to this role assignment, one easy option is guid(subscription().subscriptionId) (for example ``). You must not specify a scope.Hans
A
1

Microsoft has finally provided documentation explaining this:

https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-template#resource-scope

Alanalana answered 31/7, 2020 at 1:9 Comment(0)
T
0

It is possible to apply RBAC on resource level using ARM.

The example what you referred shows how to apply RBAC on a particular resource group, where the scope is the path of the resource group.

Here, you are trying to assign a role to a particular resource. Changing the scope from resource group to resource (AppInsights) will work.

From the exception, I can see that the path of the resource may not be in the expected format.

The path of AppInsights should be in the following format,

/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/microsoft.insights/components/{insightName}

Hope framing the scope like this helps!

Tarryn answered 16/9, 2018 at 8:17 Comment(1)
When you say 'path of AppInsights' and I assume you are meaning that I need to modify my scope setting. I added '/providers' to my scope like you suggested and have received the following (which is similar to what I got initially): The request to create role assignment '{guid}' is not valid. Role assignment scope '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/microsoft.insights/components/{insightName}' must match the scope specified on the URI '/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}. Thoughts?Acker
A
0

Agree that the documentation on this issue is less than useful. I have an array of Role IDs that I wanted to add as Owners at the App Insight resource, without making the users Owners at the Resource Group level. I didn't want to use the nested resource approach as I wanted to iterate over an array of objects to dynamically create the roles, so after tweaking the type, name, and scope attributes, the following resource block is what ended up working for me:

    {
      "comments": "Add the Application Insights resource",
      "apiVersion": "2014-04-01",
      "name": "[variables('appInsightsName')]",
      "type": "Microsoft.Insights/components",
      "location": "[resourceGroup().location]",
      "properties": {
        "ApplicationId": "[variables('appInsightsName')]"
      }
    },
    {
      "comments": "Add the IAM roles to the App Insights resource",
      "condition": "[parameters('isProduction')]",
      "type": "Microsoft.Insights/components/providers/roleAssignments",
      "name": "[concat(variables('appInsightsName'),'/Microsoft.Authorization/',guid(parameters('roleAssignments')[copyIndex()].principalId))]",
      "apiVersion": "2017-05-01",
      "location": "[resourceGroup().location]",
      "properties": {
        "roleDefinitionId": "[concat(subscription().Id, '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", // Owner Role
        "principalId": "[parameters('roleAssignments')[copyIndex()].principalId]",
        "scope": "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
      },
      "copy": {
        "name": "appInsightsRoleAssignments",
        "count": "[length(parameters('roleAssignments'))]"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
      ]
    }
Abecedarium answered 7/10, 2020 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.