Define a custom role using Bicep template
Published: 2022-11-09 09:45:00

In this post I would like to show you how you can define a custom role in your subscriptions using a Bicep template.
First of all, I suggest you read the official documentation ([here](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles)) to understand what a built-in Role in Azure is.
Remember that it is very important to assign the permissions strictly necessary so that an identity can do its job at the best. In some real-world scenarios, it may happen that you cannot find a role that has the necessary permissions. In this case you must define your custom role.
You can find more information about custom roles and how you can define it in the [official documentation](https://learn.microsoft.com/en-us/azure/role-based-access-control/custom-roles).

For this post, we suppose we want to give, to our identities, the capabilities to read blobs inside a storage account using the Azure portal.

If we look at the built-in roles, we find a role called "Storage Blob Data Reader" with the following definition

```json
{
    "properties": {
        "roleName": "Storage Blob Data Reader",
        "description": "Allows for read access to Azure Storage blob containers and data",
        "assignableScopes": [
            "/"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.Storage/storageAccounts/blobServices/containers/read",
                    "Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action"
                ],
                "notActions": [],
                "dataActions": [
                    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read"
                ],
                "notDataActions": []
            }
        ]
    }
}
```

It seems the right one, but if we try, for example, to assign this role to a user on a storage account, that user will not see the storage in the Azure portal, so he/she cannot read any blob inside it using the portal.  
To achieve our goal, we need to create a custom role adding a couple of operation to the "actions" section.

```json
{
   "properties": {
        "roleName": "Custom Storage Data Reader",
        "description": "",
        "assignableScopes": [
            "/"
        ],
        "permissions": [
            {
                "actions": [
                    "Microsoft.Resources/resources/read",
                    "Microsoft.Storage/storageAccounts/read",
                    "Microsoft.Storage/storageAccounts/blobServices/read",
                    "Microsoft.Storage/storageAccounts/blobServices/containers/read",
                    "Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action"
                ],
                "notActions": [],
                "dataActions": [
                    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read"
                ],
                "notDataActions": []
            }
        ]
    }
}
```

To add the custom role to the collection of the roles inside our Azure subscription we can use the portal, Azure CLI/Azure Powershell or we can define the following Bicep template:

```
targetScope = 'subscription'

var roleDefinitionName = guid(subscription().id, string(actions), string(notActions), string(dataActions), string(notDataActions))

var roleName = 'Custom Storage Data Reader'

var actions = [
  'Microsoft.Resources/resources/read'
  'Microsoft.Storage/storageAccounts/read'
  'Microsoft.Storage/storageAccounts/blobServices/read'
  'Microsoft.Storage/storageAccounts/blobServices/containers/read'
  'Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action'
]

var notActions = [
]

var dataActions = [
  'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'
]

var notDataActions = [
]

resource customRoleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
  name: roleDefinitionName
  properties: {
    roleName: roleName
    description: ''
    type: 'customRole'
    permissions: [
      {
        actions: actions
        notActions: notActions
        dataActions: dataActions
        notDataActions: notDataActions
      }
    ]
    assignableScopes: [
      subscription().id
    ]
  }
}

```

The `roleDefinition` resource must have a `name` property as GUID. For this reason, in the previous template, we generate it starting from the subscription id and the actions sections (with this way, we are sure that the GUID will be reasonable unique for different role definitions).

Finally, to deploy the definition in a subscription you can use the following az command:

```bash
az deployment sub create --location <your region> --template-file customRole.bicep --subscription <name or ID of the subscription>
```

where:

- `<your region>` is the region you want to use for the deployment (e.g. `northeurope`);
- `customRole.bicep` is the file name of the previous template (you can save the template with the name you prefer and use it here);
- `<name or ID of the subscription>` the name or the ID of the subscripton you want to deploy the role to.