Understanding and Protecting local authentication for Azure services — Part 2 (Cosmos DB)
I recently started a series on understanding and protecting access in Azure. In a previous post, I covered Azure storage. This post is about Cosmos DB.
Local Authentication on Cosmos DB
Master Keys — Every Cosmos DB account consists of four long lived access keys that are auto-generated at creation time. Two of the keys have read-write access while the other two keys have read-only access. The keys have a pre-defined level of access that cannot be modified. The read-write keys have unrestricted access to both management and data planes including to accounts, databases, users, and permissions — It has a broad scope of access and cannot be used to provide granular access to cosmos DB resources like containers and documents.
The following permissions can be used to gain access to the keys:
Microsoft.DocumentDB/databaseAccounts/listKeys/action
Microsoft.DocumentDB/databaseAccounts/readonlykeys/action
Microsoft.DocumentDB/databaseAccounts/listConnectionStrings/action
Resource tokens — These are time bound tokens that can be used to grant permissions to specific Cosmos DB data resources. Using it involves first creating a local user using the Cosmos DB API or a supported programming language SDK, defining a permission resource, and then assigning the permission resource to the user for a specific Cosmos DB data resource (database, container, user defined functions, stored procedure).
Unlike the master keys, resource tokens allows for granularity in resource scoping but the permission options are still limited to two modes:
- All: The user has full permission (write, update, or delete operations) on the specific resource. In other to use a token to run a stored procedures, this permission mode is needed on the container where the stored procedure will be run.
- Read: The user can only read the contents of the specific resource but cannot perform write, update, or delete operations on the resource.
By default, issued tokens expire after one hour per default but the requester can specify a token expiration time of up to 5 hours using the x-ms-documentdb-expiry-seconds request option. Also, resource tokens cannot be refreshed. When the token expires, a new one needs to be issued. This means a compromised token can be used for up to a maximum of 5 hours and is only suitable to establish a short-term backdoor in an attack scenario.
The main use case for a resource token is to limit the scope of access for clients that cannot be trusted with the master key. It also allows for cloud design patterns like the valet-key where a “permissions broker” is responsible for issuing temporary access tokens to authenticated clients for specific resources (based off of what they should be able to access for example, a given collection and a given partitionkey within that collection).
The process of creating resource tokens requires data plane operations that uses a read-write master key. The operations include creating a native cosmos DB user; creating a permissions resource for a user; linking a permissions resource to a Cosmos DB data resources; Reading the resource token. So anyone with the permission to read the read-write master keys can perform these operations.
Microsoft.DocumentDB/databaseAccounts/listKeys/action
Microsoft.DocumentDB/databaseAccounts/listConnectionStrings/action
Impact if compromised
- Unrestricted data plane access to data in the databases and containers.
- Stored procedures!
- Broadly scoped resource tokens generated for short-term backdoor access
Does it support identity-based authentication for client requests?
Partially yes. The CosmosDB service currently supports five APIs — Core (SQL), Table, MongoDB, Cassandra, Gremlin. Of all these APIs, only the Core (SQL) option allows identity based access using Azure AD with RBAC.
Can local auth be disabled?
Partially yes (for the SQL API only). To disable the master keys usage, you can set the following account-level property — disableLocalAuth: true
. This can be done using an ARM template or resources.azure.com (The option is not yet configurable through the portal).
For the other APIs that still requires master key usage, the ability to use the keys to modify resource metadata should at least be disabled by setting the following account-level property — “disableKeyBasedMetadataWriteAccess”: true. This can be done using an ARM template, Azure CLI or Azure PowerShell
- Azure CLI — ``` az cosmosdb update — name <CosmosDBAccountName> — resource-group <ResourceGroupName> — disable-key-based-metadata-write-access true
- Azure PowerShell — Update-AzCosmosDBAccount -ResourceGroupName <ResourceGroupName> -Name <CosmosDBAccountName> -DisableKeyBasedMetadataWriteAccess true
- Reference — https://docs.microsoft.com/en-us/azure/cosmos-db/role-based-access-control#prevent-sdk-changes
Does it support private endpoint?
Yes. At a minimum, this should be enabled for every Cosmos DB account that still uses key-based auth.
Can it be assigned an identity?
Yes — mainly for the service to access key vault to retrieve the encryption key in a customer managed encryption key scenario. I’ll highly recommend giving it explicit access (and not wide). Also, is this logged?
Can it execute user-provided code?
Yes. Server-side programming is supported with stored procedures, user-defined functions and triggers.
How to detect usage?
Master keys
The authTokenType
property in the resource logs (not enabled by default) will indicate if a master key was used to authenticate the request. It can have values like PrimaryMasterKey
OR PrimaryReadOnlyMasterKey
depending on the key type.
Resource tokens
If you enable the resource logs for data-plane requests, the following two properties corresponding to resource token usage are useful:
authTokenType
— This property indicates the resource token permission Id that you have specified.resourceTokenPermissionMode
— This property indicates the permission mode that is set for the used resource token. The permission mode can have values such asall
orread
.
Keep in mind that resource tokens are meant to be specific. If you notice resource token authenticated requests where properties.requestResourceType
is the Database
with properties.resourceTokenPermissionsMode
is all
, you may want to verify with the teams if this can be scoped more specifically.
For guidance on implementing a comprehensive protection strategy, please refer to the first blog post in this series (section on Implementing a protection strategy that scales)
I deliver beginner to beginner to advanced level Azure security training to organizations all over the world. Please reach out at david@chariscloud.com for more information.