Azure ARM templates: Conditionally add an access policy to a Key Vault

As part of the standard template there is an individual Key Vault (these are awesome, especially when being used with .NET Core web apps!). We often find that during development the values that are stored in them for our development environments are constantly in flux. This means having to add permissions to add/update/remove secrets. This is easy enough, but after each deployment of the ARM template by the CD Pipeline these permissions are wiped away, and we have to go and add them again.

The desired outcome for the ARM template is this: an Azure web app is deployed along with a key vault. The key vault has an access policy configured for the web app to be able to access secrets. If the ARM template is running into the testing environment then an additional access policy for the DrDoctor Developers Azure AD group is automatically added.

1. Declare a Key Vault

The following snippet from the azuredeploy.json file (this is the ARM template), defines a key vault, a few things to note:

  • the name and location are coming from a variable
  • dependsOn refers to an azure web app, this is also defined in the same ARM template, and means that the web app will be created prior to the Key Vault
  • accessPolicies already has an entry, this allows the web app to be able to access secrets stored in the Key Vault (this access policy should be set for all environments)
  • the key vault and the web app use the same variable resource_name so they will end up named the same, but obviously be different resource types
{
   "resources":[
      {
         "type":"Microsoft.KeyVault/vaults",
         "apiVersion":"2016-10-01",
         "name":"[variables('resource_name')]",
         "location":"[variables('resource_location')]",
         "dependsOn":[
            "[resourceId('Microsoft.Web/sites', variables('resource_name'))]"
         ],
         "properties":{
            "sku":{
               "family":"A",
               "name":"Standard"
            },
            "tenantId":"[subscription().tenantId]",
            "accessPolicies":[
               {
                  "tenantId":"[reference(resourceId('Microsoft.Web/sites', variables('resource_name')), '2018-11-01', 'Full').identity.tenantId]",
                  "objectId":"[reference(resourceId('Microsoft.Web/sites', variables('resource_name')), '2018-11-01', 'Full').identity.principalId]",
                  "permissions":{
                     "keys":[],
                     "secrets":["Get", "List"],
                     "certificates":[]
                  }
               }
            ],
            "enabledForDeployment":false,
            "enabledForDiskEncryption":false,
            "enabledForTemplateDeployment":true,
            "enableSoftDelete":true
         }
      }
   ]
}

2. Define the add access policy

The following snippet of the azuredeploy.json file shows how to define an add access policy for the above Key Vault. This snipped of json is a child resource of the above key vault resource. It is in this snippet that a condition can be defined.

There are a few key things to note:

  • The name is made up of the key vault name (which is defined in a variable) and /add
  • The type is Microsoft.KeyVault/vaults/accessPolicies
  • dependsOn is the name of the key vault that we want to add this access policy to
  • condition is an expression which the ARM template evaluates to decided if it should deploy this resource or not
{
   "resources":[
      {
         "name":"[concat(variables('resource_name'), '/add')]",
         "type":"Microsoft.KeyVault/vaults/accessPolicies",
         "apiVersion":"2019-09-01",
         "condition":"[startsWith(parameters('environmentName'), 'uat')]",
         "dependsOn":[
            "[resourceId('Microsoft.KeyVault/vaults', variables('resource_name'))]"
         ],
         "properties":{
            "accessPolicies":[
               {
                  "tenantId":"[reference(resourceId('Microsoft.Web/sites', variables('resource_name')), '2018-11-01', 'Full').identity.tenantId]",
                  "objectId":"[variables('drdoctor_developers_group_id')]",
                  "permissions":{
                     "keys":[],
                     "secrets":["Get","List","Set"],
                     "certificates":[]
                  }
               }
            ]
         }
      }
   ]
}

With this in place when the ARM template is run in the test environment the access policy for the drdoctor_developers_group_id Azure AD group is created, but when the same ARM template is run in the subsequent QA or production environments it isn’t added.

Leave a comment