Use role-based access control with Azure Cosmos DB for Table

APPLIES TO: Table

Diagram of the current location ('Role-based access control') in the sequence of the deployment guide.

Diagram of the sequence of the deployment guide including these locations, in order: Overview, Concepts, Prepare, Role-based access control, and Reference. The 'Role-based access control' location is currently highlighted.

This article walks through the steps to grant an identity access to manage data in an Azure Cosmos DB for Table account. The steps in this article only cover data plane access to perform operations on individual items and run queries.

Prerequisites

  • An Azure account with an active subscription. Create an account.
  • An existing Azure Cosmos DB for Table account.
  • One or more existing identities in Microsoft Entra ID.

You can use the local Azure CLI.

Prepare role definition

First, you must prepare a role definition with a list of dataActions to grant access to read, query, and manage data in Azure Cosmos DB for Table.

First, get the resource identifier of the existing Azure Cosmos DB for Table account using az cosmsodb show and store it in a variable. Then, list all of the role definitions associated with your Azure Cosmos DB for Table account using az rest. Finally, review the output and locate the role definition named Cosmos DB Built-in Data Contributor. The output contains the unique identifier of the role definition in the id property. Record this value as it is required to use in the assignment step later in this guide.

resourceId=$( \
    az cosmosdb show \
        --resource-group "<name-of-existing-resource-group>" \
        --name "<name-of-existing-table-account>" \
        --query "id" \
        --output tsv \
)

az rest \
    --method "GET" \
    --url $resourceId/tableRoleDefinitions?api-version=2023-04-15
[
  ...,
  {
    "id": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql/tableRoleDefinitions/00000000-0000-0000-0000-000000000002",
    "name": "00000000-0000-0000-0000-000000000002",
    "properties": {
      "assignableScopes": [
        "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql"
      ],
      "permissions": [
        {
          "dataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/tables/*",
            "Microsoft.DocumentDB/databaseAccounts/tables/containers/entities/*"
          ],
          "notDataActions": []
        }
      ],
      "roleName": "Cosmos DB Built-in Data Contributor",
      "type": "BuiltInRole"
    },
    "type": "Microsoft.DocumentDB/databaseAccounts/tableRoleDefinitions"
  }
  ...
]

Note

In this example, the id value would be /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql/tableRoleDefinitions/00000000-0000-0000-0000-000000000002. This example uses fictitious data and your identifier would be distinct from this example. This example output is truncated.

Use Get-AzCosmosDBAccount to get the resource identifier of the existing Azure Cosmos DB for Table account and store it in a variable. Then, use Invoke-AzRestMethod to list all of the role definitions associated with your Azure Cosmos DB for Table account. Review the output and locate the role definition named Cosmos DB Built-in Data Contributor. The output contains the unique identifier of the role definition in the Id property. Record this value as it is required to use in the assignment step later in this guide.

$parameters = @{
    ResourceGroupName = "<name-of-existing-resource-group>"
    Name = "<name-of-existing-table-account>"
}
$resourceId = (
    Get-AzCosmosDBAccount @parameters |
        Select-Object -Property Id -First 1
).Id

$parameters = @{
  Path = "$resourceId/tableRoleDefinitions?api-version=2023-04-15"
  Method = "GET"
}
Invoke-AzRestMethod @parameters
StatusCode : 200
Content    : {
               "value": [
                ...,
                {
                  "id": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql/tableRoleDefinitions/00000000-0000-0000-0000-000000000002",
                  "name": "00000000-0000-0000-0000-000000000002",
                  "properties": {
                    "assignableScopes": [
                      "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql"
                    ],
                    "permissions": [
                      {
                        "dataActions": [
                          "Microsoft.DocumentDB/databaseAccounts/readMetadata",
                          "Microsoft.DocumentDB/databaseAccounts/tables/*",
                          "Microsoft.DocumentDB/databaseAccounts/tables/containers/entities/*"
                        ],
                        "notDataActions": []
                      }
                    ],
                    "roleName": "Cosmos DB Built-in Data Contributor",
                    "type": "BuiltInRole"
                  },
                  "type": "Microsoft.DocumentDB/databaseAccounts/tableRoleDefinitions"
                }
                ...
               ]
             }
...

Note

In this example, the Id value would be /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql/tableRoleDefinitions/00000000-0000-0000-0000-000000000002. This example uses fictitious data and your identifier would be distinct from this example. This example output is truncated.

Assign role to identity

Now, assign the newly defined role to an identity so that your applications can access data in Azure Cosmos DB for Table.

Important

