I was recently asked how to give access to an existing KeyVault to a managed identity that already have access policies configured. It's not a secret but not all know about this little trick that will enable you to incrementally process permissions to KeyVault over time using ARM templates.


It all started with this article on the best way to reference Managed Identity using ARM templates - there-is-a-new-way-to-reference-managed-identity-in-arm-template/

One of my readers (Sam not to name it :)) reached out with a question I got asked several times over the years. So I decided to write an article about it.

The question was:

Thanks for the article. I'm trying to assign keyvault access policies to the system-assigned identity of my webapp. However in your example a new keyvault is created. How can do that for an existing keyvault ?

My understading with this question is that he wants to update his existing KeyVault without messing with the existing acess policies. The good news is there's a way to do this, let's see how.

Incremental Access Policy update

The way to perform an incremental update of KeyVault AccessPolicies is by using a resource type named Microsoft.KeyVault/vaults/accessPolicies

You have three choice of name for the resource: add, replace or remove. As you can guess they will perform different actions on the access policy you are defining. I used add in the example below but let me summarize them rapidly.

  • add will add a new set of permission or merge them with existing if any exists for the pair objectId and tenantId.

    In the case of add if the principal had the list permission and you call add with the get permission, the end result will be list, get.
  • replace will create or override any existing permission with what is expressed in the template for the pair objectId and tenantId.

    In the case of replace if the principal had list, get permissions and you call replace with the get permission, the end result will be get.
  • delete will delete the access policyfor the pair objectId and tenantId.

Complete example

Here is a complete and functional ARM template that use vaulName, principalIdand optional tenantId parameters to populate add/merge (1) access policy because of the resource name add on KeyVault vaulName.

    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "",
    "parameters": {
        "vaultName": {
            "type": "string"
        "principalId": {
            "type": "string"
        "tenantId": {
            "type": "string",
            "defaultValue": "[subscription().tenantId]"
    "resources": [
            "type": "Microsoft.KeyVault/vaults/accessPolicies",
            "name": "[concat(parameters('vaultName'), '/add')]",
            "apiVersion": "2019-09-01",
            "properties": {
                "accessPolicies": [
                        "tenantId": "[parameters('tenantId')]",
                        "objectId": "[parameters('principalId')]",
                        "permissions": {
                            "keys": ["all"],
                            "secrets": ["all"],
                            "certificates": ["all"],
                            "storage": ["all"]
    "outputs": {

Hope you like this article, and Sam, that it answer your question!

Happy ARM template!