Reputation: 1321
I have a private Azure Cosmos DB for MongoDB account (RU) together with a private AKS cluster. I want to access the MongoDB server from the AKS cluster through a workload identity. I followed the tutorial
https://learn.microsoft.com/en-us/azure/aks/learn/tutorial-kubernetes-workload-identity
My AKS Cluster has the OIDC stuff enabled. Also, I have created a User-Assigned Managed Identity (called test-mongo
below) with the relevant role assignments (DocumentDB Account Contributor
). The goal is that the test-mongo
managed identity be able to perform data operations on the MongoDB server. In this particular post, I want to list the database names. Later on, I will not want that identity to be able to do that anymore, instead I will want it to read / write documents in some collections of some database.
First, I created the service account
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
azure.workload.identity/client-id: <my-user-assigned-managed-identity-app-id>
azure.workload.identity/tenant-id: <my-tenant-id>
labels:
azure.workload.identity/use: "true"
name: test-mongo
namespace: test-mongo
Then, I established the federated identity credential like this:
az identity federated-credential create --name test-mongo --identity-name test-mongo \
--resource-group my-resource-group \
--issuer https://eastus.oic.prod-aks.azure.com/<my-tenant-id>/<my-subscription-id>/ \
--subject system:serviceaccount:test-mongo:test-mongo \
--subscription <my-subscription-id> \
--audience api://AzureADTokenExchange
Finally, I deployed the following pod:
apiVersion: v1
kind: Pod
metadata:
name: test-mongo
namespace: test-mongo
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: test-mongo
containers:
- image: my-docker-image
name: container-0
When I kubectl describe
my pod, I can see that the AZURE_CLIENT_ID
, AZURE_AUTHORITY_HOST
, AZURE_FEDERATED_TOKEN_FILE
, and AZURE_TENANT_ID
are provided to it.
My docker image is a python application which I'm not sure how to write. Currently, it looks like this:
from azure.identity import DefaultAzureCredential
from pymongo import MongoClient
def main():
credential = DefaultAzureCredential()
connection_string = f"mongodb://<cosmosdb-account-name>:{credential.get_token()}@<cosmosdb-account-name>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@<cosmosdb-account-name>@"
client = MongoClient(connection_string)
print(client.is_primary)
if __name__ == "__main__":
main()
Unfortunately, that doesn't work, because I am not passing the right scope to the credential.get_token()
method:
WorkloadIdentityCredential: "get_token" requires at least one scope
In the case of the connection with a postgres server, I believe (but I have never been in a situation to test that yet), that the following code would be correct:
credential = DefaultAzureCredential()
# here we pass the scope for postgres servers
token = credential.get_token("https://ossrdbms-aad.database.windows.net/.default")
postgresUser = '<aad-user-name>@<server-name>'
host = "<server-name>.postgres.database.azure.com"
dbname = "<database-name>"
conn_string = "host={0} user={1} dbname={2} password={3}".format(host, postgresUser, dbname, token.token)
conn = psycopg2.connect(conn_string)
How should I proceed in the MongoDB case?
Here's the documentation I checked so far on the topic:
I followed along this tutorial and tried to adapt it to python. Apparently, with the CosmosClient
, we necessarily need to access a CosmosDB server with SQL API, which is not my case, hence my adapted code fails:
credential = DefaultAzureCredential(
managed_identity_client_id="<my-user-assigned-managed-identity-app-id>"
)
data_client = CosmosClient(
url="https://<cosmosdb-account-name>.documents.azure.com:443/",
credential=credential,
)
with error
Message: Request blocked by Auth <cosmosdb-account-name>: Request is blocked because principal [<principal-id>] does not have required RBAC permissions to perform action [Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/]. Learn more: https://aka.ms/cosmos-native-rbac.
ActivityId: c1e9f553-3cac-481b-a450-d099feebfb72, Microsoft.Azure.Documents.Common/2.14.0
and trying to add that role definition to my user-assigned managed identity doesn't work because
The Database Account [<cosmosdb-account-name>] has an API type which is invalid for processing SQL Role Definitions: [MongoDB]
I tried to do this lately:
from azure.identity import DefaultAzureCredential
from pymongo import MongoClient
def main():
credential = DefaultAzureCredential(
managed_identity_client_id="<my-user-assigned-managed-identity-app-id>"
)
token = credential.get_token("https://<cosmosdb-account-name>.documents.azure.com/.default").token
connection_string = f"mongodb://<cosmosdb-account-name>:{token}@<cosmosdb-account-name>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@<cosmosdb-account-name>@"
client = MongoClient(connection_string)
client.list_database_names()
this throws
raise OperationFailure(errmsg, code, response, max_wire_version)
pymongo.errors.OperationFailure: Invalid key, full error: {'ok': 0.0, 'errmsg': 'Invalid key', 'code': 18, 'codeName': 'AuthenticationFailed'}
Upvotes: 0
Views: 554
Reputation: 1321
As of today, from the many discussions I had with the Azure Premier support, it appears authentication through workload identities to a Cosmos DB for MongoDB account (RU) is not supported. A first hint is given here and was confirmed by the product group. It may be supported in the V-Core variant in the future though.
The way to achieve secure authentication is therefore to define an identity somehow with the relevant RBAC permissions on the MongoDB server (or its collections or databases or whatever), then store the credentials in a key vault and let the pod get the credentials from that vault. Automatic key rotation would also be a good thing in that case.
Upvotes: 0