Wanted: Sample Bicep Script to grant App Service Web App System Service Principal access to Cosmos DB

Siegfried Heintze 1,851 Reputation points
2022-04-04T20:43:27.183+00:00

Presently I'm storing the end point and account key in environment variables for my C# web app running in the Azure App Service.

(1) How do I write a bicep script to grant my App Service's web app system service principal access to my cosmos db partitions?
(2) Assuming I have the above bicep script working, how would my C# connect to the cosmos db? Would I use a connection string instead of the enpoint/accountkeys?
(3) Would I need to store the connection string in the key vault? If so, would I still need to grant my service principal access to my cosmos dB?

Thanks
Siegfried

Monday Evening Update:
I found this blog called partly cloudy that has an associated github project. It looks like he recreates the database each time he deploys via bicep. This sounds like a ridiculous constraint because it is common to have many projects sharing a database... Is it possible to use bicep to to configure access to an existing database? Or, more specifically: can I figure a new service principal (for a webapp or kubernetes cluster) to have access to an existing database?

2022 April 13 Evening Update:
Ah hah! I can answer my question above. I think I can use the "existing" key word in the bicep language. I have not tried it yet, however.

My application needs to be granted read/write access to the cosmos database and read access to the key vault secret.

As explained my reply below, previously I was creating a managed entity and passing this into the bicep script as suggested by the partly cloudy blog (see link above). This managed entity was also a user assigned identity for the App Service Web app. I am granting this same managed identity access to the key vault. However, it is failing to fetch the secret from the key vault when running as a web app in Azure.

Instead of creating a RBAC for this managed identity, I would like to instead create RBAC for the system assigned identity of the Azure App Service Web App. I am creating the web app in the same bicep script... However, I get this error when defining the role definition:

   Error BCP120: This expression is being used in an assignment to the "name" property of the "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions" type, which requires a value that can be calculated at the start of the deployment. You are referencing a variable which cannot be calculated at the start ("roleDefId" -> "web"). Properties of web which can be calculated at the start include "apiVersion", "id", "name", "type".  

So how do I allow a web app system service principal to have read/write access to a cosmos database?

2022 Apr 16 Sat Morning Update:

Previously I was only granting the user assigned managed identity for the App Service Web app (the principalId in your bicep script as created in the with the powershell command in the Partly Cloudy blog in the above link) access to the key vault (to fetch the AAD client secret) and my blazor server app would die immediately after deployment to azure. Now I am granting both the system assigned and the user assigned managed identity for the web app access to the key vault and I can now log in when deployed to azure. Hurray! This makes me think that assigning the user assigned managed identity to the web app has no affect! I tried to apply the RBAC to the system assigned identity but bicep complains that this is not possible because it is a computed value. So now I can deploy to azure app service and log in but I still cannot access the cosmos db.

Also: I finally started to type in your code but discovered it was identical (almost) to the RBAC bicep code in the partly cloudy blog. The only differences were syntactic.

