Azure · Key Vault · Security

Azure Managed HSM – AccessDenied when creating a Role Assignment

Recently I needed to allow development teams to manage access to their own keys in an Azure Key Vault Managed HSM, without granting permissions to the entire HSM.

In short, the idea was to use the Managed HSM Policy Administrator role at the scope of a key. This way, each team could create and remove Role Assignments only for the key under their responsibility.

That’s when I received an AccessDenied using the Azure CLI, but when I checked the key, I noticed that the permission had been created anyway.

Let me show what happened.

Scenario

The user executing the command had the Managed HSM Policy Administrator role at the scope /keys/my-key.

According to the documentation, this role allows creating and removing Role Assignments. When assigned at /keys/<key-name>, the permission is limited to that key.

So I ran the following command to grant Managed HSM Crypto User to a Managed Identity:

az keyvault role assignment create \
  --hsm-name <hsm-name> \
  --assignee-object-id <object-id> \
  --assignee-principal-type ServicePrincipal \
  --role "Managed HSM Crypto User" \
  --scope "/keys/my-key"

Error

Even with the permission on the key’s scope, I received the following error:

ERROR: (AccessDenied) Not authorized to access
Microsoft.KeyVault/managedHsm/roleAssignments/read/action on /

Looking at the message, I noted that the access denied happened at /, which is the root scope of the HSM, and not at /keys/my-key, which was the scope used in the command.

Up to this point, I thought that the Role Assignment had not been created.

But when querying the key’s permissions, the new Role Assignment was there.

In other words, the Azure CLI showed an error, but the operation was completed.

Verifying whether the Role Assignment was created

To confirm, you can list the permissions using the same scope as the key:

az keyvault role assignment list \
  --hsm-name <hsm-name> \
  --scope "/keys/my-key" \
  --query "[?principalId=='<object-id>'].{role:roleName, scope:scope, principalId:principalId}" \
  --output table

If the identity, the role, and the scope appear in the result, the permission was created, even if the previous command returned AccessDenied.

What happened

While reviewing the Azure CLI code, I found the reason for the error.

During execution, the command:

  1. looks up the role definition;
  2. creates the Role Assignment in the provided scope;
  3. queries again the role definitions to assemble the response to be displayed.

The problem occurs in the third step.

After creating the permission in the correct scope, the code calls list_role_definitions without specifying the scope. As a result, the query is performed at /.

Since the user had Managed HSM Policy Administrator only in /keys/my-key, they could create the permission at that key, but could not query the definitions in the entire HSM.

So, the creation succeeded and the subsequent query failed.

Beware of scripts and pipelines

This behavior can cause issues in scripts and pipelines, because the command will be interpreted as a failure and may be retried.

Before attempting again:

  • list the Role Assignments using --scope "/keys/<key-name>";
  • verify that the identity, the role, and the scope are correct;
  • run the command again only if the permission truly does not exist.

Each run can create a new Role Assignment for the same identity, role, and scope. Therefore, you should not rely solely on the error message shown by the Azure CLI.

It would also be possible to grant the user permission at the root scope, but that would give access beyond what is necessary and would defeat the separation I wanted to maintain between teams.

What I learned

In this case, the AccessDenied does not mean that the creation of the Role Assignment failed.

The permission is created at the key’s scope and the error occurs later, when the Azure CLI tries to perform a query at /.

So, if you encounter the same behavior, first check permissions directly at /keys/<key-name> before running the command again.

I opened an issue in the Azure CLI repository, and as I write this article, it is still open.

References

Azure CLIAzure Key VaultManaged HSMRBAC
Azure Managed HSM – AccessDenied when creating a Role Assignment — Vinicius Deschamps