Migrate an application to use passwordless connections with Azure Cosmos DB for NoSQL

Application requests to Azure Cosmos DB for NoSQL must be authenticated. Although there are multiple options for authenticating to Azure Cosmos DB, you should prioritize passwordless connections in your applications when possible. Traditional authentication methods that use connection strings with passwords or secret keys create security risks and complications. Visit the passwordless connections for Azure services hub to learn more about the advantages of moving to passwordless connections.

The following tutorial explains how to migrate an existing application to connect to Azure Cosmos DB for NoSQL using passwordless connections instead of a key-based solution.

Configure roles and users for local development authentication

When developing locally with passwordless authentication, make sure the user account that connects to Cosmos DB is assigned a role with the correct permissions to perform data operations. Currently, Azure Cosmos DB for NoSQL doesn't include built-in roles for data operations, but you can create your own using the Azure CLI or PowerShell.

Roles consist of a collection of permissions or actions that a user is allowed to perform, such as read, write, and delete. You can read more about configuring role-based access control (RBAC) in the Cosmos DB security configuration documentation.

Create the custom role

  1. Create a role using the az role definition create command. Pass in the Cosmos DB account name and resource group, followed by a body of JSON that defines the custom role. The following example creates a role named PasswordlessReadWrite with permissions to read and write items in Cosmos DB containers. The role is also scoped to the account level using /.

    az cosmosdb sql role definition create \
        --account-name <cosmosdb-account-name> \
        --resource-group  <resource-group-name> \
        --body '{
        "RoleName": "PasswordlessReadWrite",
        "Type": "CustomRole",
        "AssignableScopes": ["/"],
        "Permissions": [{
            "DataActions": [
                "Microsoft.DocumentDB/databaseAccounts/readMetadata",
                "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
                "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
            ]
        }]
    }'
    
  2. When the command completes, copy the ID value from the name field and paste it somewhere for later use.

  3. Assign the role you created to the user account or service principal that will connect to Cosmos DB. During local development, this will generally be your own account that's logged into a development tool like Visual Studio or the Azure CLI. Retrieve the details of your account using the az ad user command.

    az ad user show --id "<your-email-address>"
    
  4. Copy the value of the id property out of the results and paste it somewhere for later use.

  5. Assign the custom role you created to your user account using the az cosmosdb sql role assignment create command and the IDs you copied previously.

    az cosmosdb sql role assignment create \
        --account-name <cosmosdb-account-name> \
        --resource-group  <resource-group-name> \
        --scope "/" \
        --principal-id <your-user-id> \
        --role-definition-id <your-custom-role-id> 
    

Sign-in to Azure locally

For local development, make sure you're authenticated with the same Microsoft Entra account you assigned the role to. You can authenticate via popular development tools, such as the Azure CLI or Azure PowerShell. The development tools with which you can authenticate vary across languages.

Sign-in to Azure through the Azure CLI using the following command:

az login

Migrate the app code to use passwordless connections

  1. To use DefaultAzureCredential in a .NET application, install the Azure.Identity package:

    dotnet add package Azure.Identity
    
  2. At the top of your file, add the following code:

    using Azure.Identity;
    
  3. Identify the locations in your code that create a CosmosClient object to connect to Azure Cosmos DB. Update your code to match the following example.

    DefaultAzureCredential credential = new();
    
    using CosmosClient client = new(
        accountEndpoint: Environment.GetEnvironmentVariable("COSMOS_ENDPOINT"),
        tokenCredential: credential
    );
    

Run the app locally

After making these code changes, run your application locally. The new configuration should pick up your local credentials, such as the Azure CLI, Visual Studio, or IntelliJ. The roles you assigned to your local dev user in Azure allows your app to connect to the Azure service locally.

Configure the Azure hosting environment

Once your application is configured to use passwordless connections and runs locally, the same code can authenticate to Azure services after it's deployed to Azure. The sections that follow explain how to configure a deployed application to connect to Azure Cosmos DB using a managed identity.

Create the managed identity

You can create a user-assigned managed identity using the Azure portal or the Azure CLI. Your application uses the identity to authenticate to other services.

  1. At the top of the Azure portal, search for Managed identities. Select the Managed Identities result.
  2. Select + Create at the top of the Managed Identities overview page.
  3. On the Basics tab, enter the following values:
    • Subscription: Select your desired subscription.
    • Resource Group: Select your desired resource group.
    • Region: Select a region near your location.
    • Name: Enter a recognizable name for your identity, such as MigrationIdentity.
  4. Select Review + create at the bottom of the page.
  5. When the validation checks finish, select Create. Azure creates a new user-assigned identity.

After the resource is created, select Go to resource to view the details of the managed identity.

A screenshot showing how to create a user assigned managed identity.

Associate the managed identity with your web app

You need to configure your web app to use the managed identity you created. Assign the identity to your app using either the Azure portal or the Azure CLI.

Complete the following steps in the Azure portal to associate an identity with your app. These same steps apply to the following Azure services:

  • Azure Spring Apps
  • Azure Container Apps
  • Azure virtual machines
  • Azure Kubernetes Service
  1. Navigate to the overview page of your web app.

  2. Select Identity from the left navigation.

  3. On the Identity page, switch to the User assigned tab.

  4. Select + Add to open the Add user assigned managed identity flyout.

  5. Select the subscription you used previously to create the identity.

  6. Search for the MigrationIdentity by name and select it from the search results.

  7. Select Add to associate the identity with your app.

    Screenshot showing how to create a user assigned identity.

Assign roles to the managed identity

Grant permissions to the managed identity by assigning it the custom role you created, just like you did with your local development user.

To assign a role at the resource level using the Azure CLI, you first must retrieve the resource ID using the az cosmosdb show command. You can filter the output properties using the --query parameter.

az cosmosdb show \
    --resource-group '<resource-group-name>' \
    --name '<cosmosdb-name>' \
    --query id

Copy the output ID from the preceding command. You can then assign roles using the az role assignment command of the Azure CLI.

az role assignment create \
    --assignee "<your-managed-identity-name>" \
    --role "PasswordlessReadWrite" \
    --scope "<cosmosdb-resource-id>"

Update the application code

You need to configure your application code to look for the specific managed identity you created when it's deployed to Azure. In some scenarios, explicitly setting the managed identity for the app also prevents other environment identities from accidentally being detected and used automatically.

  1. On the managed identity overview page, copy the client ID value to your clipboard.

  2. Apply the following language-specific changes:

    Create a DefaultAzureCredentialOptions object and pass it to DefaultAzureCredential. Set the ManagedIdentityClientId property to the client ID.

    DefaultAzureCredential credential = new(
        new DefaultAzureCredentialOptions
        {
            ManagedIdentityClientId = managedIdentityClientId
        });
    
  3. Redeploy your code to Azure after making this change in order for the configuration updates to be applied.

Test the app

After deploying the updated code, browse to your hosted application in the browser. Your app should be able to connect to Cosmos DB successfully. Keep in mind that it may take several minutes for the role assignments to propagate through your Azure environment. Your application is now configured to run both locally and in a production environment without the developers having to manage secrets in the application itself.

Next steps

In this tutorial, you learned how to migrate an application to passwordless connections.

You can read the following resources to explore the concepts discussed in this article in more depth: