azureazure-keyvaultazure-rm-templateazure-private-link

Link private endpoint connection with Azure Keyvault using ARM template


I have a keyvault already created in Azure and it has secrets, keys, certificates and also two private endpoint connections. I am required to create an ARM template for it (for IAC). I exported the template from automation tab parameterised it but when deploying it fails at- "Change state of Private Endpoint connection". I am trying by changing the name of keyvault.

I believe i need to link those private end points to my keyvault but here in the template specified below I am not doing that, I am not sure.

The main template looks like this :

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "keyVaultName": {
      "type": "String",
      "metadata": {
        "description": "Specifies the name of the key vault."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specifies the Azure location where the key vault should be created."
      }
    },
    "enabledForDeployment": {
      "type": "bool",
      "defaultValue": false,
      "metadata": {
        "description": "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault."
      }
    },
    "enabledForDiskEncryption": {
      "type": "bool",
      "defaultValue": false,
      "metadata": {
        "description": "Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys."
      }
    },
    "enabledForTemplateDeployment": {
      "type": "bool",
      "defaultValue": false,
      "metadata": {
        "description": "Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault."
      }
    },
    "tenantId": {
      "type": "string",
      "defaultValue": "[subscription().tenantId]",
      "metadata": {
        "description": "Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet."
      }
    },
    "pvtEndpointConnKv": {
      "type": "string"
    },
    "pvtEndpointConnVMSS": {
      "type": "string"
    },
    "accessPolicies": {
      "type": "array",
      "metadata": {
        "description": "List of Key Vault's access policies"
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.KeyVault/vaults",
      "apiVersion": "2024-04-01-preview",
      "name": "[parameters('keyVaultName')]",
      "location": "[parameters('location')]",
      "tags": {
        "Created_by": "KeyVaultPOC"
      },
      "properties": {
        "sku": {
          "family": "A",
          "name": "Standard"
        },
        "tenantId": "[parameters('tenantId')]",
        "networkAcls": {
          "bypass": "AzureServices",
          "defaultAction": "Deny",
          "ipRules": [],
          "virtualNetworkRules": []
        },
        "accessPolicies": "[parameters('accessPolicies')]",
        "enabledForDeployment": "[parameters('enabledForDeployment')]",
        "enabledForDiskEncryption": "[parameters('enabledForDiskEncryption')]",
        "enabledForTemplateDeployment": "[parameters('enabledForTemplateDeployment')]",
        "enableSoftDelete": true,
        "softDeleteRetentionInDays": 90,
        "enableRbacAuthorization": false,
        "enablePurgeProtection": true,
        "vaultUri": "[concat('https://', parameters('keyVaultName'), '.vault.azure.net/')]",
        "provisioningState": "Succeeded",
        "publicNetworkAccess": "Disabled"
      }
    },
    {
      "type": "Microsoft.KeyVault/vaults/privateEndpointConnections",
      "apiVersion": "2024-04-01-preview",
      "name": "[concat(parameters('keyVaultName'),'/',parameters('pvtEndpointConnKv'))]",
      "location": "uksouth",
      "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
      ],
      "properties": {
        "provisioningState": "Succeeded",
        "privateEndpoint": {},
        "privateLinkServiceConnectionState": {
          "status": "Approved",
          "actionsRequired": "None"
        }
      }
    },
    {
      "type": "Microsoft.KeyVault/vaults/privateEndpointConnections",
      "apiVersion": "2024-04-01-preview",
      "name": "[concat(parameters('keyVaultName'),'/',parameters('pvtEndpointConnVMSS'))]",
      "location": "uksouth",
      "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
      ],
      "properties": {
        "provisioningState": "Succeeded",
        "privateEndpoint": {},
        "privateLinkServiceConnectionState": {
          "status": "Approved",
          "actionsRequired": "None"
        }
      }
    }
  ]
}

PS: The above template is not working.

I am very new to this field and I might not be aware of what I am doing. Please help me and share your knowledge.

I have tried deploying this file using this command:

az deployment group create 
    --resource-group <resource-group-name> 
    --template-file <path-to-template>.json 
    --parameters <path-to-parameters-file>.json

My keyvault got deployed but when I check in the deployments it is in failed state and the reason given is:

Operation name - Change state of Private Endpoint connection
Error code - ResourceNotFound
Message - The specified resource does not exist. Follow this link for more information: https://go.microsoft.com/fwlink/?linkid=2147446

I am trying to create an ARM template which can deploy a replica of the existing keyvault. When it is succeeded I will use that template in my deploy file and will be using parameter files for deployment.


Solution

  • Link private endpoint connection with Azure Keyvault using ARM template

    The ARM configuration is lacks the correct way of refering the private end point ID to keyvaults which end up failing to provision we need to refer the correct ID of the private endpoint.

    When try the ARM templete from the json of deployment its dependencies and reference might changes as youre approach is reverse now.

    Demo configuration:

    {
          "type": "Microsoft.Network/privateEndpoints",
          "apiVersion": "2023-03-01",
          "name": "[parameters('privateEndpoint1Name')]",
          "location": "[parameters('location')]",
          "dependsOn": [
            "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
          ],
          "properties": {
            "subnet": {
              "id": "[parameters('subnetId1')]"
            },
            "privateLinkServiceConnections": [
              {
                "name": "keyVaultPrivateLink1",
                "properties": {
                  "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]",
                  "groupIds": [
                    "vault"
                  ],
                  "requestMessage": "Requesting connection to Key Vault - Endpoint 1"
                }
              }
            ]
          }
        },
        {
          "type": "Microsoft.Network/privateEndpoints",
          "apiVersion": "2023-03-01",
          "name": "[parameters('privateEndpoint2Name')]",
          "location": "[parameters('location')]",
          "dependsOn": [
            "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
          ],
          "properties": {
            "subnet": {
              "id": "[parameters('subnetId2')]"
            },
            "privateLinkServiceConnections": [
              {
                "name": "keyVaultPrivateLink2",
                "properties": {
                  "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]",
                  "groupIds": [
                    "vault"
                  ],
                  "requestMessage": "Requesting connection to Key Vault - Endpoint 2"
                }
              }
            ]
          }
        }
      ]
    

    In this way you can refer the Private end point to keyvault. you can parameters for secrects and keys in the similar way.

    Deployment:

    enter image description here

    enter image description here

    Refer:

    Microsoft.KeyVault/vaults/privateEndpointConnections - Bicep, ARM template & Terraform AzAPI reference | Microsoft Learn