The importance of understanding the assignments of Azure resource roles when giving permissions.
One great thing about access management in Azure is the clear distinction between control plane actions (“actions”) and data plane actions (“dataActions”) in Roles. One proviso, however: you may wind up granting more permissions to an entity than intended -- and likely because the caveats offered are less conspicuous than they should be.
The distinction between “actions” and “dataActions” is very important - and useful - in configuring and selecting roles for different business functions and jobs. “Actions” are management operations (a.k.a. control plane operations), performed on the resources themselves. “Data actions” are operations such as read, write and delete, performed on data within a resource. These fundamentally distinct types of operations commonly align with functions within an organization, namely: entities that manage resources (such as system admins) and entities that consume and/or manipulate them.
The utility of this distinction relies heavily on “actions” giving permissions to only management operations, and “dataActions” giving permissions to only data-related operations. As it turns out, this is not always the case. As we will see in this article: At times you may think you are granting management actions but are actually granting access to data - and even the ability to modify it!
Such is the unintended backdoor-by-design reality of the action: Microsoft.Storage/storageAccounts/listkeys/action.
Listing Access Keys - a Control Plane Action that Allows Manipulation of Data
According to Azure documentation: “When you create a storage account, Azure generates two 512-bit storage account access keys. These keys can be used to authorize access to data and even the modification (including deletion!) in your storage account via Shared Key authorization.”
Due to the highly sensitive nature of these access keys, when using them, store them with care. Even if you will not be using them and never extracting them from the console, know this:
While accessing the data in a storage account is very clearly a data action, the action that lets a function get to the access keys, Microsoft.Storage/storageAccounts/listkeys/action, is a control plane action, as seen in Figure 1.
This fact is important to understand because you may often want to enable users to manage a storage account without being able to access its data. To do so, you may be tempted to provide them with the Contributor role, which has no data actions listed in it.
Yet, the Contributor role does have access to the action: Microsoft.Storage/storageAccounts/listkeys/action. Therefore, a user or service principal assigned this Role can in fact access the data within the storage account - unless otherwise restricted from doing so.
Microsoft published a post on this issue. Nonetheless, in our experience with DevOps and security practitioners, we feel the issue may not be very well known. And that’s not all.
Not "Hard to Get" at All -- It’s the Default
To make matters worse: Not only does the Storage Accounts List Keys action enable unintended access; in the Azure portal, for users that can list the access keys, access keys are the default, out-of-the-box authentication method for accessing the storage account. In other words, when using the Azure portal, a user that can list the access keys can, with no special effort, access the data in the storage account.
As per the Microsoft post above: “When you attempt to access blob data in the Azure portal, the portal first checks whether you have been assigned a role with Microsoft.Storage/storageAccounts/listkeys/action. If you have been assigned a role with this action, then the portal uses the account key for accessing blob data. If you have not been assigned a role with this action, then the portal attempts to access data using your Azure AD account.”
In short, even if unaware of having been granted this excessive permission, a user is highly likely to stumble upon it.
Let’s see this in action. Let’s say a user has the Contributor role on a storage account:
When in the Azure portal, the user can actually - again, since the console uses the access key by default to authenticate the user’s access to a storage account - perform the data plane action of viewing the contents of the storage account and its containers.
If the user switches to the Azure AD User Account authentication method, Azure denies access to the storage account’s contents since the user does not have access to data actions.
It should be noted that even if the Azure portal did not use the access keys for authentication, a user that can list the access keys can still simply leverage an interface like Azure’s CLI to get the access keys and use them to access the data itself. It’s needless to say that unintended access to the contents of storage accounts may be a compliance issue - not to mention the potential cause of much more damaging fallout to an organization upon a security breach.
Issues like this highlight how important it is, when giving permissions to resources, to get familiar with the contents and implications of the Azure resource roles assigned to users and service principals. You want insight and control to be able to choose the most appropriate built-in role. Optimally, you will want to create custom roles with least privilege access permissions curated to the business functions that an entity assigned a role is required to perform.