This assignment task requires you to have the unique identifier of any identity you want to grant role-based access control permissions. If you do not have a unique identifier for an identity, follow the instructions in the create managed identity or get signed-in identity guides.

  1. Use az cosmosdb show to get the unique identifier for your current account.

    az cosmosdb show \
        --resource-group "<name-of-existing-resource-group>" \
        --name "<name-of-existing-resource-group>" \
        --query "{id:id}"
    
  2. Observe the output of the previous command. Record the value of the id property for this account as it is required to use in the next step.

    {
      "id": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql"
    }
    

    Note

    In this example, the id value would be /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql. This example uses fictitious data and your identifier would be distinct from this example.

  3. Create a new JSON file named role-assignment.json. In the JSON file, add the unique identifier for your identity and unique identifier for the account resource.

    {
      "properties": {
        "roleDefinitionId": "<account-resource-id>/tableRoleDefinitions/d3d3d3d3-eeee-ffff-aaaa-b4b4b4b4b4b4",
        "scope": "<account-resource-id>",
        "principalId": "<id-of-existing-identity>"
      }
    }
    

    Note

    In this example, the unique GUID specified was d3d3d3d3-eeee-ffff-aaaa-b4b4b4b4b4b4. You can use the unique GUID you used previously for your own role definition.

  4. Now create or update a role assignment using az cosmosdb show and az rest together to issue an HTTP PUT request. As part of this request, specify a unique GUID for your role assignment.

    resourceId=$( \
        az cosmosdb show \
            --resource-group "<name-of-existing-resource-group>" \
            --name "<name-of-existing-table-account>" \
            --query "id" \
            --output tsv \
    )
    
    az rest \
        --method "PUT" \
        --url $resourceId/tableRoleAssignments/e4e4e4e4-ffff-aaaa-bbbb-c5c5c5c5c5c5?api-version=2023-04-15 \
        --body @role-assignment.json
    

    Note

    In this example, the unique GUID specified was e4e4e4e4-ffff-aaaa-bbbb-c5c5c5c5c5c5. You can specify any unique GUID for your own role assignment.

  1. Create another Bicep file to assign a role to an identity. Name this file data-plane-role-assignment.bicep.

    metadata description = 'Assign RBAC role for data plane access to Azure Cosmos DB for Table.'
    
    @description('Name of the Azure Cosmos DB for Table account.')
    param accountName string
    
    @description('Id of the role definition to assign to the targeted principal in the context of the account.')
    param roleDefinitionId string
    
    @description('Id of the identity/principal to assign this role in the context of the account.')
    param identityId string
    
    resource account 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = {
      name: accountName
    }
    
    resource assignment 'Microsoft.DocumentDB/databaseAccounts/tableRoleAssignments@2023-04-15' = {
      name: guid(roleDefinitionId, identityId, account.id)
      parent: account
      properties: {
        principalId: identityId
        roleDefinitionId: roleDefinitionId
        scope: account.id
      }
    }
    
    output id string = assignment.id
    
  2. Create a new Bicep parameters file named data-plane-role-assignment.bicepparam. In this parameters file; assign the name of your existing Azure Cosmos DB for Table account to the accountName parameter, the previously recorded role definition identifiers to the roleDefinitionId parameter, and the unique identifier for your identity to the identityId parameter.

    using './data-plane-role-assignment.bicep'
    
    param accountName = '<name-of-existing-table-account>'
    param roleDefinitionId = '<id-of-new-role-definition>'
    param identityId = '<id-of-existing-identity>'
    
  3. Deploy this Bicep template using az deployment group create.

    az deployment group create \
        --resource-group "<name-of-existing-resource-group>" \
        --parameters data-plane-role-assignment.bicepparam \
        --template-file data-plane-role-assignment.bicep
    
  4. Repeat these steps to grant access to the account from any other identities you would like to use.

    Tip

    You can repeat these steps for as many identities as you'd like. Typically, these steps are at least repeated to allow developers access to an account using their human identity and to allow applications access using a managed identity.

  1. Use `Get-AzCosmosDBAccount to get the unique identifier for your current account.

    $parameters = @{
        ResourceGroupName = "<name-of-existing-resource-group>"
        Name = "<name-of-existing-nosql-account>"
    }
    Get-AzCosmosDBAccount @parameters | Select -Property Id
    
  2. Observe the output of the previous command. Record the value of the Id property for this account as it is required to use in the next step.

    Id
    --    
    /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql
    

    Note

    In this example, the Id value would be /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-identity-example/providers/Microsoft.DocumentDB/databaseAccounts/msdocs-identity-example-nosql. This example uses fictitious data and your identifier would be distinct from this example.

  3. Now create or update a role assignment using Get-AzCosmosDBAccount and Invoke-AzRestMethod together to issue an HTTP PUT request. As part of this request, specify a unique GUID for your role assignment. Finally, create a resource assignment payload specifying the unique identifier for your identity.

    $parameters = @{
        ResourceGroupName = "<name-of-existing-resource-group>"
        Name = "<name-of-existing-table-account>"
    }
    $resourceId = (
        Get-AzCosmosDBAccount @parameters |
            Select-Object -Property Id -First 1
    ).Id    
    
    $payload = @{
      properties = @{
        roleDefinitionId = "$resourceId/tableRoleDefinitions/00000000-0000-0000-0000-000000000002"
        scope = "$resourceId"
        principalId = "<id-of-existing-identity>"
      }
    }
    
    $parameters = @{
      Path = "$resourceId/tableRoleAssignments/e4e4e4e4-ffff-aaaa-bbbb-c5c5c5c5c5c5?api-version=2023-04-15"
      Method = "PUT"
      Payload = $payload | ConvertTo-Json -Depth 2
    }
    Invoke-AzRestMethod @parameters
    

    Note

    In this example, the unique GUID specified was e4e4e4e4-ffff-aaaa-bbbb-c5c5c5c5c5c5. You can specify any unique GUID for your own role assignment.

Validate data plane access in code

Finally, validate that you correctly granted access using application code and the Azure SDK in your preferred programming language.

using Azure.Identity;
using Azure.Data.Tables;
using Azure.Core;

string endpoint = "<account-endpoint>";

TokenCredential credential = new DefaultAzureCredential();

TableServiceClient client = new(new Uri(endpoint), credential);

Important

This code sample uses the Azure.Data.Tables and Azure.Identity libraries from NuGet.

Warning

If you are using a user-assigned managed identity, you will need to specify the unique identifier of the managed identity as part of creating the credentials object.