Lastly: when using your (& CDennig's) bicep code originally, I was not assigning the RBAC to my azure account... only to the managed identity. I am now creating role definitions and role assignments assignments for both the managed identity and my personal azure account and when running my blazor app on my development machine I can now log in and write to the cosmos database... So we now know that the RBAC code is working...

Please help me resolve these mysteries:

(1) How do I see these RBAC role assignments in the azure portal? How do I use the portal to manually add a custom role assignment to a managed identity?

(2) Why is azure ignoring the user assigned managed identity assigned the web app?

(3) How do I create RBAC role assignments for the system assigned identity for the azure web app?

2022 Apr 17 Evening update:

Using powershell commands I was able to grant the RBAC to the system assigned service principal for the App Service Web App. I could not see these roles or role assignments in the portal (why not?) but they worked. So user assigned service principals for App Service Web Apps are not working for key vault access or RBAC for cosmos! Is this bug? Please help me fix my bicep script to add cosmos RBAC to my system assigned service principal.

2022 May 5 Thu Update:

I have created an azure support incident for this issue and I have noticed I don't have an obvious link to my code:
I forked from Azure Active Directory B2C Blazer sample. Here is the source code: If you extract the script from the embedded comments in deploy.bicep they will run... However, I had to hard code the random name generated by bicep and after deploying via bicep I have to (see the comments) use powershell to grant access to the cosmos db.

Ryan has been helping me with a different approach but we are having trouble with the LinuxFxVersion.

I have lots of questions such has why does not CDennig's approach (see link above) of granting a user assigned service principal access to the cosmos db work? What is the difference between Ryan's access rights and CDennig's access rights?

Thanks

Azure Key Vault
Azure Key Vault
An Azure service that is used to manage and protect cryptographic keys and other secrets used by cloud apps and services.
1,083 questions
Azure Cosmos DB
Azure Cosmos DB
An Azure NoSQL database service for app development.
1,401 questions
Azure App Service
Azure App Service
Azure App Service is a service used to create and deploy scalable, mission-critical web apps.
6,689 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Oury Ba-MSFT 15,821 Reputation points Microsoft Employee
    2022-04-05T23:30:17.16+00:00

    Hi @Siegfried Heintze Thank you for your query

    I want to make sure I understand completely but your end goal is to store the connection string in the key vault and need to grant your service principal access to my cosmos db.
    Your prior question was about how to write a bicep script to grant my App Service's web app system service principal access to my cosmos db partitions. Please let me know if my understanding is not correct.

    (1) Please also confirm which cosmos db API you are using (this is for SQL API). You can also find for other APIs in this [Documentation][1]

    (2) In my understanding for question 2 the ask is how you would connect the bicep script to your cosmos db. Please let me know if that is not the ask.
    There are many ways to deploy Azure Bicep files including, [Azure CLI][3], Azure PowerShell and Cloud Shell.

    It’s advisable to store connection strings in key vault but it’s not necessary. But it is best to grant access to cosmos or any other service for that matter via service principal.

    @description('Application Name')
    @maxLength(30)
    param applicationName string = 'todo-app-${uniqueString(resourceGroup().id)}'
    @description('Location for all resources.')
    param location string = resourceGroup().location
    @allowed([
    'F1'
    'D1'
    'B1'
    'B2'
    'B3'
    'S1'
    'S2'
    'S3'
    'P1'
    'P2'
    'P3'
    'P4'
    ])
    @description('App Service Plan\'s pricing tier. Details at https://azure.microsoft.com/en-us/pricing/details/app-service/')
    param appServicePlanTier string = 'F1'
    @minValue(1)
    @maxValue(3)
    @description('App Service Plan\'s instance count')
    param appServicePlanInstances int = 1
    @description('The URL for the GitHub repository that contains the project to deploy.')
    param repositoryUrl string = 'https://github.com/Azure-Samples/cosmos-dotnet-core-todo-app.git'
    @description('The branch of the GitHub repository to use.')
    param branch string = 'main'
    @description('The Cosmos DB database name.')
    param databaseName string = 'Tasks'
    @description('The Cosmos DB container name.')
    param containerName string = 'Items'
    var cosmosAccountName = toLower(applicationName)
    var websiteName = applicationName
    var hostingPlanName = applicationName
    var keyvaultName = applicationName
    // Use built-in roles https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide?tabs=azure-cli#azure-built-in-roles-for-key-vault-data-plane-operations
    var keyVaultSecretsUserRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
    resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2021-04-15' = {
    name: cosmosAccountName
    kind: 'GlobalDocumentDB'
    location: location
    properties: {
    consistencyPolicy: {
    defaultConsistencyLevel: 'Session'
    }
    locations: [
    {
    locationName: location
    failoverPriority: 0
    isZoneRedundant: false
    }
    ]
    databaseAccountOfferType: 'Standard'
    }
    }
    resource kv 'Microsoft.KeyVault/vaults@2019-09-01' = {
    // Make sure the Key Vault name begins with a letter.
    name: keyvaultName
    location: location
    properties: {
    sku: {
    family: 'A'
    name: 'standard'
    }
    tenantId: subscription().tenantId
    enableRbacAuthorization: true
    enabledForDeployment: false
    enabledForDiskEncryption: true
    enabledForTemplateDeployment: false
    }
    resource cosmosDbAccountSecret 'secrets' = {
    name: 'CosmosDbAccount'
    properties: {
    value: cosmosAccount.properties.documentEndpoint
    }
    }
    resource cosmostDbKeySecret 'secrets' = {
    name: 'CosmostDbKey'
    properties: {
    value: cosmosAccount.listKeys().primaryMasterKey
    }
    }
    }
    resource hostingPlan 'Microsoft.Web/serverfarms@2020-06-01' = {
    name: hostingPlanName
    location: location
    sku: {
    name: appServicePlanTier
    capacity: appServicePlanInstances
    }
    }
    resource website 'Microsoft.Web/sites@2020-06-01' = {
    name: websiteName
    location: location
    identity: {
    type: 'SystemAssigned'
    }
    properties: {
    serverFarmId: hostingPlan.id
    siteConfig: {
    appSettings: [
    {
    name: 'CosmosDb:Account'
    value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::cosmosDbAccountSecret.name})'
    }
    {
    name: 'CosmosDb:Key'
    value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::cosmostDbKeySecret.name})'
    }
    {
    name: 'CosmosDb:DatabaseName'
    value: databaseName
    }
    {
    name: 'CosmosDb:ContainerName'
    value: containerName
    }
    ]
    }
    }
    }
    resource kvWebsitePermissions 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = {
    name: guid(kv.id, website.name, keyVaultSecretsUserRole)
    scope: kv
    properties: {
    principalId: website.identity.principalId
    principalType: 'ServicePrincipal'
    roleDefinitionId: keyVaultSecretsUserRole
    }
    }
    resource srcControls 'Microsoft.Web/sites/sourcecontrols@2020-06-01' = {
    name: '${website.name}/web'
    properties: {
    repoUrl: repositoryUrl
    branch: branch
    isManualIntegration: true
    }
    }

    Please feel free to reach if you have any further queries or have any doubt regarding the above questions.

    Regards,
    Oury

    [1]: https://learn.microsoft.com/en-us/azure/cosmos-db/sql/manage-with-bicep [3]: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-cli


  2. Ryan Hill 25,216 Reputation points Microsoft Employee
    2022-04-20T03:52:43.723+00:00

    Hi @Siegfried Heintze hope all is well. Oury and I were able to determine the following main.bicep that should help shed some light. This file will create an app service from a GitHub repo (connected through Deployment Center), a key vault, and cosmos db. The app service app settings will pull the cosmos db connection from Key Vault. The Key Vault itself is configured to use RBAC role which is used for the permission on behalf of the app service managed service identity.

    We were working on the other approach which would be to use access policies but having difficulties getting around a cyclic reference between key vault and the app service.