你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用基于角色的访问控制和Microsoft Entra ID 连接到 Azure DocumentDB

Azure DocumentDB 支持Microsoft Entra ID 以及本机 DocumentDB 身份验证。 每个群集都启用了本机身份验证,并创建了一个内置管理用户。

基于角色的访问控制提供了一种集中机制,用于通过 Microsoft Entra ID 分配和强制实施权限,确保只有授权标识才能在群集上执行作。 此方法简化了治理,支持最低特权原则,并使审核变得简单-帮助组织在部署增长时保持运营完整性和合规性。 在 Azure DocumentDB 中管理访问权限涉及两个不同的级别:

  • 用于管理群集作为 Azure 资源时的 Azure 角色基于的访问(例如读取元数据、管理防火墙规则和配置专用终结点)
  • DocumentDB 访问,用于在群集上的数据库和集合中读取和写入数据。

启用 Microsoft Entra ID 以允许Microsoft Entra 主体(用户、服务主体或托管标识)向群集进行身份验证。 Microsoft Entra ID 身份验证是使用 OpenID Connect (OIDC) 实现的。 客户端向 MongoDB 驱动程序提供 Entra 颁发的 OIDC 访问令牌。 群集必须启用本机身份验证;支持的配置为仅本机身份验证或本机身份验证与 Microsoft Entra ID 身份验证结合使用。 Microsoft Entra ID 不能是唯一的身份验证方法。

注释

预配后,可以随时在群集上启用或更改身份验证方法。 更改身份验证方法 不需要 重启群集,并且不中断。 创建群集时,必须启用本机 DocumentDB 身份验证。 可以在群集完成预配后禁用本机身份验证。

使用 Microsoft Entra ID 进行身份验证的好处包括:

  • 跨 Azure 服务的统一标识和登录。
  • 集中管理凭据、密码策略和轮换。
  • 支持Microsoft Entra ID 中的无密码和多重身份验证方法。
  • 应用程序的基于令牌的身份验证,消除了存储的密码。

启用Microsoft Entra ID 身份验证后,可以将一个或多个 Microsoft Entra 主体注册为群集上的管理用户或非管理用户。 已注册主体对象将成为 Microsoft.DocumentDB/mongoClusters/users 下的 Azure 资源,并会被复制到数据库中;将这些主体映射到 MongoDB 数据库角色会授予相应的数据库权限。 这种形式的身份验证支持多种主体类型,包括:人类用户、服务主体(应用)、用户分配的托管标识和系统分配的托管标识。

注释

可以同时将多个Microsoft Entra ID 标识和标识类型配置为群集的管理员。 Microsoft Entra ID 标识类型包括但不限于:

  • 人的身份
  • 用户分配的托管标识
  • 系统分配的托管标识
  • 工作负载标识

所有标识类型都可以同时成为管理员。

管理用户拥有管理群集及其数据的完整权限。 可以为不需要管理权限的持续生产任务添加非管理用户。 非管理员用户通常拥有受限角色,例如对特定数据库的只读或读写访问,但无法执行群集范围的管理作。

使用此功能之前,请查看以下注意事项:

  • 主群集和副本群集上的身份验证方法 是独立管理的
  • Microsoft Entra 主体在群集元数据中永久存在。 如果主体从 Microsoft Entra ID 中删除,则相应的群集用户将保留,但无法再获取新令牌。 现有令牌在过期之前保持有效(通常从 令牌颁发起最多 90 分钟)。
  • 若要立即撤销访问权限,请从群集中删除主体(删除 users/<principal-id> 资源),并删除任何关联的数据库角色;数据库管理员必须处理已删除主体的所有权转移或清理。

先决条件

  • 现有的 Azure DocumentDB 群集

  • Microsoft Entra ID 中的一个或多个现有标识。

管理 Azure 基于角色的访问控制

Azure 基于角色的访问控制是指无需管理数据即可管理 Azure 服务的资源。 例如,Azure DocumentDB 群集的基于角色的访问可能包括:

  • 读取所有帐户和资源元数据
  • 读取和重新生成连接字符串
  • 管理数据库和集合
  • 修改帐户属性

Azure DocumentDB 支持对 mongoCluster 资源类型的 Azure 基于角色的访问控制。 在 Azure 基于角色的访问控制中,mongoCluster 资源类型的以下操作可用于单个分配和基于自定义角色的访问控制角色创建

