当前位置: 首页 > 知识库问答 >
问题:

使用托管身份将功能应用程序连接到CosmosDB

贺景山
2023-03-14

我正在尝试在Function App中编写一个函数来操作CosmosDB中的数据。如果我在环境变量中删除读写键,它就会工作。为了使它更健壮,我希望它作为托管标识应用程序工作。该应用程序在Cosmos DB上具有“DocumentDB帐户贡献者”角色。

但是,CosmosClient构造函数不接受凭据,需要读写密钥。我一直在追查azure的兔子洞。管理。宇宙数据库。有一个带有list\u keys()方法的DatabaseAccountsOperations类的操作。但我找不到一个简单的方法来访问该函数。如果我尝试创建该对象(需要从我的dbmgmt对象中非法获取配置、序列化器和反序列化器),它仍然需要资源组名和帐户名。

我忍不住想,我在某个地方拐错了方向,因为这必须以更直接的方式实现。特别是考虑到JavaScript SDK引用了与SubscriptionClient一致的逻辑性更强的类CosmosDBManagementClient。然而,我在python端的任何地方都找不到该类。有什么指示吗?

from azure.identity import DefaultAzureCredential
from azure.cosmos import CosmosClient
from azure.mgmt.resource import SubscriptionClient
from azure.mgmt.cosmosdb import CosmosDB
from .cred_wrapper import CredentialWrapper

def main(req: func.HttpRequest) -> func.HttpResponse:
    request_body = req.get_body()
    # credential = DefaultAzureCredential()
    # https://gist.github.com/lmazuel/cc683d82ea1d7b40208de7c9fc8de59d
    credential = CredentialWrapper()  

    uri = os.environ.get('cosmos-db-uri')
    # db = CosmosClient(url=uri, credential=credential)  # Doesn't work, wants a credential that is a RW/R key
    # Does work if I replace it with my primary / secondary key but the goal is to remove dependence on that.

    subscription_client = SubscriptionClient(credential)
    subscription = next(subscription_client.subscriptions.list())

    dbmgmt = CosmosDB(credential, subscription.subscription_id)  # This doesn't accept the DB URI??
    operations = list(dbmgmt.operations.list())  # I see the list_keys() Operation there...

一个乐于助人的灵魂在这里提供了一个响应,但在我做出反应或接受它作为答案之前就将其删除了。他们指出,有一个等效的pythonSDK并且来自azure.mgmt.cosmosdb导入CosmosDBManagementClient的可以做到这一点。

从那以后,我就靠自己了

ImportError: cannot import name 'CosmosDBManagementClient' from 'azure.mgmt.cosmosdb'

我认为问题的根源在于azure管理包的不兼容性。从我的要求中删除azure管理后。txt,并且仅加载cosmos和identiy相关包,导入错误得到解决。

这解决了90%的问题。

dbmgmt  = CosmosDBManagementClient(credential, subscription.subscription_id, c_uri)
print(dbmgmt.database_accounts.list_keys())
TypeError: list_keys() missing 2 required positional arguments: 'resource_group_name' and 'account_name'

真的需要收集这些参数吗?与从保险库中读取机密的示例相比,它似乎非常复杂。


共有2个答案

公冶才
2023-03-14

更新日期:2021年5月12日-我来这里是为了用Javascript/Typescript解决这个问题。所以把答案留给其他人。我认为类似的方法也可以用于Python。

您可以使用RBAC对托管标识进行数据平面操作。很难找到文件。

具有托管标识的Cosmos DB数据平面操作的RBAC

重要-如果您收到错误Request被Auth mydb阻止:Request被阻止,因为主体[xxxxxx-6fad-44e4-98bc-2d423a88b65f]没有执行操作所需的RBAC权限Microsoft。资源[/]上的文档数据库/数据库帐户/读取元数据。不要使用门户分配角色,请使用Azure CLI for CosmosDB。如何-为用户/系统MSI/用户MSI创建角色分配是使用Azure CosmosDB CLI完成的

# Find the role ID:

resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
az cosmosdb sql role definition list --account-name $accountName --resource-group $resourceGroupName

# Assign to the MSI or user managed MSI:

readOnlyRoleDefinitionId = '<roleDefinitionId>' # as fetched above
principalId = '<aadPrincipalId>'
az cosmosdb sql role assignment create --account-name $accountName --resource-group $resourceGroupName --scope "/" --principal-id $principalId --role-definition-id $readOnlyRoleDefinitionId

完成此步骤后,连接代码就很容易了。使用@azure/identity包的默认凭据。这在具有托管身份的Azure Function应用程序和使用VS code或az登录的笔记本电脑上都有效。

azure/identity sdk的文档

使用@azure/标识获取凭据对象的身份验证示例

import { CosmosClient } from "@azure/cosmos";
import { DefaultAzureCredential, ManagedIdentityCredential, ChainedTokenCredential } from "@azure/identity";

const defaultCredentials = new DefaultAzureCredential();
const managedCredentials = new ManagedIdentityCredential();
const aadCredentials = new ChainedTokenCredential(managedCredentials, defaultCredentials);
        
client = new CosmosClient({
                endpoint: "https://mydb.documents.azure.com:443/",
                aadCredentials
            });
贺功
2023-03-14

对于其他希望使用托管身份访问CosmosDB的不幸者来说,截至2021年5月,这似乎还不可能。

来源:关于Github的讨论

 类似资料: