Create or update Azure custom roles using an ARM template

If the Azure built-in roles don't meet the specific needs of your organization, you can create your own custom roles. This article describes how to create or update a custom role using an Azure Resource Manager template (ARM template).

An ARM template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax. In declarative syntax, you describe your intended deployment without writing the sequence of programming commands to create the deployment.

To create a custom role, you specify a role name, permissions, and where the role can be used. In this article, you create a role named Custom Role - RG Reader with resource permissions that can be assigned at a subscription scope or lower.

If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template will open in the Azure portal.

Deploy to Azure

Prerequisites

To create a custom role, you must have:

Review the template

The template used in this article is from Azure Quickstart Templates. The template has four parameters and a resources section. The four parameters are:

  • Array of actions with a default value of ["Microsoft.Resources/subscriptions/resourceGroups/read"].
  • Array of notActions with an empty default value.
  • Role name with a default value of Custom Role - RG Reader.
  • Role description with a default value of Subscription Level Deployment of a Role Definition.

The scope where this custom role can be assigned is set to the current subscription.

{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "actions": {
      "type": "array",
      "defaultValue": [
        "Microsoft.Resources/subscriptions/resourceGroups/read"
      ],
      "metadata": {
        "description": "Array of actions for the roleDefinition"
      }
    },
    "notActions": {
      "type": "array",
      "defaultValue": [],
      "metadata": {
        "description": "Array of notActions for the roleDefinition"
      }
    },
    "roleName": {
      "type": "string",
      "defaultValue": "Custom Role - RG Reader",
      "metadata": {
        "description": "Friendly name of the role definition"
      }
    },
    "roleDescription": {
      "type": "string",
      "defaultValue": "Subscription Level Deployment of a Role Definition",
      "metadata": {
        "description": "Detailed description of the role definition"
      }
    }
  },
  "variables": {
    "roleDefName": "[guid(subscription().id, string(parameters('actions')), string(parameters('notActions')))]"
  },
  "resources": [
    {
      "type": "Microsoft.Authorization/roleDefinitions",
      "apiVersion": "2018-07-01",
      "name": "[variables('roleDefName')]",
      "properties": {
        "roleName": "[parameters('roleName')]",
        "description": "[parameters('roleDescription')]",
        "type": "customRole",
        "isCustom": true,
        "permissions": [
          {
            "actions": "[parameters('actions')]",
            "notActions": "[parameters('notActions')]"
          }
        ],
        "assignableScopes": [
          "[subscription().id]"
        ]
      }
    }
  ]
}

The resource defined in the template is:

Deploy the template

Follow these steps to deploy the previous template.

  1. Sign in to the Azure portal.

  2. Open Azure Cloud Shell for PowerShell.

  3. Copy and paste the following script into Cloud Shell.

    $location = Read-Host -Prompt "Enter a location (i.e. centralus)"
    [string[]]$actions = Read-Host -Prompt "Enter actions as a comma-separated list (i.e. action1,action2)"
    $actions = $actions.Split(',')
    $templateUri = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/subscription-deployments/create-role-def/azuredeploy.json"
    New-AzDeployment -Location $location -TemplateUri $templateUri -actions $actions
    
  4. Enter a location for the deployment such as centralus.

  5. Enter a list of actions for the custom role as a comma-separated list such as Microsoft.Resources/resources/read,Microsoft.Resources/subscriptions/resourceGroups/read.

  6. If necessary, press Enter to run the New-AzDeployment command.

    The New-AzDeployment command deploys the template to create the custom role.

    You should see output similar to the following:

    PS> New-AzDeployment -Location $location -TemplateUri $templateUri -actions $actions
    
    Id                      : /subscriptions/{subscriptionId}/providers/Microsoft.Resources/deployments/azuredeploy
    DeploymentName          : azuredeploy
    Location                : centralus
    ProvisioningState       : Succeeded
    Timestamp               : 6/25/2020 8:08:32 PM
    Mode                    : Incremental
    TemplateLink            :
                              Uri            : https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/subscription-deployments/create-role-def/azuredeploy.json
                              ContentVersion : 1.0.0.0
    
    Parameters              :
                              Name               Type                       Value
                              =================  =========================  ==========
                              actions            Array                      [
                                "Microsoft.Resources/resources/read",
                                "Microsoft.Resources/subscriptions/resourceGroups/read"
                              ]
                              notActions         Array                      []
                              roleName           String                     Custom Role - RG Reader
                              roleDescription    String                     Subscription Level Deployment of a Role Definition
    
    Outputs                 :
    DeploymentDebugLogLevel :
    

Review deployed resources

Follow these steps to verify that the custom role was created.

  1. Run the Get-AzRoleDefinition command to list the custom role.

    Get-AzRoleDefinition "Custom Role - RG Reader" | ConvertTo-Json
    

    You should see output similar to the following:

    {
      "Name": "Custom Role - RG Reader",
      "Id": "11111111-1111-1111-1111-111111111111",
      "IsCustom": true,
      "Description": "Subscription Level Deployment of a Role Definition",
      "Actions": [
        "Microsoft.Resources/resources/read",
        "Microsoft.Resources/subscriptions/resourceGroups/read"
      ],
      "NotActions": [],
      "DataActions": [],
      "NotDataActions": [],
      "AssignableScopes": [
        "/subscriptions/{subscriptionId}"
      ]
    }
    
  2. In the Azure portal, open your subscription.

  3. In the left menu, select Access control (IAM).

  4. Select the Roles tab.

  5. Set the Type list to CustomRole.

  6. Verify that the Custom Role - RG Reader role is listed.

    New custom role in Azure portal

Update a custom role

Similar to creating a custom role, you can update an existing custom role by using a template. To update a custom role, you must specify the role you want to update.

Here are the changes you would need to make to the previous Quickstart template to update the custom role.

  • Include the role ID as a parameter.

        ...
        "roleDefName": {
          "type": "string",
          "metadata": {
            "description": "ID of the role definition"
          }
        ...
    
  • Include the role ID parameter in the role definition.

      ...
      "resources": [
        {
          "type": "Microsoft.Authorization/roleDefinitions",
          "apiVersion": "2018-07-01",
          "name": "[parameters('roleDefName')]",
          "properties": {
            ...
    

Here's an example of how to deploy the template.

$location = Read-Host -Prompt "Enter a location (i.e. centralus)"
[string[]]$actions = Read-Host -Prompt "Enter actions as a comma-separated list (i.e. action1,action2)"
$actions = $actions.Split(',')
$roleDefName = Read-Host -Prompt "Enter the role ID to update"
$templateFile = "rg-reader-update.json"
New-AzDeployment -Location $location -TemplateFile $templateFile -actions $actions -roleDefName $roleDefName

Clean up resources

To remove the custom role, follow these steps.

  1. Run the following command to remove the custom role.

    Get-AzRoleDefinition -Name "Custom Role - RG Reader" | Remove-AzRoleDefinition
    
  2. Enter Y to confirm that you want to remove the custom role.

Next steps