Description
Microsoft.DocumentDB/mongoClusters/read 读取mongoCluster资源或列出所有mongoCluster资源。
Microsoft.DocumentDB/mongoClusters/write 创建或更新指定 mongoCluster 资源的属性或标记。
Microsoft.DocumentDB/mongoClusters/delete 删除指定的 mongoCluster 资源。
Microsoft.DocumentDB/mongoClusters/PrivateEndpointConnectionsApproval/action 管理 mongoCluster 资源的专用终结点连接
Microsoft.DocumentDB/mongoClusters/listConnectionStrings/action 列出给定 mongoCluster 资源的连接字符串
Microsoft.DocumentDB/mongoClusters/firewallRules/read 读取防火墙规则或列出指定 mongoCluster 资源的所有防火墙规则。
Microsoft.DocumentDB/mongoClusters/firewallRules/write 在指定 mongoCluster 资源上创建或更新防火墙规则。
Microsoft.DocumentDB/mongoClusters/firewallRules/delete 删除指定 mongoCluster 资源的现有防火墙规则。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnectionProxies/read 读取指定 mongoCluster 资源的专用终端连接代理。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnectionProxies/write 在指定的 mongoCluster 资源上创建或更新专用终结点连接代理。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnectionProxies/delete 删除指定 mongoCluster 资源的现有专用终结点连接代理。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnectionProxies/validate/action 验证指定 mongoCluster 资源的专用终结点连接代理。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnections/read 读取专用终结点连接或列出指定 mongoCluster 资源的所有专用终结点连接。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnections/write 在指定 mongoCluster 资源上创建或更新专用终结点连接。
Microsoft.DocumentDB/mongoClusters/privateEndpointConnections/delete 删除指定 mongoCluster 资源的现有专用终结点连接。
Microsoft.DocumentDB/mongoClusters/privateLinkResources/read 读取指定 mongoCluster 资源的某个专用链接资源,或列出其所有专用链接资源。
Microsoft.DocumentDB/mongoClusters/users/read 读取指定 mongoCluster 资源的某个用户,或列出其所有用户。
Microsoft.DocumentDB/mongoClusters/users/write 在指定 mongoCluster 资源上创建或更新用户。
Microsoft.DocumentDB/mongoClusters/users/delete 删除指定 mongoCluster 资源的现有用户。
  1. 打开新的终端。

  2. 登录到 Azure CLI。

  3. 使用 az group show 来获取当前资源组的元数据。

    az group show \
        --name "<name-of-existing-resource-group>"
    
  4. 观察上一命令的输出。 记录此资源组的属性 id 值,因为下一步需要使用此属性。

    {
      "id": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example",
      "location": "westus",
      "name": "msdocs-identity-example",
      "type": "Microsoft.Resources/resourceGroups"
    }
    

    注释

    在此示例中,该值 id/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example. 此示例使用虚构数据,标识符与此示例不同。 此字符串是输出的截断示例。

  5. 创建名为 role-definition.json的新 JSON 文件。 在文件中,创建此资源定义,指定此处列出的值。 在AssignableScopes列表中,添加上一步中记录的资源组的id属性。

    {
      "Name": "Azure DocumentDB RBAC Owner",
      "IsCustom": true,
      "Description": "Can perform all Azure role-based access control actions for Azure DocumentDB clusters.",
      "Actions": [
        "Microsoft.DocumentDb/mongoClusters/*"
      ],
      "AssignableScopes": [
        "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example"
      ]
    }
    

    注释

    此示例使用 /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example 上一步中记录的值。 实际资源标识符可能有所不同。

  6. 使用 az role definition create. 创建一个新的角色定义。 使用 role-definition.json 文件作为 --role-definition 参数的输入。

    az role definition create \
        --role-definition role-definition.json
    
  7. 查看定义创建命令的输出。 输出包含属性中 id 角色定义的唯一标识符。 记下此值,因为本指南后面的工作分配步骤需要使用此值。

    {
      "assignableScopes": [
        "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example"
      ],
      "description": "Can perform all Azure role-based access control actions for Azure DocumentDB clusters.",
      "id": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example/providers/Microsoft.Authorization/roleDefinitions/a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1",
      "name": "e4e4e4e4-ffff-aaaa-bbbb-c5c5c5c5c5c5",
      "permissions": [
        {
          "actions": [
            "Microsoft.DocumentDb/*"
          ]
        }
      ],
      "roleName": "Azure DocumentDB RBAC Owner",
      "roleType": "CustomRole"
    }
    

    注释

    在此示例中,该值 id/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example/providers/Microsoft.Authorization/roleDefinitions/a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1. 此示例使用虚构数据,标识符与此示例不同。 此示例是部署中输出的典型 JSON 的子集,为清楚起见。

  1. 打开新的终端。

  2. 登录到 Azure CLI。

  3. 创建新的 Bicep 文件以定义角色定义。 将文件 control-plane-role-definition.bicep 命名。 将以下项 actions 添加到定义:

    Description
    Microsoft.DocumentDb/mongoClusters/* 启用所有可能的操作。
    metadata description = 'Create RBAC definition for Azure role-based access control access to Azure DocumentDB.'
    
    @description('Name of the role definition.')
    param roleDefinitionName string = 'Azure DocumentDB RBAC Owner'
    
    @description('Description of the role definition.')
    param roleDefinitionDescription string = 'Can perform all Azure role-based access control actions for Azure DocumentDB clusters.'
    
    resource definition 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
      name: guid(subscription().id, resourceGroup().id, roleDefinitionName)
      scope: resourceGroup()
      properties: {
        roleName: roleDefinitionName
        description: roleDefinitionDescription
        type: 'CustomRole'
        permissions: [
          {
            actions: [
              'Microsoft.DocumentDb/mongoClusters/*'
            ]
          }
        ]
        assignableScopes: [
          resourceGroup().id
        ]
      }
    }
    
    output definitionId string = definition.id
    
  4. 使用 az deployment group create 部署 Bicep 模板。 指定 Bicep 模板和 Azure 资源组的名称。

    az deployment group create \
        --resource-group "<name-of-existing-resource-group>" \
        --template-file control-plane-role-definition.bicep
    
  5. 查看部署的输出。 输出包含属性中 properties.outputs.definitionId.value 角色定义的唯一标识符。 记下此值,因为本指南后面的工作分配步骤需要使用此值。

    {
      "properties": {
        "outputs": {
          "definitionId": {
            "type": "String",
            "value": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example/providers/Microsoft.Authorization/roleDefinitions/a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1"
          }
        }
      }
    }
    

    注释

    在此示例中,该值 id/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/msdocs-identity-example/providers/Microsoft.Authorization/roleDefinitions/a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1. 此示例使用虚构数据,标识符与此示例不同。 此示例是部署中输出的典型 JSON 的子集,为清楚起见。

  6. 创建新的 Bicep 文件以定义角色分配。 将文件命名为 control-plane-role-assignment.bicep

    metadata description = 'Assign RBAC role for Azure role-based access control access to Azure DocumentDB.'
    
    @description('Id of the role definition to assign to the targeted principal in the context of the cluster.')
    param roleDefinitionId string
    
    @description('Id of the identity/principal to assign this role in the context of the cluster.')
    param identityId string
    
    resource assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
      name: guid(subscription().id, resourceGroup().id, roleDefinitionId, identityId)
      scope: resourceGroup()
      properties: {
        roleDefinitionId: roleDefinitionId
        principalId: identityId
      }
    }
    
  7. 创建名为 control-plane-role-assignment 的新 Bicep 参数文件。bicepparam 在此参数文件中。将以前记录的角色定义标识符分配给参数 roleDefinitionId,将您身份的唯一标识符分配给参数 identityId

    using './control-plane-role-assignment.bicep'
    
    param roleDefinitionId = '<id-of-new-role-definition>'
    param identityId = '<id-of-existing-identity>'
    
  8. 使用 az deployment group create 部署此 Bicep 模板。

    az deployment group create \
        --resource-group "<name-of-existing-resource-group>" \
        --parameters control-plane-role-assignment.bicepparam \
        --template-file control-plane-role-assignment.bicep
    
  1. 登录到 Azure 门户 (https://portal.azure.com)。

  2. 在全局搜索栏中输入 资源组

  3. “服务”中,选择 “资源组”。

  4. 在“ 资源组 ”窗格中,选择现有的资源组。

  5. 在资源组的窗格中,在服务菜单中选择 访问控制(IAM )。

  6. “访问控制”(IAM) 窗格中,选择“ 添加”。 然后选择 “添加自定义角色”。

  7. “基本信息 ”窗格中,配置以下选项,然后选择“ 下一步” :

    价值
    自定义角色名称 Azure DocumentDB RBAC Owner
    说明 Can perform all Azure role-based access control actions for Azure DocumentDB clusters.
    基线权限 从头开始
  8. 在“ 权限 ”窗格中,选择“ 添加权限”。 然后,在权限对话框中搜索 DocumentDB 。 最后,选择 Microsoft.DocumentDB/mongoClusters 选项。

  9. 在“权限”对话框中,为 选择所有 Microsoft.DocumentDB/mongoClusters。 然后选择 “添加 ”以返回到“权限 ”窗格。

  10. 返回“ 权限 ”窗格,观察权限列表。 然后选择 “查看 + 创建”。

  11. “审阅 + 创建 ”窗格中,查看新角色定义的指定选项。 最后,选择“ 创建”。

  12. 等待门户完成角色定义创建。

  13. “访问控制”(IAM) 窗格中,选择“ 添加 ”,然后选择 “添加角色分配”。

  14. “角色 ”窗格中,搜索 Azure DocumentDB 并选择本指南前面创建的 Azure DocumentDB RBAC 所有者 角色。 然后选择下一步

    小窍门

    可以选择筛选角色列表,以仅包含自定义角色。

  15. 在“ 成员 ”窗格中,选择“ 选择成员 ”选项。 在成员对话框中,选择要为 Azure DocumentDB 群集授予此级别访问权限的标识,然后使用 “选择 ”选项确认选择。

  16. 返回“ 成员 ”窗格,查看所选成员[s],然后选择“ 审阅 + 分配”。

  17. “审阅 + 分配 ”窗格中,查看新角色分配的指定选项。 最后,选择“ 审阅 + 分配”。

  18. 等待门户完成创建角色分配。

  1. 打开新的终端。

  2. 登录到 Azure CLI。

  3. 检查目标 Azure 订阅。

    az account show
    
  4. 创建新的 Terraform 文件以定义角色定义。 将文件 control-plane-role-definition 命名。tf 将以下项 actions 添加到定义:

    Description
    Microsoft.DocumentDb/mongoClusters/* 启用所有可能的操作。
    variable "role_definition_name" {
      type        = string
      description = "Name of the role definition."
      default     = "Azure DocumentDB RBAC Owner"
    }
    
    variable "role_definition_description" {
      type        = string
      description = "Description of the role definition."
      default     = "Can perform all Azure role-based access control actions for Azure DocumentDB clusters."
    }
    
    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~> 4.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    data "azurerm_client_config" "current" {}
    
    data "azurerm_resource_group" "existing" {
      name = "<name-of-existing-resource-group>"
    }
    
    resource "azurerm_role_definition" "control_plane" {
      name               = var.role_definition_name
      scope              = data.azurerm_resource_group.existing.id
      description        = var.role_definition_description
    
      permissions {
        actions = [
          "Microsoft.DocumentDb/mongoClusters/*"
        ]
      }
    
      assignable_scopes = [
        data.azurerm_resource_group.existing.id
      ]
    }
    
    output "definition_id" {
      value = azurerm_role_definition.control_plane.id
    }
    
  5. 初始化 Terraform 部署。

    terraform init --upgrade
    
  6. 为角色定义创建执行计划,并将其保存到名为 role-definition.tfplan 的文件。

    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform plan --out "role-definition.tfplan"
    
  7. 应用执行计划将角色定义部署到 Azure。

    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform apply "role-definition.tfplan"
    
  8. 查看部署的输出。 输出包含属性中 definition_id 角色定义的唯一标识符。 记下此值,因为本指南后面的工作分配步骤需要使用此值。

  9. 创建新的 Terraform 文件以定义角色分配。 将文件 control-plane-role-assignment 命名。tf

    variable "role_definition_id" {
      type        = string
      description = "Id of the role definition to assign to the targeted principal in the context of the cluster."
    }
    
    variable "identity_id" {
      type        = string
      description = "Id of the identity/principal to assign this role in the context of the cluster."
    }
    
    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~> 4.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    data "azurerm_resource_group" "existing" {
      name = "<name-of-existing-resource-group>"
    }
    
    resource "azurerm_role_assignment" "control_plane" {
      scope              = data.azurerm_resource_group.existing.id
      role_definition_id = var.role_definition_id
      principal_id       = var.identity_id
    }
    
  10. 创建名为 control-plane-role-assignment.tfvars 的新 Terraform 变量文件。 在此变量文件中;将以前记录的角色定义标识符分配给 role_definition_id 变量,并将标识的唯一标识符分配给 identity_id 变量。

    role_definition_id = "<id-of-new-role-definition>"
    identity_id        = "<id-of-existing-identity>"
    
  11. 初始化并应用此 Terraform 配置。

    terraform init --upgrade
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform plan --var-file="control-plane-role-assignment.tfvars" --out "role-assignment.tfplan"
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform apply "role-assignment.tfplan"
    

Microsoft Entra ID 身份验证

创建 Azure DocumentDB 群集时,群集配置为默认仅使用本机身份验证。 若要使用 Microsoft Entra ID 启用身份验证,请打开 Microsoft Entra ID 身份验证方法,并将 Microsoft Entra ID 标识添加到群集。

  1. 使用 az ad signed-in-user 获取当前登录帐户的详细信息。

    az ad signed-in-user show
    
  2. 该命令将输出包含各种字段的 JSON 响应。

    {
      "@odata.context": "<https://graph.microsoft.com/v1.0/$metadata#users/$entity>",
      "businessPhones": [],
      "displayName": "Kai Carter",
      "givenName": "Kai",
      "id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
      "jobTitle": "Senior Sales Representative",
      "mail": "<kai@adventure-works.com>",
      "mobilePhone": null,
      "officeLocation": "Redmond",
      "preferredLanguage": null,
      "surname": "Carter",
      "userPrincipalName": "<kai@adventure-works.com>"
    }
    

    小窍门

    记录id字段的值。 在此示例中,该值为 aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb. 然后,可以在各种脚本中使用此值来授予对 Azure 资源的当前帐户基于角色的访问控制权限。 如果使用托管标识,可以通过使用 az identity show 命令获取该托管标识的 id

  3. 通过将 authConfig.allowedModes 包含在 MicrosoftEntraID 数组中并更新群集资源,以在群集上启用 Microsoft Entra ID 身份验证:

    az resource patch \
        --resource-group "<resource-group>" \
        --name "<cluster-name>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters" \
        --properties '{"authConfig":{"allowedModes":["MicrosoftEntraID","NativeAuth"]}}' \
        --latest-include-preview
    

    注释

    <resource-group><cluster-name> 替换为自定义值。

  4. 使用 az resource show 读取 authConfig 群集上的属性,以验证更改是否已应用。

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters" \
        --query "properties.authConfig" \
        --latest-include-preview
    

    注释

    输出应包含 allowedModes 列表。 如果已成功启用Microsoft Entra ID,则数组包含这两个 ID NativeAuthMicrosoftEntraID

  1. (可选)获取计划在群集上注册的 Microsoft Entra 主体的唯一标识符。 可以使用以下命令之一通过 Azure CLI 获取它:

    • 当前已登录身份

      az ad signed-in-user show      
      
    • 使用友好名称的另一个个人身份

      az ad user show \
        --id "<user-alias-and-domain>"
      
    • 服务主体使用应用程序标识符

      az ad sp show \
        --id "<application-id>"
      
    • 使用资源组和名称的托管标识

      az identity show \
        --resource-group "<resource-group>" \
        --name "<managed-identity-name>"      
      
  2. 创建一个小型 Bicep 模板,用于更新群集 authConfig 以包含 Microsoft Entra ID(另存为 enable-entra-id.bicep):

    param clusterName string
    param location string = resourceGroup().location
    
    resource cluster 'Microsoft.DocumentDB/mongoClusters@2025-09-01' = {
      name: clusterName
      location: location
      properties: {
        authConfig: {
          allowedModes: [
            'MicrosoftEntraID'
            'NativeAuth'
          ]
        }
      }
    }
    
  3. 部署模板以更新群集:

    az deployment group create \
        --resource-group "<resource-group>" \
        --template-file enable-entra-id.bicep \
        --parameters clusterName="<cluster-name>"
    
  4. 使用 az resource show 验证群集上的 authConfig 属性。

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters" \
        --query "properties.authConfig" \
        --latest-include-preview
    

    注释

    输出应包含 allowedModes 列表。 如果已成功启用Microsoft Entra ID,则数组包含这两个 ID NativeAuthMicrosoftEntraID

  1. 在 Azure 门户的 “主页 ”窗格中,找到并选择 Microsoft Entra ID 选项。

    Azure 门户的“主页”页中Microsoft Entra ID 选项的屏幕截图。

    小窍门

    如果未列出此选项,请选择“更多服务”,然后使用搜索词“Entra”搜索Microsoft Entra ID

  2. 在Microsoft Entra ID 租户的“概述”窗格中,选择“服务”菜单的“管理”部分内的“用户”。

    Microsoft Entra ID 租户的服务菜单中的“用户”选项的屏幕截图。

  3. 在用户列表中,选择您要获取更多信息的用户身份。

    Microsoft Entra ID 租户的用户列表的屏幕截图,其中突出显示了示例用户。

    注释

    此屏幕截图演示了一个名为“Kai Carter”和主体为 kai@adventure-works.com 的示例用户

  4. 在特定用户的详细信息窗格中,观察 对象 ID 属性的值。

    用户详细信息窗格的屏幕截图,其中突出显示了“对象 ID”。

    小窍门

    记录 对象 ID 属性的值。 在此示例中,该值为 aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb. 然后,可以在各种脚本中使用此值来授予对 Azure 资源的当前帐户基于角色的访问控制权限。 如果使用托管标识,则步骤类似。

  5. 导航到现有的 Azure DocumentDB 群集资源。

  6. 在群集菜单中的 “设置”下,选择“ 身份验证”。

  7. “身份验证方法” 部分中,选择 “本机 DocumentDB 身份验证”和“Microsoft Entra ID”,以启用 Microsoft Entra ID 身份验证以及本机身份验证。

  8. 选择 “保存” 以保留更改。

  9. “身份验证方法”部分现在应同时将 NativeAuthMicrosoftEntraID 列为已启用的方法。

  1. (可选)获取计划在群集上注册的 Microsoft Entra 主体的唯一标识符。 可以使用以下命令之一通过 Azure CLI 获取它:

    • 当前已登录身份

      az ad signed-in-user show      
      
    • 使用友好名称的另一个个人身份

      az ad user show \
        --id "<user-alias-and-domain>"
      
    • 服务主体使用应用程序标识符

      az ad sp show \
        --id "<application-id>"
      
    • 使用资源组和名称的托管标识

      az identity show \
        --resource-group "<resource-group>" \
        --name "<managed-identity-name>"      
      
  2. 创建 Terraform 配置文件,以便在现有群集上启用Microsoft Entra ID 身份验证。 将文件另存为 enable-entra-id.tf

    variable "cluster_name" {
      type        = string
      description = "Name of the existing cluster"
    }
    
    variable "resource_group_name" {
      type        = string
      description = "Name of the existing resource group"
    }
    
    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~> 4.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    data "azurerm_resource_group" "existing" {
      name = var.resource_group_name
    }
    
    data "azurerm_mongo_cluster" "existing" {
      name                = var.cluster_name
      resource_group_name = data.azurerm_resource_group.existing.name
    }
    
    resource "azurerm_mongo_cluster" "enable_entra" {
      name                   = data.azurerm_mongo_cluster.existing.name
      resource_group_name    = data.azurerm_resource_group.existing.name
      location               = data.azurerm_mongo_cluster.existing.location
      administrator_username = data.azurerm_mongo_cluster.existing.administrator_username
      administrator_password = data.azurerm_mongo_cluster.existing.administrator_password
      shard_count            = data.azurerm_mongo_cluster.existing.shard_count
      compute_tier           = data.azurerm_mongo_cluster.existing.compute_tier
      high_availability_mode = data.azurerm_mongo_cluster.existing.high_availability_mode
      storage_size_in_gb     = data.azurerm_mongo_cluster.existing.storage_size_in_gb
      version                = data.azurerm_mongo_cluster.existing.version
    
      # Enable both Microsoft Entra ID and Native authentication
      authentication_enabled = true
    }
    

    小窍门

    有关使用 azurerm_mongo_cluster 资源的选项的详细信息,请参阅 azurerm Terraform 注册表中的提供程序文档

  3. 使用群集详细信息创建名为 enable-entra-id.tfvars 的 变量文件:

    cluster_name        = "<cluster-name>"
    resource_group_name = "<resource-group>"
    
  4. 初始化并应用 Terraform 配置以启用Microsoft Entra ID 身份验证:

    terraform init --upgrade
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform plan --var-file="enable-entra-id.tfvars" --out "enable-entra.tfplan"
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform apply "enable-entra.tfplan"
    
  5. 使用 az resource show 验证群集上的 authConfig 属性。

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters" \
        --query "properties.authConfig" \
        --latest-include-preview
    

    注释

    输出应包含 allowedModes 列表。 如果已成功启用Microsoft Entra ID,则数组包含这两个 ID NativeAuthMicrosoftEntraID

管理 DocumentDB 管理 Microsoft Entra ID 标识和本机用户

Microsoft在 Azure DocumetnDB 群集上启用 Entra ID 身份验证时,可以将一个或多个 Microsoft Entra ID 主体作为 管理员用户 添加到该群集。 Microsoft Entra ID 管理员可以是 Microsoft Entra ID 用户、服务主体或托管标识。 可以随时配置多个Microsoft Entra ID 管理员。

管理 Entra ID 用户被创建为 Microsoft.DocumentDB/mongoClusters/users 下的 Azure 实体,并被复制到数据库中。

此外,一旦启用 Entra ID 身份验证,可以随时将一个或多个非管理Microsoft Entra ID 用户添加到 Microsoft群集。 非管理员用户通常用于不需要管理权限的持续生产任务。

对于 Azure DocumentDB,通过在群集上注册 Microsoft Entra 主体,并将它们映射到 MongoDB 数据库角色(例如,在某个数据库上使用readWrite或在admin数据库上使用root),来授予此访问权限。 注册主体被创建为类型为Microsoft.DocumentDB/mongoClusters/users,名称格式为<cluster-name>/users/<principal-id>的 Azure 资源。

管理用户具有管理群集及其数据的完整权限,包括完整的用户管理功能。 对于非管理员用户,可以通过特定的 MongoDB 数据库角色授予读写或只读权限。 readWriteAnyDatabaseclusterAdmin 角色共同授予对群集的完整读写权限,包括数据库管理和数据库作的权限。 readAnyDatabase 角色用于授予对群集的只读权限。 不能单独分配 readWriteAnyDatabaseclusterAdmin 角色 - 必须一起授予它们才能完全读写访问权限。

非管理员(辅助)用户和安全主体在群集上被授予有限的用户管理权限,如下表所述:

安全提供程序 角色 创建用户 (CreateUser) DeleteUser UpdateUser 列出用户
Microsoft Entra ID 读写(readWriteAnyDatabase,clusterAdmin) ✔️
Microsoft Entra ID 只读(readAnyDatabase) ✔️
原生 DocumentDB 读写(readWriteAnyDatabase,clusterAdmin) 仅更改自己的密码 ✔️
原生 DocumentDB 只读(readAnyDatabase) 仅更改自己的密码 ✔️
  1. 获取要授予访问权限的 Microsoft Entra 主体的唯一标识符(对象 ID),使用以下命令之一:

    • 当前已登录身份

      az ad signed-in-user show      
      
    • 使用友好名称的另一个个人身份

      az ad user show \
        --id "<user-alias-and-domain>"
      
    • 服务主体使用应用程序标识符

      az ad sp show \
        --id "<application-id>"
      
    • 使用资源组和名称的托管标识

      az identity show \
        --resource-group "<resource-group>" \
        --name "<managed-identity-name>"      
      
  2. 在群集上注册主体对象,并将其映射到 MongoDB 数据库角色。 以下示例将主体注册为 sales 数据库中的 readWrite 用户:

    az resource create \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --location "<cluster-region>" \
        --properties '{"identityProvider":{"type":"MicrosoftEntraID","properties":{"principalType":"User"}},"roles":[{"db":"sales","role":"readWrite"}]}' \
        --latest-include-preview
    
    • principalType替换为应用/服务主体的servicePrincipal或托管标识的ManagedIdentity
    • 若要授予管理权限,请在 roles 数组中使用 {"db":"admin","role":"root"}
  3. 列出所有已注册主体及其映射角色(群集级别视图):

    az rest \
        --method "GET" \
        --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.DocumentDB/mongoClusters/<cluster-name>/users?api-version=2025-09-01"
    
    • 响应包含一组用户资源,每个资源都有 identityProvider 元数据和一个 roles 显示映射的数据库角色的数组。
  4. 获取特定注册主体的详细信息(替换 <principal-id>):

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --latest-include-preview
    
  5. 删除已注册主体(撤销数据平面访问):

    az resource delete \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --latest-include-preview
    
  1. 创建 Bicep 文件(例如 register-principal.bicep),以注册主体和映射数据库角色:

    param clusterName string
    param principalId string
    param location string = resourceGroup().location
    param principalType string = 'User'
    param roles array = [
      {
        db: 'sales'
        role: 'readWrite'
      }
    ]
    
    resource user 'Microsoft.DocumentDB/mongoClusters/users@2025-09-01' = {
      name: '${clusterName}/users/${principalId}'
      location: location
      properties: {
        identityProvider: {
          type: 'Microsoft.EntraID'
          properties: {
            principalType: principalType
          }
        }
        roles: roles
      }
    }
    
  2. 部署 Bicep 模板以注册主体:

    az deployment group create \
        --resource-group "<resource-group>" \
        --template-file register-principal.bicep \
        --parameters clusterName="<cluster-name>" principalId="<principal-id>"
    
  3. 使用 REST API 列出群集的所有已注册主体(在 Bicep 部署后很有用):

    az rest \
        --method GET \
        --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.DocumentDB/mongoClusters/<cluster-name>/users?api-version=2025-09-01"
    
  4. 获取 Bicep 创建的特定注册主体的详细信息(替换 <principal-id>):

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --latest-include-preview
    
  5. 通过删除资源(或部署没有用户资源的模板)删除主体:

    az resource delete \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --latest-include-preview
    
  1. 在 Azure 门户中打开目标 Azure DocumentDB 群集。

  2. 在“设置”下选择“身份验证”

  3. “Microsoft Entra ID 身份验证 ”部分中,门户按对象 ID 列出已注册的Microsoft Entra 主体。 使用此视图可以:

    • 扫描列表以查找预期的对象标识符。
    • 通过选择列出的条目(或使用门户的搜索功能)检查单个主体的详细信息。
    • 使用对应条目旁边的“删除”操作,立即撤销用户的数据平面访问权限。
  4. 若要获取门户列表中显示的对象标识符的友好名称,请使用“Microsoft Entra ID”部分内的“用户”页。 然后,按对象 ID 或友好名称进行搜索。

  1. 获取要授予访问权限的 Microsoft Entra 主体的唯一标识符(对象 ID),使用以下命令之一:

    • 当前已登录身份

      az ad signed-in-user show      
      
    • 使用友好名称的另一个个人身份

      az ad user show \
        --id "<user-alias-and-domain>"
      
    • 服务主体使用应用程序标识符

      az ad sp show \
        --id "<application-id>"
      
    • 使用资源组和名称的托管标识

      az identity show \
        --resource-group "<resource-group>" \
        --name "<managed-identity-name>"      
      
  2. 创建 Terraform 文件(例如 register-principal.tf),以使用 AzAPI 提供程序来注册主体并映射数据库角色:

    variable "cluster_name" {
      type        = string
      description = "Name of the existing cluster"
    }
    
    variable "resource_group_name" {
      type        = string
      description = "Name of the existing resource group"
    }
    
    variable "principal_id" {
      type        = string
      description = "Object ID of the Microsoft Entra principal"
    }
    
    variable "principal_type" {
      type        = string
      description = "Type of principal: User, ServicePrincipal, or ManagedIdentity"
      default     = "User"
    }
    
    variable "roles" {
      type = list(object({
        db   = string
        role = string
      }))
      description = "Database roles to assign"
      default = [
        {
          db   = "sales"
          role = "readWrite"
        }
      ]
    }
    
    terraform {
      required_providers {
        azapi = {
          source  = "azure/azapi"
          version = "~> 2.0"
        }
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~> 4.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    provider "azapi" {}
    
    data "azurerm_resource_group" "existing" {
      name = var.resource_group_name
    }
    
    data "azurerm_mongo_cluster" "existing" {
      name                = var.cluster_name
      resource_group_name = var.resource_group_name
    }
    
    resource "azapi_resource" "mongo_cluster_user" {
      type      = "Microsoft.DocumentDB/mongoClusters/users@2025-09-01"
      name      = var.principal_id
      parent_id = data.azurerm_mongo_cluster.existing.id
      location  = data.azurerm_resource_group.existing.location
    
      body = {
        properties = {
          identityProvider = {
            type = "MicrosoftEntraID"
            properties = {
              principalType = var.principal_type
            }
          }
          roles = var.roles
        }
      }
    }
    

    小窍门

    有关 AzAPI 提供程序的详细信息,请参阅 Azure AzAPI 提供程序文档

    • principalType替换为应用/服务主体的servicePrincipal或托管标识的ManagedIdentity
    • 若要授予管理权限,请在 roles 数组中使用 {"db":"admin","role":"root"}
  3. 创建名为 : 的 register-principal.tfvars变量文件:

    cluster_name        = "<cluster-name>"
    resource_group_name = "<resource-group>"
    principal_id        = "<principal-id>"
    principal_type      = "User"
    roles = [
      {
        db   = "sales"
        role = "readWrite"
      }
    ]
    
  4. 初始化并应用 Terraform 配置以注册主体:

    terraform init --upgrade
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform plan --var-file="register-principal.tfvars" --out "register-principal.tfplan"
    
    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform apply "register-principal.tfplan"
    
  5. 使用 REST API 列出群集的所有已注册主体(在 Terraform 部署后很有用):

    az rest \
        --method GET \
        --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.DocumentDB/mongoClusters/<cluster-name>/users?api-version=2025-09-01"
    
  6. 获取由 Terraform 创建的特定注册主体的详细信息(替换 <principal-id>):

    az resource show \
        --resource-group "<resource-group>" \
        --name "<cluster-name>/users/<principal-id>" \
        --resource-type "Microsoft.DocumentDB/mongoClusters/users" \
        --latest-include-preview
    
  7. 通过销毁 Terraform 资源移除主体:

    ARM_SUBSCRIPTION_ID=$(az account show --query id --output tsv) terraform destroy --var-file="register-principal.tfvars"
    

注释

Azure DocumentDB 群集是通过创建一个内置的本地管理 DocumentDB 用户来完成的。 完成群集预配后,可以 添加更多本机管理 DocumentDB 用户 。 Microsoft Entra ID 管理用户添加到群集后,将成为同一群集上已定义的本机管理 DocumentDB 用户之外的附加用户。 所有的 Microsoft Entra ID 管理标识都会被复制到数据库中。

在数据库中创建非管理Microsoft Entra ID 标识。 列出数据库中的非管理用户时,该列表包含所有管理和非管理 Microsoft Entra ID 标识以及所有辅助(非管理)本机 DocumentDB 用户

获取群集凭据

可以使用首选语言的驱动程序中的连接 URI 或自定义设置对象连接到群集。 在任一选项中,必须将 方案 设置为 mongodb+srv 连接到群集。 主机位于*.global.mongocluster.cosmos.azure.com*.mongocluster.cosmos.azure.com域,具体取决于使用的是当前群集还是全局读写终结点+srv 方案和 *.global.* 主机可确保客户端在多群集配置中动态连接到适当的可写群集,即使发生区域交换操作,也是如此。 在单群集配置中,可以不分青红皂白地使用任一连接字符串。

还必须启用 tls 设置。 其余建议的设置是最佳实践配置。

选项 价值
scheme mongodb+srv
host <cluster-name>.global.mongocluster.cosmos.azure.com<cluster-name>.mongocluster.cosmos.azure.com
tls true
authMechanism MONGODB-OIDC
retrywrites false
maxIdleTimeMS 120000

重要

使用 Azure 门户 获取连接字符串。

  1. 导航到 Azure DocumentDB 群集。

  2. 选择 连接字符串 导航菜单选项。

  3. 复制或记录 连接字符串 字段中的值。

    小窍门

    Microsoft Entra ID 连接字符串位于 “Microsoft Entra ID ”部分中。

在 MongoDB Shell 中使用 Microsoft Entra ID 进行连接

使用安装了 MongoDB Shell 的客户端设备,通过 Microsoft Entra ID 标识连接到 Azure DocumentDB 群集。

  1. 在安装了 MongoDB shell 的客户端上打开终端。

  2. 获取 Azure DocumentDB 群集名称 和目标身份的 客户端 ID

  3. 使用以下连接字符串进行连接:

    mongosh "mongodb+srv://<client-id>@<cluster-name>.global.mongocluster.cosmos.azure.com/?tls=true&authMechanism=MONGODB-OIDC&retrywrites=false&maxIdleTimeMS=120000"
    

在 Visual Studio Code 中使用 Microsoft Entra ID 进行连接

将 Visual Studio Code 与 DocumentDB 扩展 配合使用,通过 Microsoft Entra ID 标识连接到 Azure DocumentDB 群集。

重要

在 Visual Studio Code 中使用 Microsoft Entra ID 对带有 DocumentDB 扩展的 Azure DocumentDB 群集进行身份验证时,shell 不支持该功能。 如果需要将 MongoDB shell 与 Microsoft Entra ID 身份验证配合使用, 请直接在客户端计算机上使用 MongoDB Shell

  1. 打开 Visual Studio Code。

  2. 在侧栏中浏览DocumentDB扩展。

  3. 在“ 连接 ”部分中,选择“ + 新建连接...”

  4. 在“连接类型”对话框中,选择 “连接字符串”。

  5. 使用以下连接字符串:

    mongodb+srv://<client-id>@<cluster-name>.global.mongocluster.cosmos.azure.com/?tls=true&authMechanism=MONGODB-OIDC&retrywrites=false&maxIdleTimeMS=120000
    
  6. 等待自动提示使用 Microsoft Entra ID 身份验证。 输入您身份类型的相关凭据。

    注释

    例如,如果要使用自己的标识(人工标识)登录,请使用无密码身份验证体验。

  7. 等待连接完成。 然后将新的 DocumentDB 条目添加到群集的 “连接” 部分。

在 MongoDB Compass 中使用 Microsoft Entra ID 进行连接

使用 Microsoft Entra ID 标识直接通过 MongoDB Compass 应用程序连接到 Azure DocumentDB 群集。

  1. 启动 MongoDB Compass 应用程序。

  2. +“连接”菜单中选择添加新连接。

  3. 切换 “编辑连接字符串 ”设置,以便在 “新建连接 ”对话框中启用。

  4. URI 输入框中输入以下连接字符串。

    mongodb+srv://<client-id>@<cluster-name>.global.mongocluster.cosmos.azure.com/?tls=true&authMechanism=MONGODB-OIDC&retrywrites=false&maxIdleTimeMS=120000
    
  5. 现在,打开 “高级连接选项 ”对话框。

  6. “常规”部分中,选择mongodb+srv“连接字符串方案”。

  7. 接下来,导航到 “身份验证 ”部分。

  8. 确保已选择 OIDC 选项。

  9. 现在,导航到 “OIDC 选项” 部分。

  10. 确保还选择了“考虑目标终结点受信任”选项。

  11. 选择“ 保存并连接”。

管理 DocumentDB 辅助(非管理)Microsoft Entra ID 标识

使用管理 Microsoft Entra ID 标识登录到群集,以对非管理 Microsoft Entra ID 标识执行管理操作。

注释

支持针对 SecurityPrincipaluser 主体类型的非管理用户的所有管理命令。

  1. 使用管理Microsoft Entra ID 标识并使用 MongoDB Shell 等工具登录到群集。

  2. 使用命令在群集上添加具有createUser权限的非强制Microsoft Entra ID 标识:

    db.runCommand(
      {
        createUser: "<entra-id-unique-identifier>",
        roles: [
          { role: "clusterAdmin", db: "admin" },
          { role: "readWriteAnyDatabase", db: "admin" }
        ],
        customData: { "IdentityProvider": { "type": "MicrosoftEntraID", "properties": { "principalType": "user" } } }
      }
    )
    
  3. 在具有 createUser 和一组不同角色的群集中添加具有只读权限的非管理 Microsoft Entra ID 标识。

    db.runCommand(
      {
        createUser: "<entra-id-unique-identifier>",
        roles: [
          { role: "readAnyDatabase", db: "admin" }
        ],
        customData: { "IdentityProvider": { "type": "MicrosoftEntraID", "properties": { "principalType": "user" } } }
      }
    )
    
  4. 使用 dropUser 命令从群集中删除非管理Microsoft Entra ID 标识。

    db.runCommand(
      {
        dropUser: "<entra-id-unique-identifier>"
      }
    )
    
  5. 使用 userInfo 列出群集上所有 Microsoft Entra ID 和本地 DocumentDB 用户。

    db.runCommand(
      {
        usersInfo: 1
      }
    )
    

    注释

    所有 Microsoft Entra ID 和 Azure DocumentDB 的管理用户都已复制到数据库中。 由于此复制,用户列表包含群集中的所有管理和非管理的Microsoft Entra ID用户以及本地DocumentDB用户。

在代码中使用 Microsoft Entra ID 进行连接

验证是否使用应用程序代码和首选语言的相应客户端库正确授予访问权限。

class AzureIdentityTokenCallback(OIDCCallback):
    def __init__(self, credential):
        self.credential = credential

    def fetch(self, context: OIDCCallbackContext) -> OIDCCallbackResult:
        token = self.credential.get_token(
            "https://ossrdbms-aad.database.windows.net/.default").token
        return OIDCCallbackResult(access_token=token)

clusterName = "<cluster-name>"

credential = DefaultAzureCredential()
authProperties = {"OIDC_CALLBACK": AzureIdentityTokenCallback(credential)}

client = MongoClient(
  f"mongodb+srv://{clusterName}.global.mongocluster.cosmos.azure.com/",
  connectTimeoutMS=120000,
  tls=True,
  retryWrites=True,
  authMechanism="MONGODB-OIDC",
  authMechanismProperties=authProperties
)
const AzureIdentityTokenCallback = async (params: OIDCCallbackParams, credential: TokenCredential): Promise<OIDCResponse> => {
  const tokenResponse: AccessToken | null = await credential.getToken(['https://ossrdbms-aad.database.windows.net/.default']);
  return {
      accessToken: tokenResponse?.token || '',
      expiresInSeconds: (tokenResponse?.expiresOnTimestamp || 0) - Math.floor(Date.now() / 1000)
  };
};

const clusterName: string = '<cluster-name>';

const credential: TokenCredential = new DefaultAzureCredential();

const client = new MongoClient(
    `mongodb+srv://${clusterName}.global.mongocluster.cosmos.azure.com/`, {
    connectTimeoutMS: 120000,
    tls: true,
    retryWrites: true,
    authMechanism: 'MONGODB-OIDC',
    authMechanismProperties: {
        OIDC_CALLBACK: (params: OIDCCallbackParams) => AzureIdentityTokenCallback(params, credential),
        ALLOWED_HOSTS: ['*.azure.com']
    }
  }
);
string tenantId = "<microsoft-entra-tenant-id>";
string clusterName = "<cluster-name>";

DefaultAzureCredential credential = new();
AzureIdentityTokenHandler tokenHandler = new(credential, tenantId);

MongoUrl url = MongoUrl.Create($"mongodb+srv://{clusterName}.global.mongocluster.cosmos.azure.com/");
MongoClientSettings settings = MongoClientSettings.FromUrl(url);
settings.UseTls = true;
settings.RetryWrites = false;
settings.MaxConnectionIdleTime = TimeSpan.FromMinutes(2);
settings.Credential = MongoCredential.CreateOidcCredential(tokenHandler);
settings.Freeze();

MongoClient client = new(settings);

internal sealed class AzureIdentityTokenHandler(
    TokenCredential credential,
    string tenantId
) : IOidcCallback
{
    private readonly string[] scopes = ["https://ossrdbms-aad.database.windows.net/.default"];

    public OidcAccessToken GetOidcAccessToken(OidcCallbackParameters parameters, CancellationToken cancellationToken)
    {
        AccessToken token = credential.GetToken(
            new TokenRequestContext(scopes, tenantId: tenantId),
            cancellationToken
        );

        return new OidcAccessToken(token.Token, token.ExpiresOn - DateTimeOffset.UtcNow);
    }

    public async Task<OidcAccessToken> GetOidcAccessTokenAsync(OidcCallbackParameters parameters, CancellationToken cancellationToken)
    {
        AccessToken token = await credential.GetTokenAsync(
            new TokenRequestContext(scopes, parentRequestId: null, tenantId: tenantId),
            cancellationToken
        );

        return new OidcAccessToken(token.Token, token.ExpiresOn - DateTimeOffset.UtcNow);
    }
}