Laurent Michel
Laurent Michel

Reputation: 1321

how do I log on my azure cosmosdb for mongodb from aks through my workload identity?

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:

EDIT 1

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]

EDIT 2

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

Answers (1)

Laurent Michel
Laurent Michel

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

Related Questions