使用托管标识将 Function App 连接到 CosmosDB
Connect Function App to CosmosDB with Managed Identity
我正在尝试在 Function App 中编写一个函数来操作 CosmosDB 中的数据。如果我在环境变量中删除读写密钥,我就能正常工作。为了让它更健壮,我希望它作为一个托管身份应用程序工作。该应用在 Cosmos DB 上具有 'DocumentDB Account Contributor' 角色。
但是,CosmosClient 构造函数不接受凭据并且需要读写密钥。我一直在寻找 azure.mgmt.cosmosdb.operations 的兔子洞,那里有 DatabaseAccountsOperations
class 和 list_keys()
方法。不过,我找不到访问该功能的巧妙方法。如果我尝试创建该对象(这需要从我的 dbmgmt 对象中窃取配置、序列化程序和反序列化程序),它仍然需要 resourceGroupName
和 accountName
.
我忍不住认为我在某处走错了路,因为这必须以更直接的方式实现。特别是考虑到 JavaScript SDK 引用了与 SubscriptionClient 一致的更合乎逻辑的 class CosmosDBManagementClient。但是,我在 python 一侧的任何地方都找不到 class。
有什么指点吗?
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...
编辑
一位乐于助人的人在这里提供了回复,但在我做出反应或接受它作为答案之前将其删除。他们指出有一个等效的 python SDK 并且 from azure.mgmt.cosmosdb import CosmosDBManagementClient
可以解决问题。
从那时起,我就靠自己了,结果是
ImportError: cannot import name 'CosmosDBManagementClient' from 'azure.mgmt.cosmosdb'
我认为问题的根源在于包的不兼容性 azure-mgmt
。从我的 requirements.txt
中删除 azure-mgmt
并仅加载 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'
真的需要收集这些参数中的每一个吗?比起example that reads a secret from a Vault就显得很绕了
对于其他希望使用托管身份访问 CosmosDB 的不幸用户,截至 2021 年 5 月,这似乎还不可能。
来源:Github
上的讨论
2021 年 5 月 12 日更新 - 我来这里是为了寻找解决方案 Javascript/Typescript。所以把答案留给其他人。我认为类似的方法适用于 Python.
您可以使用 RBAC 通过托管身份进行数据平面操作。很难找到文档。
RBAC for Cosmos DB data plane operations with Managed Identities
重要 - 如果您收到错误 Request blocked by Auth mydb :请求被阻止,因为主体 [xxxxxx-6fad-44e4-98bc-2d423a88b65f] 确实没有执行操作所需的 RBAC 权限 Microsoft.DocumentDB/databaseAccounts/readMetadata 对资源 [/]。 不要使用门户分配角色,使用 Azure CLI for CosmosDB。
How to - creating a role assignment for a user/system MSI/user MSI is done using the 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 App 以及使用 VS 代码或 az login
.
的笔记本电脑
Examples of authentication with @azure/identity to get the credential object
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
});
我正在尝试在 Function App 中编写一个函数来操作 CosmosDB 中的数据。如果我在环境变量中删除读写密钥,我就能正常工作。为了让它更健壮,我希望它作为一个托管身份应用程序工作。该应用在 Cosmos DB 上具有 'DocumentDB Account Contributor' 角色。
但是,CosmosClient 构造函数不接受凭据并且需要读写密钥。我一直在寻找 azure.mgmt.cosmosdb.operations 的兔子洞,那里有 DatabaseAccountsOperations
class 和 list_keys()
方法。不过,我找不到访问该功能的巧妙方法。如果我尝试创建该对象(这需要从我的 dbmgmt 对象中窃取配置、序列化程序和反序列化程序),它仍然需要 resourceGroupName
和 accountName
.
我忍不住认为我在某处走错了路,因为这必须以更直接的方式实现。特别是考虑到 JavaScript SDK 引用了与 SubscriptionClient 一致的更合乎逻辑的 class CosmosDBManagementClient。但是,我在 python 一侧的任何地方都找不到 class。 有什么指点吗?
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...
编辑
一位乐于助人的人在这里提供了回复,但在我做出反应或接受它作为答案之前将其删除。他们指出有一个等效的 python SDK 并且 from azure.mgmt.cosmosdb import CosmosDBManagementClient
可以解决问题。
从那时起,我就靠自己了,结果是
ImportError: cannot import name 'CosmosDBManagementClient' from 'azure.mgmt.cosmosdb'
我认为问题的根源在于包的不兼容性 azure-mgmt
。从我的 requirements.txt
中删除 azure-mgmt
并仅加载 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'
真的需要收集这些参数中的每一个吗?比起example that reads a secret from a Vault就显得很绕了
对于其他希望使用托管身份访问 CosmosDB 的不幸用户,截至 2021 年 5 月,这似乎还不可能。
来源:Github
上的讨论2021 年 5 月 12 日更新 - 我来这里是为了寻找解决方案 Javascript/Typescript。所以把答案留给其他人。我认为类似的方法适用于 Python.
您可以使用 RBAC 通过托管身份进行数据平面操作。很难找到文档。
RBAC for Cosmos DB data plane operations with Managed Identities
重要 - 如果您收到错误 Request blocked by Auth mydb :请求被阻止,因为主体 [xxxxxx-6fad-44e4-98bc-2d423a88b65f] 确实没有执行操作所需的 RBAC 权限 Microsoft.DocumentDB/databaseAccounts/readMetadata 对资源 [/]。 不要使用门户分配角色,使用 Azure CLI for CosmosDB。 How to - creating a role assignment for a user/system MSI/user MSI is done using the 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 App 以及使用 VS 代码或 az login
.
Examples of authentication with @azure/identity to get the credential object
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
});