Common problem when using Azure resource groups & RBAC

** Before you start reading:

  • This article references a lot of PowerShell commands. Read this post to get up to speed on how to use Azure PowerShell module
  • Long PowerShell scripts in this article have been wrapped to multiple lines to be readable, make sure you use a single line when you try to execute them
  • Snapshots and scripts have been modified to remove account identifying information for security reasons

AzureClassic

Since the introduction of Azure resource manager aka ARM, a lot of organizations started looking at how they can leverage ARM to better manage Azure resources for their different business groups within a company.

In the past, before the introduction of ARM, it was very common to manage resources on two levels:

  • Cloud services
  • Subscription level

The later (subscription level) was the common model for enterprises since it provides some sort of isolation from resources and security perspective.

So, if you have a specific workload were all resources in that workload share the same lifecycle or belong to the same business group, that workload would be organized under a separate Azure subscription.

Under that model (Azure classic resources) you can only have two different security roles:

  • Service administrator
  • Co-administrator

Both roles have full admin rights on the subscription level, the only difference between the two is that ‘Co-administrators’ can’t change the association of subscriptions to Azure directories.

For more details about the above roles go to: https://azure.microsoft.com/en-us/documentation/articles/billing-add-change-azure-subscription-administrator/

After the introduction of the ARM model aka v2.0 resources, organizations started looking at leveraging resource groups as another level of management and isolation for different workloads in Azure.

Moreover, role based access control provided a much better way to manage permissions overall. One of the common implementation is to create few azure subscriptions (think of them as separate billing points or buckets). Each subscription might belong to a specific business group, for instance: HR, Finance, IT, Engineering …etc.

Then, under these subscriptions, different Azure resource groups are created to provide another layer of isolation between workloads. Resources can be organized under a single resource group if they share one of the following attributes:

  • Location (US West, Germany Central …etc.)
  • Level (Production, Test, Development …etc.)
  • Workload (Web application, Data warehouse, BI …etc.)

[caption id="attachment_145" align="aligncenter" width="548"]RBAC The RBAC role that you assign dictates what resources the user, group, or application can manage within that scope. [Source: Microsoft][/caption]To allow different business groups to manage their resource groups in a self-service manner, subscription admins provide owner rights to individuals on their perspective resource groups. This will allow these resource group owners to create, delete & manage any resources only within their assigned resource group.

A resource group owner should have all the permissions he/she needs to manage resources in the resource group. It’s the highest level of permissions on the resource group level.

A resource group owner can grant other users permissions on the resource group level.

There are three main built-in roles that comes out-of-the-box:

  • Owner: Full access
  • Contributor: Full access but cannot grant others permissions
  • Reader: View only access

For more information about RBAC go here.

Common issue

One of the issues administrators have been facing, is receiving complaints from resource group owners about the inability of creating certain types of resources due to lack of enough permissions. So for instance when a resource group owners tris to create an “IoT Hub” resource, they get the following error:

“The subscription {{SUBSCRIPTION_NAME}} doesn’t have permissions to register resource provider: Microsoft.Devices.” Error creating a resource

or during the validation process they get the following error:

‘AuthorizationFaild’ – The client ‘{{USER_ACCOUNT}}’ with object id ’{{OBJECT_ID}}’ does not have authorization to perform action ‘Microsoft.Devices/register/action’ over scope ‘/subscriptions/{{SUBSCRIPTION_ID}}.(Code: AuthorizationFailed)(Code: 8) Validation error

This issue is more likely to happen in newer subscriptions and usually happens if a certain resource type has never been created before in that subscription.

Subscription admins often fix this issue by granting resource group owners contributor rights on the subscription level which contradicts with their strategy of isolating access down to the level of resource group level not the subscription level.

Root cause

Some admins say, that some resources require access to the subscription level to be able to create these resources and that ‘owner’ rights on a resource group level is not sufficient. That is not true.

Let’s take a step back to understand how this all works first.

To provision any resources in azure (using the resource manager model) you need to have a resource provider that supports the creation of that resource. For example, if you will provision a virtual machine, you need to have a ‘Microsoft.Compute’ resource provider available in the subscription first before you can do that.

Resource providers are registered on the level of the subscription only.

Luckily, the Azure Resource Manager (ARM) is intelligent enough to figure that out for you. When a new Azure resource gets provisioned, if the resource provider required for that resource type is not registered in the subscription yet, ARM will attempt to register it for you. That action (resource provider registration) requires access to the subscription level.

By default, any new azure subscription will be pre-registered with a list of commonly used resource providers. The resource provider for IoTHub for instance, is not one of them.

When a user is granted owner rights only on a specific resource group, if that user tries to provision a resource that requires registering a resource provider for the first time, that operation will fail. That is what happened in our case above when trying to provision IoThub.

So the bottom line is, we *DO NOT* need to grant access permissions to the subscription level for users to be able to create resources like HDInsight, IotHub and SQLDW …etc within their resource groups that they have owner rights on, as long as the resource providers for these resources is already registered.

To get a list of registered resource providers in the current subscription run the following command:

 get-AzureRmResourceProvider -ListAvailable |where {$_.Registrationstate -eq "Registered"}

Quick resolution

The issue should be easier to understand now after the above explanation. The issue is that we need to make sure that we have the resource provider registered in the subscription before we attempt to create resources. If we don’t, we need to make sure that the user creating the new resource has enough rights to register the required resource provider on the subscription level

To fix the issue in hand Look at the error message to figure out what resource provider needs to be registered. In our case, it is: “Microsoft.Devices”. Have a subscription admin run the following PowerShell command to register that resource for you:

Register-AzureRmResourceProvider -ProviderNamespace Microsoft.Devices

Long-term resolution

The solution we have provided above addresses only that particular instance of the problem. If you have another user that tries to create a resource that requires a different provider that is not registered yet and that user only has owner rights on his resource group, the user will fall into the same issue again.

In order to maintain the resource groups owners model and still be able to create all kinds of resources, and yet don’t fall into the issue described above we have to implement *one* of the following solutions:

  1. Preregister all providers in a subscription
  2. Create a custom RBAC role to permit registration of resources providers to resource group owners

1- Preregister all providers in a subscription

If we have a limited number of subscriptions that doesn’t change often, we can run a PowerShell command to preregister all available providers to each subscription. The only downside here is that every time a new service is added to Azure including Azure marketplace you will need to run a PowerShell command to register the new providers for these new services.

To get a list of all available resource providers run the following PowerShell command:

 get-AzureRmResourceProvider -ListAvailable | select ProviderNamespace

GetResourceProviders

To register all available resource providers in the current subscription run the following PowerShell command:

 get-AzureRmResourceProvider -ListAvailable | foreach-object{Register-AzureRmResourceProvider -ProviderNamespace $_.ProviderNamespace}

To register a resource provider (e.g. the one required for provisioning IoT Hub resources) run the following command:

 Register-AzureRmResourceProvider -ProviderNamespace Microsoft.Devices

2- Create a custom RBAC role to permit registration of resources providers to resource group owners

This solution will leverage a custom RBAC role to enable resource group owners to have the ability to register resource providers to subscriptions. The custom RBAC role will grant *ONLY* registration rights on the subscription, this role should be assigned in-addition to the resource group owner built-in role:

Here is the definition of the custom role:

 {
"Name": "Register Microsoft providers",
"Description": "Can register Microsoft providers",
"Actions": [ "*/register/action" ],
"AssignableScopes": [ "/subscriptions/[SUBSCRIPTION1_ID_GOES_HERE]",
"/subscriptions/[SUBSCRIPTION2_ID_GOES_HERE]",
"/subscriptions/[SUBSCRIPTION3_ID_GOES_HERE]" ]
}

Replace ‘[SUBSCRIPTION1_ID_GOES_HERE], [SUBSCRIPTION2_ID_GOES_HERE] …etc.’ with all subscription ids that you would like this role to be associated to.

** Please note that custom role definition objects span subscriptions and sit on the AAD tenant level. That means you can only have uniquely named custom roles defined across all subscriptions in a single tenant. So make sure you include all the subscriptions ids you want to include in the above custom role definition in the assignable scopes section.

Here is how to create a custom role using PowerShell:

First save the custom role definition listed above in a file called MycustomRole.json then run the following command:

 New-AzureRmRoleDefinition -InputFile C:\MycustomRole.json

NewCustomRBACPS

Now you can go to the portal and assign this custom role to users or security groups (in our case to resource owners):

AddUserPermission

What happens to newly created subscriptions?

In future, newly added subscriptions will not have the custom role associated to them. To make the new custom role you created above available and applies to new subscriptions, run the following PowerShell script to update the existing custom role to include the new subscriptions:

 $role = Get-AzureRmRoleDefinition -Name "Register Microsoft providers"
$role.AssignableScopes.Add("/subscriptions/[NEW_SUBSCRIPTION_ID_GOES_HERE]")   ##[[Repeat this step to add all the subscriptions you want to add]]
Set-AzureRmRoleDefinition -Role $role

Additional resources: