Search code examples
azureazure-web-app-serviceazure-managed-identity

Multi Container Azure App services not able to access Cosmos NoSql with Managed Identity


I am building a multi container app, deployed on Azure App services with 'docker compose',assigned an identity (user assigned managed identity) and gave RBAC to principal Id to access the cosmos container with the following command

az cosmosdb sql role assignment create -a cosmos-nosql-db -g rish90-rg-westus -s "/" -p actual_principal_id -d 00000000-0000-0000-0000-000000000002

Multi container app consists of three containers nginx proxy, nginx http web server and .NET based backend server. It's the backend server which talks to CosmosDB with DefaultAzureCredential.

But with multi container app, the cosmos db is not accessible. I get error Azure.Identity.CredentialUnavailableException: DefaultAzureCredential failed to retrieve a token from the included credentials.

BUT if I deploy a backend as single container azure app service; and enable Managed identity and respective RBAC, the backend is able to access cosmos;

Here is the link to Github repo of same.

I am not able to understand what is the problem here and how can it be fixed?

here is a design of what the system looks like

rough design of system


Solution

  • I don't think multi-container app using docker compose file supports Managed identity to connect currently, as it is currently in preview. I would suggest to use connection string for connection for work around.

    Using connection string worked for me.

    I used connection string for client.

    docker-compose.yml:

    version: '3.3'
    
    services:
      proxy:
        image: vivek.azurecr.io/proxy
        ports:
          - "80:80"
        container_name: proxy
    
    
      frontend:
        image: vivek.azurecr.io/frontend
        ports:
          - "80"
        depends_on:
          - backend
        container_name: frontend
    
    
      backend:
        image: vivek.azurecr.io/backend
        ports:
          - "3000"
        container_name: backend
    
    

    TodoListDbClient.cs:

    using System.Net.Http.Headers;
    using Azure.Identity;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    using TodoApi;
    
    public class TodoListDbClient : IDbClient
    {
        private readonly Container _todoListContainer;
    
        public TodoListDbClient()
        {   
            var cosmosClientOptions = new CosmosClientOptions {
                
            };
            var cosmosClient = new CosmosClient("AccountEndpoint=https://multicontainer-web-app-db.documents.azure.com:443/;AccountKey=xxxxxxxxxxxxxxxxxxxxx;");
            _todoListContainer = cosmosClient.GetDatabase("ToDoList").GetContainer("Items");
        }
    
        public async Task<ItemResponse<Todo>> AddAsync(Todo todoItem)
        {    
            return await _todoListContainer.CreateItemAsync<Todo>(todoItem);
        }
    
        public async Task<List<Todo>> GetAllAsync()
        {
            var queryable = _todoListContainer.GetItemLinqQueryable<Todo>();
            var feed = queryable.Where(p => p.id != null).ToFeedIterator();
    
            List<Todo> todos = [];
    
            while (feed.HasMoreResults)
            {   //pagination response
                var response = await feed.ReadNextAsync();
                foreach (var item in response)
                {
                    todos.Add(item);
                }
            }
    
            return todos;
        }
    }
    

    OUTPUT