Penetration testing Azure key vaults permission model

TLDR;

It is often assumed that the Contributor role cannot read secrets from key vaults. This is inaccurate and is often abused when doing Azure penetration testing. We’ll understand why and how we can possibly address this.

  • Contributor roles gets often assigned to service principals and users in dev and testing teams
  • By default, Contributors can grant self-permission to read secrets. This is undesirable
  • We follow Microsoft’s recommendation and secure against this behavior using RBAC controlled secrets

Screenshots from the owner account are in Dark Mode

Screenshots from our penetration tester are in Light Mode

Contributor’s Keys to the Kingdom

Following up on the previous article Azure AD Roles Vs. Azure Resources Roles let us expand a bit on some useful RBAC configurations. Here’s a scenario that is all too common when going through an Azure penetration testing exercise.

A subscription is created for the development team. In the subscription is a key vault with keys, secrets and/or certificates that are usually used by apps. The key vault isn’t and shouldn’t normally be accessed by the dev team directly.

As the same time, most of the devs are assigned a Contributor role to make it easy for them to manage their resources. This has an inherent risk associated.

At a certain stage of the Azure penetration testing, the consultant gets their hands on a dev account. This allows them to manipulate the key vault to access the secrets. This is undesirable as these vaults could contain sensitive secrets like a break glass admin passwords for example.

Unfortunately, this is known and expected as mentioned by Microsoft here.

Figure 1 Important message from Microsoft

Revealing Secrets

How does the above message translate in an Azure penetration testing engagement? Here is a typical scenario. We have our user, a Contributor, scoped to the subscription.

Figure 2 Contributor scoped to subscription

If our penetration tester tries to access a secret, by default, they are denied access.

Figure 3 Contributor denied access to secrets, for now

However, if the account is compromised, the penetration tester (or malicious account owner) can work around this by creating an access policy with self-granting permissions.

Figure 4 Contributor adds self-permission using access policies

Once grated, they can access the secret and reveal its value.

Figure 5 Contributor revealing secrets

Why Custom Roles Fail

We can try preventing this by using custom roles. For example, here we created a custom role which is a clone of the Contributor role but with two caveats.

First, the role is scoped to the key vault.

Second, we deny changes to the access policy by excluding the following permission: Microsoft.KeyVault/vaults/accessPolicies/write

Figure 6 Custom contributor role without access policies write permission

In figure 7 is the built in, non modified, Contributor role, which has permission to change access policies. Below it, in figure 8, is the custom contributor role.

Figure 7 Built in contributor with permissions to write access policies
Figure 8 Custom contributor with no permissions to write access policies

However, when we apply this permission to our user, it doesn’t seem to make an effect. Here is why…

Access Policies Vs. RBAC

You might have noticed in the previous screenshots the “Permissions model” when we visit the access policies. The previous key vault was protected with a “Vault access policy”. This is the reason our RBAC didn’t apply. And that allowed the contributor user (or our penetration tester) to create a policy allowing themselves to reveal the secret.

Figure 9 Permission model

Alternatively, we could have used Azure RBAC. Unlike access policies that apply to key vaults only, RBAC can also apply to individual keys, secret, and certificate.

Microsoft Recommends

Microsoft recommends using RBAC over Access Policies here.

Following Microsoft’s recommendations, we create another vault, however this time, we will select the permission model to be RBAC instead of access policy.

Figure 10 Using Azure RBAC

As we already learned, the owner is now able to control access to each secret individually using RBAC.

In figure 10, we can see a secret protected by access policy and it doesn’t have any IAM control options. In figure 11, a secret protected with IAM.

Figure 11 Secret protected with access policy
Figure 12 Secret protected with RBAC

Revealing Secrets?

Now what happens a contributor role tries to access the secret?

They are denied; with a message stating that RBAC roles don’t allow this action.

Figure 13 Contributor denied access to Secrets

If the Azure penetration tester tries to work around this by changing the “Access policy model” they will also be denied.

Figure 14 Contributor denied using access policies

With that we would have successfully achieved our objective of denying Contributor users from directly revealing secrets.

Summary

Contributor roles is often assigned to users. However, it indirectly allows for revealing secrets which can be abused during an Azure penetration testing exercise. We tested the following scenarios:

  • Protect Key vault with access policies.
    • Protection failed. Both Contributor and Custom-Contributor can change “Permission model” on access policies and read secrets
  • Protect secrets with RBAC
    • Protection succeeded. Neither Contributor nor Customer-Contributor can change “Permission model” on access policies and read secrets

References

https://docs.microsoft.com/en-us/azure/key-vault/general/rbac-migration

https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles-portal

https://docs.microsoft.com/en-us/azure/key-vault/general/security-features