DEV Community

Cover image for Bicep, Keyvault & AppService
Massimo Bonanni
Massimo Bonanni

Posted on

Bicep, Keyvault & AppService

In this post I would like to show you how create an AppService with its configuration stored in a KeyVault using Bicep template.
In the next steps we make these tasks:

  1. create an AppService with its AppServicePlan;

  2. assign a managed identity to the AppService;

  3. create a KeyVault;

  4. assign the role "Key Vault Secrets User" to the AppService identity;

  5. create a secret in the KeyVault;

  6. add an app setting to the AppService with the KeyVault secret reference.

Create AppService and managed identity

The following snippet of Bicep allow you to create an AppService, its AppServicePlan, and assign a system assigned managed identity.

var location ='northeurope'

resource appService 'Microsoft.Web/sites@2021-01-01' = {
  name: appName
  location: location
  kind: 'app'
  properties: {
    enabled: true
    serverFarmId: appServicePlan.id
  }
  identity:{
     type: 'SystemAssigned'
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2021-01-01' = {
  name: appPlanName
  location: location
  sku: {
    name: 'F1'
    tier: 'Free'
    size: 'F1'
    family: 'F'
    capacity: 0
  }
}
Enter fullscreen mode Exit fullscreen mode

In the previous snippet, appName and appPlanName are the names you want to assign to AppService and to AppServicePlan (probably, in your template, are parameters or variable generated starting from other parameters).

Create KeyVault

The following snippet is the KeyVault declaration:

resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = {
  name: keyVaultName
  location: location
  properties: {
    accessPolicies: []
    enableRbacAuthorization: true
    enableSoftDelete: false
    enabledForDeployment: false
    enabledForDiskEncryption: false
    enabledForTemplateDeployment: false
    tenantId: subscription().tenantId
    sku: {
      name: 'standard'
      family: 'A'
    }
    networkAcls: {
      defaultAction: 'Allow'
      bypass: 'AzureServices'
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In the previous snippet, keyVaultName is the name of your KeyVault resource.

Assign the role "Key Vault Secrets User" to the AppService

If we want to use secret references in the AppService settings, we need to give to the AppService the right role to access to the keyVault's secrets.
The role we are looking for is the "Key Vault Secrets User" role.
Unfortunately, the role name is not enough to assign it to the AppService but we need its name (it is a GUID).
To find the right GUID to use in the assignment, we can use the following az command:

az role definition list --name 'Key Vault Secrets User'
Enter fullscreen mode Exit fullscreen mode

The command result is something like this:

[
  {
    "assignableScopes": [
      "/"
    ],
    "description": "Read secret contents. Only works for key vaults that use the 'Azure role-based access control' permission model.",
    "id": "/subscriptions/b68ed859-8021-4876-8179-8dc97208bc2c/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
    "name": "4633458b-17de-408a-b874-0445c86b69e6",
    "permissions": [
      {
        "actions": [],
        "dataActions": [
          "Microsoft.KeyVault/vaults/secrets/getSecret/action",
          "Microsoft.KeyVault/vaults/secrets/readMetadata/action"
        ],
        "notActions": [],
        "notDataActions": []
      }
    ],
    "roleName": "Key Vault Secrets User",
    "roleType": "BuiltInRole",
    "type": "Microsoft.Authorization/roleDefinitions"
  }
]
Enter fullscreen mode Exit fullscreen mode

We need to copy value of the name property (4633458b-17de-408a-b874-0445c86b69e6).
Using this value, we can assign the role to the AppService using the following Bicep snippet.

var roleId='4633458b-17de-408a-b874-0445c86b69e6'

resource appServiceKeyVaultAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: '${appService.name} Key Vault Secret User ${uniqueString(resourceGroup().id,appService.name)}'
  scope: keyVault
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId) // this is the role "Key Vault Secrets User"
    principalId: appService.identity.principalId
    principalType: 'ServicePrincipal'
  }
}
Enter fullscreen mode Exit fullscreen mode

We generate the name of the assignment concatenating the name of the AppService, the role name and a unique string (we use the string function uniqueString to be sure that the assignment name is unique).
To set the roleDefinitionId property, we need to retrieve the unique identifier for that resource, and we can use the subscriptionResourceId function.
To have more info about Bicep functions, I suggest to read this article.

Create a secret in the KeyVault

The following snippet allow us to create a secret in the KeyVault.

resource myKeyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
  name: 'mySecret'
  parent: keyVault
  properties: {
    attributes: {
      enabled: true
    }
    value: 'this is the secret'
  }
}
Enter fullscreen mode Exit fullscreen mode

The secret is an inner resource of the KeyVault, so you can use the parent keyword (as in the previous snippet) or adding the secret resource in the KeyVault definition. You can find all the different way to declare an inner resource reading this article.

Add the secret reference in the AppService settings

The following snipper allow you to create the whole app setting section inside the AppService resource:

resource appSettings 'Microsoft.Web/sites/config@2022-03-01' = {
  name: 'appsettings'
  parent: appService
  properties: {
    AppSecret: '@Microsoft.KeyVault(SecretUri=${myKeyVaultSecret.properties.secretUri})'
    }
  dependsOn:[
    appServiceKeyVaultAssignment
  ]
}
Enter fullscreen mode Exit fullscreen mode

The snippet creates a single key (named AppSecret) in the AppService settings section.

In this case, even if you can use several ways to declare an inner resource, the best way is using the parent keyword because you need to wait the AppService creation (for the managed identity), the role assignment (otherwise you receive an error while you create the settings) and the KeyVault secret.
The parent keyword tell bicep that your appsettings must create after the AppService, the myKeyVaultSecret reference tells bicep to wait for the secret creation but you need to force to wait the role assignment creation using the dependsOn keyword.
If you put the appSettings definition inside the AppService resource definition, they are created at the same time the ARM creates the AppService and then you receive an error (just because the AppService hasn't the right role yet).

Top comments (1)

Collapse
 
pythonyan profile image
Tony Pierascenzi

Great article, Max.