使用 Microsoft Entra ID 为 Azure Cosmos DB 帐户配置基于角色的访问控制

适用范围: NoSQL

注意

本文介绍了有关 Azure Cosmos DB 中数据平面操作的基于角色的访问控制。 如果使用管理平面操作,请参阅适用于管理平面操作的基于角色的访问控制一文。

Azure Cosmos DB 公开了一种内置的基于角色的访问控制系统,它允许:

  • 使用 Microsoft Entra 标识对数据请求进行身份验证。
  • 使用细粒度的、基于角色的权限模型来授权数据请求。

概念

Azure Cosmos DB 数据平面基于角色的访问控制建立在其他基于角色的访问控制系统(例如 Azure 基于角色的访问控制)中常见的概念之上:

  • 权限模型由一组操作组成;其中每个操作都映射到一个或多个数据库操作。 操作的一些示例包括读取项、写入项或执行查询。
  • Azure Cosmos DB 用户创建包含允许操作列表的角色定义
  • 角色定义通过角色分配分配给特定的 Microsoft Entra 标识。 角色分配还定义了角色定义适用的作用域;目前有三个作用域:
    • 一个 Azure Cosmos DB 帐户,
    • 一个 Azure Cosmos DB 数据库,
    • 一个 Azure Cosmos DB 容器。

Diagram of common role-based access control concepts including role definitions, role assignments, and principals.

权限模型

重要

此权限模型仅涵盖涉及读取和写入数据的数据库操作。 它涵盖对管理资源的任何类型的管理操作,包括:

  • 创建/替换/删除数据库
  • 创建/替换/删除容器
  • 读取/替换容器吞吐量
  • 创建/替换/删除/读取存储过程
  • 创建/替换/删除/读取触发器
  • 创建/替换/删除/读取用户定义的函数

不能通过任何 Azure Cosmos DB 数据平面 SDK 使用 Microsoft Entra 标识对管理操作进行身份验证。 而是,必须通过以下其中一个选项使用 Azure 基于角色的访问控制

读取数据库和读取容器被视为元数据请求。 可以按以下部分所述授予对这些操作的访问权限。

此表列出了权限模型公开的所有操作。

名称 对应的数据库操作
Microsoft.DocumentDB/databaseAccounts/readMetadata 读取帐户元数据。 有关详细信息,请参阅元数据请求
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/create 创建新项。
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read 通过 ID 和分区键读取单个项(点读)。
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/replace 替换现有项。
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/upsert “更新插入”项。 如果尚不存在项,此操作会创建项,如果存在项,会进行替换。
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/delete 删除项。
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery 执行 SQL 查询
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed 从容器的更改源读取。 使用 SDK 执行 SQL 查询
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeStoredProcedure 执行存储过程
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/manageConflicts 管理多写入区域帐户的冲突(即,列出并删除冲突源中的项)。

注意

通过 SDK 执行查询时,需要 Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQueryMicrosoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed 权限。

容器和项级别均支持通配符:

  • Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*
  • Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*

元数据请求

Azure Cosmos DB SDK 会在初始化期间发出只读元数据请求,并为特定的数据请求提供服务。 这些请求会提取各种配置详细信息,例如:

  • 帐户的多区域配置,其中包括帐户可用的 Azure 区域。
  • 容器或其索引策略的分区键。
  • 构成容器及其地址的物理分区列表。

它们会提取你在帐户中存储的任何数据。

为了确保最大程度地提高权限模型的透明度,这些元数据请求由 Microsoft.DocumentDB/databaseAccounts/readMetadata 操作显式覆盖。 在任何通过某个 Azure Cosmos DB SDK 访问 Azure Cosmos DB 帐户的情况下,都应允许此操作。 它可以在 Azure Cosmos DB 层次结构的任何级别(即帐户、数据库或容器)中分配(通过角色分配)。

Microsoft.DocumentDB/databaseAccounts/readMetadata 操作允许的实际元数据请求取决于分配操作的范围:

范围 操作允许的请求
帐户 • 列出帐户下的数据库
• 对于帐户下的每个数据库,数据库作用域允许的操作
数据库 • 读取数据库元数据
• 列出数据库下的容器
• 对于数据库下的每个容器,容器作用域允许的操作
容器 • 读取容器元数据
• 列出容器下的物理分区
• 解析每个物理分区的地址

