Monday, January 10, 2022

Configure RBAC for Cosmos DB with Managed Identity instead of Service Principal

Objectives

 

Topology and service components

  • Function App (Read Only and Read/Write)
    • Runtime: Java 11
    • HTTP binding/trigger
  • Cosmos DB Java SDK v4
    • The SDK is used in each Function App to interact with Cosmos DB.

image-3

 

Preparation

 

Function app

 

 

TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();

 

 

Next, we pass the TokenCredential instance to CosmosClientBuilder() to initialize CosmosClient or CosmosAsyncClient. As you can see, we don’t have to use any keys to create a client instance. We can create CosmosClient with the following code. As CosmosClient and CosmosAsyncClient is auto-closable, we should create the client instance surrounded with try-with-resources clause.

CosmosClient client = new CosmosClientBuilder()
    .endpoint(ACCOUNT_ENDPOINT)
    .credential(tokenCredential)
    .gatewayMode()
    .buildClient();
  • GET : retrieve data from Cosmos DB.
  • POST: update or insert data passed in HTTP request body.
// Get data from HTTP body of request
Track track = request.getBody().get();

// Update or insert data
CosmosItemResponse<Track> cosmosItemResponse = cosmosContainer.upsertItem(track);

// HTTP status code is used with response code from Cosmos DB 
HttpResponseMessage responseMessage
  = request.createResponseBuilder(HttpStatusType.custom(cosmosItemResponse.getStatusCode()))
           .header("Content-Type", "application/json")
           .body(track)
           .build();

Cosmos DB

[
  {
    "id": "4321",
    "type": "Hino",
    "purchaseDate": "2020/10/20",
    "remarks": "4t"
  },
  {
    "id": "1234",
    "type": "Isuzu",
    "purchaseDate": "2020/11/20",
    "remarks": "4t"
  },
  {
    "id": "6666",
    "type": "Fuso",
    "purchaseDate": "2020/12/20",
    "remarks": "4t"
  },
  {
    "id": "1111",
    "type": "Volvo",
    "purchaseDate": "2021/09/20",
    "remarks": "4t"
  },
  {
    "id": "1112",
    "type": "Volvo",
    "purchaseDate": "2021/09/20",
    "remarks": "4t"
  },
  {
    "id": "1216",
    "type": "Volvo",
    "purchaseDate": "2021/09/20",
    "remarks": "4t"
  }
]
  • JSON file for read-only role configuration : role-definition-ro.json
{
    "RoleName": "MyReadOnlyRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed"
        ]
    }]
}
  • JSON file for read-write role configuration : role-definition-rw.json
{
    "RoleName": "MyReadWriteRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
        ]
    }]
}
resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
az cosmosdb sql role definition create -a $accountName -g $resourceGroupName -b @role-definition-ro.json
az cosmosdb sql role definition create -a $accountName -g $resourceGroupName -b @role-definition-rw.json
az cosmosdb sql role definition list --account-name $accountName -g $resourceGroupName
[
  {
    "assignableScopes": [
      "/subscriptions/{subscription id}/resourceGroups/{resource group}/providers/Microsoft.DocumentDB/databaseAccounts/{CosmosDB account}"
    ],
    "id": "/subscriptions/{subscription id}/resourceGroups/{resource group}/providers/Microsoft.DocumentDB/databaseAccounts/{CosmosDB account}/sqlRoleDefinitions/{roleDefinitionId}",
    "name": "{roleDefinitionId}",
    "permissions": [
      {
        "dataActions": [
          "Microsoft.DocumentDB/databaseAccounts/readMetadata",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
        ],
        "notDataActions": []
      }
    ],
    "resourceGroup": "{resource group}",
    "roleName": "MyReadWriteRole",
    "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions",
    "typePropertiesType": "1"
  },
  {
    "assignableScopes": [
      "/subscriptions/{subscription id}/resourceGroups/{resource group}/providers/Microsoft.DocumentDB/databaseAccounts/{CosmosDB account}"
    ],
    "id": "/subscriptions/{subscription id}/resourceGroups/{resource group}/providers/Microsoft.DocumentDB/databaseAccounts/{CosmosDB account}/sqlRoleDefinitions/{roleDefinitionId}",
    "name": "{roleDefinitionId}",
    "permissions": [
      {
        "dataActions": [
          "Microsoft.DocumentDB/databaseAccounts/readMetadata",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery",
          "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed"
        ],
        "notDataActions": []
      }
    ],
    "resourceGroup": "{resource group}",
    "roleName": "MyReadOnlyRole",
    "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions",
    "typePropertiesType": "1"
  },
  {...}
]
resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
readOnlyRoleDefinitionId = '<roleDefinitionId of MyReadOnlyRole>'
ROprincipalId = '<Managed Identity Object ID for Function App, the app will be assigned to MyReadOnlyRole.>'
az cosmosdb sql role assignment create -a $accountName -g $resourceGroupName -s "/" -p $ROprincipalId -d $readOnlyRoleDefinitionId
 
readWriteRoleDefinitionId = '<roleDefinitionId of MyReadWriteRole>'
RWprincipalId = '<Managed Identity Object ID for Function App, the app will be assigned to MyReadWriteRole.>'
az cosmosdb sql role assignment create -a $accountName -g $resourceGroupName -s "/" -p $RWprincipalId -d $readWriteRoleDefinitionId

Test

Conclusion

Posted at https://sl.advdat.com/3I8dmE3