Azure RBAC Custom Roles


Introduction


Azure supports Role-Based-Access-Control (RBAC) to controlling what actions a principal (user, service principal etc) can perform via the Azure Portal, XPlat Cli or Azure PowerShell module.

Azure provides quite a few built-in roles (48 at this time) but it is also possible to define your own custom roles. In this post I will provide a few general tips on RBAC and also how to go about creating your own custom roles.

Actions and NotActions

Actions are permissions/operations that you wish to allow and NotActions are ones that you wish to restrict. When assigning roles you need to be conscious of the fact that NotActions are not deny rules as mentioned in the Microsoft document:

If a user is assigned a role that excludes an operation in NotActions, and is assigned a second role that grants access to the same operation, the user will be allowed to perform that operation. NotActions is not a deny rule – it is simply a convenient way to create a set of allowed operations when specific operations need to be excluded.

View a list of the built-in roles


You can use the Get-AzureRmRoleDefinition cmdlet to view a list of built-in roles:

Get-AzureRmRoleDefinition | Select-Object Name, Description
Name                                              Description                                                                                                                               
----                                              -----------                                                                                                                               
API Management Service Contributor                Can manage service and the APIs                                                                                                           
API Management Service Operator Role              Can manage service but not the APIs                                                                                                       
API Management Service Reader Role                Read-only access to service and APIs                                                                                                      
Application Insights Component Contributor        Can manage Application Insights components


View a list of the custom roles 

You can view the list of custom roles (ones that you have created) available in the currently selected subscription by using the -Custom switch of the same cmdlet.

Get-AzureRmRoleDefinition -Custom


How to view the possible operations for a particular resource

When you are creating your own roles, you might want to see all the possible operations that can be permissioned for a particular resource type. In the example, below Microsoft.Sql/ represents Azure SQL Database and we use the Get-AzureRmProviderOperation cmdlet to search for all operations that begin with Microsoft.Sql/.

Get-AzureRmProviderOperation  `
    -OperationSearchString '*' | ? { $_.Operation -like 'Microsoft.Sql/*' } | select Operation,Description | Out-File azure-sql-permissions.txt


Creating a custom role


There are two ways to create a custom role .

  1. Write a role definition in JSON as shown in the Microsoft documentation; or
  2. If there is a built-in role close to what you need you can create a custom role based on an existing built-in (or indeed another custom role) and just modify the actions/notactions.

If you have a JSON role definition file you can create a new role definition using the command:

New-AzureRmRoleDefinition -InputFile my-role-definition-name.json


The PowerShell code below shows how you can create a custom role based on an existing one:

# Retrieve the role definition for the "Virtual Machine Contributor" built-in role
$role = Get-AzureRmRoleDefinition "Virtual Machine Contributor"
# Set the role Id to null as this will be automatically generated when we create a custom role
$role.Id = $null
# Give it a name and description
$role.Name = "My Limited VM Operator"
$role.Description = "Can monitor, stop, deallocate and restart virtual machines."
# Remove all actions in this case as we want to start fresh
# If you wanted to grant the default permissions for this role and add new permissions, you could skip this step.
$role.Actions.Clear()

$role.Actions.Add("Microsoft.Authorization/*/read")
    
$role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")

$role.Actions.Add("Microsoft.Compute/*/read")
$role.Actions.Add("Microsoft.Compute/virtualMachines/start/action")
$role.Actions.Add("Microsoft.Compute/virtualMachines/restart/action")
$role.Actions.Add("Microsoft.Compute/virtualMachines/powerOff/action")
$role.Actions.Add("Microsoft.Compute/virtualMachines/deallocate/action")

$role.Actions.Add("Microsoft.Network/networkInterfaces/read")
$role.Actions.Add("Microsoft.Compute/disks/read")

$role.Actions.Add("Microsoft.Insights/alertRules/read")
$role.Actions.Add("Microsoft.Insights/diagnosticSettings/read")

# Clear the scopes that this applies to
$role.AssignableScopes.Clear()
# Apply it to a specific resource group, note you would need to replace  with the actual subscription id
$role.AssignableScopes.Add("/subscriptions//resourceGroups/MyResourceGroup")

New-AzureRmRoleDefinition -Role $role


NOTE
There are two important points to be aware of when creating custom roles:

  • A custom role defined in one subscription is not visible in other subscriptions.
  • The role name must be unique to your Azure AD Tenant - e.g. if you want to use the same role definition across different subscription you will need to use a different name in each subscription - yes this is a pain and could cause some confusion.

Scopes

As you may have noticed from the code snippet above roles can be applied to multiple different scopes e.g. at the subscription level, resource group level or to an individual resource.

It is important to remember that access  that you grant at parent scopes is inherited at child scopes.

Modifying an existing custom role


The simplest way to modify an existing custom role is by retrieving the role definition via Get-AzureRmRoleDefinition and storing it in a variable, then adding/removing actions or changing the scope as required, and finally applying the changes with Set-AzureRmRoleDefinition.

# Modify our custom role
$customRoleToModify = Get-AzureRmRoleDefinition -Name 'MyCustomAzureRBACRole'
# Remove the ability to grant/modify permissions
$customRoleToModify.Actions.remove('Microsoft.Authorization/*/write')
# Add the ability to read Azure Application Insights rules
$customRoleToModify.Actions.add('Microsoft.Insights/alertRules/*')

Set-AzureRmRoleDefinition -Role $customRoleToModify


Example custom roles


I have added a few example custom roles to my GitHub repo here:
https://github.com/vijayjt/AzureScripts/tree/master/rbac/role-definitions

The only thing you'd need to change is the assignable scopes in order to make use of the role definitions.

There are only two roles in the repo at the moment:

  1. A custom virtual machine operator role: I created this role to meet a requirement I had to allow particular users to start/stop/restart VMs in a particular resource group
  2. A custom limited subscription contributor role: this role was created to remove some types of sensitive operations from a subscription contributor. Of course what you deem as sensitive will change based on your context and the users involved. The custom role just adds sensitive operations into the NotActions. Ideally you should use more specific roles and scope the appropriately - but you may be asked to provide such broad access. One of the problems with this approach is new resource types are added frequently that may be sensitive so you have to constantly update the role definition.

Comments