重要

此操作的元数据中不包含吞吐量。

内置角色定义

Azure Cosmos DB 公开两个内置角色定义:

重要

此处的术语“角色定义”是指特定于 Azure Cosmos DB 的角色定义。 这些定义不同于 Azure 基于角色的访问控制角色定义。

ID 名称 包含的操作
00000000-0000-0000-0000-000000000001 Cosmos DB 内置数据读取者 Microsoft.DocumentDB/databaseAccounts/readMetadata
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed
00000000-0000-0000-0000-000000000002 Cosmos DB 内置数据参与者 Microsoft.DocumentDB/databaseAccounts/readMetadata
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*

创建自定义角色定义

创建自定义角色定义时,需要提供:

  • Azure Cosmos DB 帐户的名称。
  • 包含帐户的资源组。
  • 角色定义的类型:CustomRole
  • 角色定义的名称。
  • 希望角色允许的操作列表。
  • 可在其中分配角色定义的一个或多个范围:支持的范围包括:
    • /(帐户级别)、
    • /dbs/<database-name>(数据库级别)、
    • /dbs/<database-name>/colls/<container-name>(容器级别)。

注意

所述操作可用于:

使用 Azure PowerShell

创建一个名为 MyReadOnlyRole 的角色,该角色只包含读取操作:

$resourceGroupName = "<myResourceGroup>"
$accountName = "<myCosmosAccount>"
New-AzCosmosDBSqlRoleDefinition -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -Type CustomRole -RoleName MyReadOnlyRole `
    -DataAction @( `
        'Microsoft.DocumentDB/databaseAccounts/readMetadata',
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read', `
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery', `
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed') `
    -AssignableScope "/"

创建一个名为 MyReadWriteRole 的角色,其中包含所有操作:

New-AzCosmosDBSqlRoleDefinition -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -Type CustomRole -RoleName MyReadWriteRole `
    -DataAction @( `
        'Microsoft.DocumentDB/databaseAccounts/readMetadata',
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*', `
        'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*') `
    -AssignableScope "/"

列出已创建的用于提取其 ID 的角色定义:

Get-AzCosmosDBSqlRoleDefinition -AccountName $accountName `
    -ResourceGroupName $resourceGroupName
RoleName         : MyReadWriteRole
Id               : /subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAcc
                   ounts/<myCosmosAccount>/sqlRoleDefinitions/<roleDefinitionId>
Type             : CustomRole
Permissions      : {Microsoft.Azure.Management.CosmosDB.Models.Permission}
AssignableScopes : {/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAc
                   counts/<myCosmosAccount>}

RoleName         : MyReadOnlyRole
Id               : /subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAcc
                   ounts/<myCosmosAccount>/sqlRoleDefinitions/<roleDefinitionId>
Type             : CustomRole
Permissions      : {Microsoft.Azure.Management.CosmosDB.Models.Permission}
AssignableScopes : {/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAc
                   counts/<myCosmosAccount>}

使用 Azure CLI

在名为 role-definition-ro.json 的文件中创建一个名为 MyReadOnlyRole 的角色,该角色仅包含读取操作:

{
    "RoleName": "MyReadOnlyRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed"
        ]
    }]
}
resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
az cosmosdb sql role definition create --account-name $accountName --resource-group $resourceGroupName --body @role-definition-ro.json

在名为 role-definition-rw.json 的文件中创建一个名为 MyReadWriteRole 的角色,该角色包含所有操作:

{
    "RoleName": "MyReadWriteRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
        ]
    }]
}
az cosmosdb sql role definition create --account-name $accountName --resource-group $resourceGroupName --body @role-definition-rw.json

列出已创建的用于提取其 ID 的角色定义:

az cosmosdb sql role definition list --account-name $accountName --resource-group $resourceGroupName
[
  {
    "assignableScopes": [
      "/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<myCosmosAccount>"
    ],
    "id": "/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<myCosmosAccount>/sqlRoleDefinitions/<roleDefinitionId>",
    "name": "<roleDefinitionId>",
    "permissions": [
      {
        "dataActions": [
          "Microsoft.DocumentDB/databaseAccounts/readMetadata",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
        ],
        "notDataActions": []
      }
    ],
    "resourceGroup": "<myResourceGroup>",
    "roleName": "MyReadWriteRole",
    "sqlRoleDefinitionGetResultsType": "CustomRole",
    "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions"
  },
  {
    "assignableScopes": [
      "/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<myCosmosAccount>"
    ],
    "id": "/subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<myCosmosAccount>/sqlRoleDefinitions/<roleDefinitionId>",
    "name": "<roleDefinitionId>",
    "permissions": [
      {
        "dataActions": [
          "Microsoft.DocumentDB/databaseAccounts/readMetadata",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed"
        ],
        "notDataActions": []
      }
    ],
    "resourceGroup": "<myResourceGroup>",
    "roleName": "MyReadOnlyRole",
    "sqlRoleDefinitionGetResultsType": "CustomRole",
    "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions"
  }
]

使用 Azure 资源管理器模板

有关使用 Azure 资源管理器模板创建角色定义的参考和示例,请参阅 Microsoft.DocumentDB databaseAccounts/sqlRoleDefinitions

创建角色分配

可以将内置或自定义角色定义与 Microsoft Entra 标识相关联。 创建角色分配时,需要提供:

  • Azure Cosmos DB 帐户的名称。

  • 包含帐户的资源组。

  • 要分配的角色定义的 ID。

  • 应为角色定义分配的标识的主体 ID。

  • 角色分配的范围;支持的范围包括:

    • /(帐户级别)
    • /dbs/<database-name>(数据库级别)
    • /dbs/<database-name>/colls/<container-name>(容器级别)

    范围必须与角色定义的可分配范围之一匹配或者是该可分配范围的子范围。

注意

若要为服务主体创建角色分配,请确保使用“Microsoft Entra ID”门户边栏选项卡的“企业应用程序”部分中的“对象 ID”

注意

所述操作可用于:

使用 Azure PowerShell

为标识分配角色:

$resourceGroupName = "<myResourceGroup>"
$accountName = "<myCosmosAccount>"
$readOnlyRoleDefinitionId = "<roleDefinitionId>" # as fetched above
# For Service Principals make sure to use the Object ID as found in the Enterprise applications section of the Azure Active Directory portal blade.
$principalId = "<aadPrincipalId>"
New-AzCosmosDBSqlRoleAssignment -AccountName $accountName `
    -ResourceGroupName $resourceGroupName `
    -RoleDefinitionId $readOnlyRoleDefinitionId `
    -Scope "/" `
    -PrincipalId $principalId

使用 Azure CLI

为标识分配角色:

resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
readOnlyRoleDefinitionId='<roleDefinitionId>' # as fetched above
# For Service Principals make sure to use the Object ID as found in the Enterprise applications section of the Azure Active Directory portal blade.
principalId='<aadPrincipalId>'
az cosmosdb sql role assignment create --account-name $accountName --resource-group $resourceGroupName --scope "/" --principal-id $principalId --role-definition-id $readOnlyRoleDefinitionId

使用 Azure 资源管理器模板

有关使用 Azure 资源管理器模板创建角色分配的参考和示例,请参阅 Microsoft.DocumentDB databaseAccounts/sqlRoleAssignments

使用 Microsoft Entra ID 初始化 SDK

要在应用程序中使用 Azure Cosmos DB 基于角色的访问控制,必须更新初始化 Azure Cosmos DB SDK 的方式。 必须传递 TokenCredential 类的实例,而不是传递帐户的主键。 此实例为 Azure Cosmos DB SDK 提供了在代表要使用的标识获取 Microsoft Entra 令牌时所需的上下文。

创建 TokenCredential 实例的方式不在本文讨论范围。 有多种方法可以创建此类实例,具体取决于要使用的 Microsoft Entra 标识类型(用户主体、服务主体、组等)。 最重要的是,TokenCredential 实例必须解析为已向其分配角色的标识(主体 ID)。 你可以找到创建 TokenCredential 类的示例:

以下示例将服务主体与 ClientSecretCredential 实例结合使用。

在 .NET 中

.NET SDK V3 目前支持 Azure Cosmos DB 基于角色的访问控制。

TokenCredential servicePrincipal = new ClientSecretCredential(
    "<azure-ad-tenant-id>",
    "<client-application-id>",
    "<client-application-secret>");
CosmosClient client = new CosmosClient("<account-endpoint>", servicePrincipal);

在 Java 中

Java SDK V4 目前支持 Azure Cosmos DB 基于角色的访问控制。

TokenCredential ServicePrincipal = new ClientSecretCredentialBuilder()
    .authorityHost("https://login.chinacloudapi.cn")
    .tenantId("<azure-ad-tenant-id>")
    .clientId("<client-application-id>")
    .clientSecret("<client-application-secret>")
    .build();
CosmosAsyncClient Client = new CosmosClientBuilder()
    .endpoint("<account-endpoint>")
    .credential(ServicePrincipal)
    .build();

在 JavaScript 中

JavaScript SDK V3 目前支持 Azure Cosmos DB 基于角色的访问控制。

const servicePrincipal = new ClientSecretCredential(
    "<azure-ad-tenant-id>",
    "<client-application-id>",
    "<client-application-secret>");
const client = new CosmosClient({
    endpoint: "<account-endpoint>",
    aadCredentials: servicePrincipal
});

在 Python 中

Python SDK 版本 4.3.0b4 及更高版本支持 Azure Cosmos DB 基于角色的访问控制。

aad_credentials = ClientSecretCredential(
    tenant_id="<azure-ad-tenant-id>",
    client_id="<client-application-id>",
    client_secret="<client-application-secret>")
client = CosmosClient("<account-endpoint>", aad_credentials)

对 REST API 上的请求进行身份验证

构造 REST API 授权标头时,将 type 参数设置为 Microsoft Entra ID,并将哈希签名 (sig) 设置为 oauth 令牌,如以下示例所示:

type=aad&ver=1.0&sig=<token-from-oauth>

审核数据请求

使用 Azure Cosmos DB 基于角色的访问控制时,诊断日志 使用每个数据操作的标识和授权信息进行扩充。 此扩充使你能够执行详细审核,并检索用于发送到 Azure Cosmos DB 帐户的每个数据请求的 Microsoft Entra 标识。

此附加信息存在于 DataPlaneRequests 日志类别中,并包含两个额外的列:

  • aadPrincipalId_g 显示用于对请求进行身份验证的 Microsoft Entra 标识的主体 ID。
  • aadAppliedRoleAssignmentId_g 显示在授权请求时接受的角色分配

强制执行基于角色的访问控制作为唯一的身份验证方法

在要强制客户端以独占方式通过基于角色的访问控制连接到 Azure Cosmos DB 的情况下,可以禁用该帐户的主/辅助密钥。 执行此操作时,系统会主动拒绝任何使用主/辅助密钥或资源令牌的传入请求。

使用 Azure 资源管理器模板

在使用 Azure 资源管理器模板创建或更新 Azure Cosmos DB 帐户时,请将 disableLocalAuth 属性设置为 true

"resources": [
    {
        "type": " Microsoft.DocumentDB/databaseAccounts",
        "properties": {
            "disableLocalAuth": true,
            // ...
        },
        // ...
    },
    // ...
 ]

限制

  • 对于每个 Azure Cosmos DB 帐户,最多可以创建 100 个角色定义和 2,000 个角色分配。
  • 只能将角色定义分配给属于与 Azure Cosmos DB 帐户相同的 Microsoft Entra 租户的 Microsoft Entra 标识。
  • 属于超过 200 个组的标识目前不支持 Microsoft Entra 组解析。
  • Microsoft Entra 令牌当前以标头的形式传递,其中每个单独的请求发送到 Azure Cosmos DB 服务,从而增加总体有效负载大小。

常见问题

本部分包括有关基于角色的访问控制和 Azure Cosmos DB 的常见问题。

哪些 Azure Cosmos DB API 支持基于角色的访问控制?

支持 API for NoSQL。 对 API for MongoDB 的支持目前为预览版。

是否可以从 Azure 门户管理角色定义和角色分配?

尚未提供对角色管理的 Azure 门户支持。

Azure Cosmos DB API for NoSQL 中的哪些 SDK 支持基于角色的访问控制?

目前支持 .NET V3Java V4JavaScript V3Python V4.3+ SDK。

Azure Cosmos DB SDK 在过期时是否自动刷新 Microsoft Entra 令牌?

是的。

使用基于角色的访问控制时,可以禁用帐户主/辅助密钥吗?

可以,请参阅 强制执行基于角色的访问控制作为唯一的身份验证方法

后续步骤