Search code examples
connection-stringazure-keyvaultazure-rm-template

How to set a connection string for web app in arm template that references a keyvault?


I am building an arm template that deploys a web app, sql database and a key vault.

The web app will be deployed with

1- System identity (which will be used to access the keyvault).

2- Connection string to the sql database that would be using the keyvault access way:

@Microsoft.KeyVault(SecretUri=https://', parameters('keyVaultName'),'.vault.azure.net/secrets/connectionString)')

The keyvault will be deployed with

1 - Access policy for the webapp above.

2 - Secret that contains the connection string (constructed in the pipeline while deploying).

The webapp needs to be deployed before the keyvault, so when the keyvault is deployed, it can find the webapp identity so it creates the access policy for it.

But the issue I am having with this approach is that when the connection string added as part of the webapp, the keyvault doesn't exist yet, so that @Microsoft.KeyVault way of accessing the secret doesn't work, even after the keyvault is deployed, and I get the below

enter image description here

But if I remove the connection string and add it manually after the deployment, keeping the exact same value, it works. enter image description here

How can I deploy the connection string containing the keyvault access way where the webapp is happy and can access the connection string in it?

I think the problem is clear and no need to include the template, but if you do need to look please leave a comment and will add to the question.

EDIT Template


Solution

  • You can use depends on condition on keyvault . I created a Keyvault first and added

    "dependsOn": [
                "[resourceId('Microsoft.Web/sites', parameters('appBaseName'))]"
    

    while setting the access policies.

    So the complete template will be :

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "appBaseName": {
          "type": "string"
        },
        "sqlName": {
          "type": "string"
        },
        "adminLogin": {
          "type": "string"
        },
        "secretValue": {
          "type": "securestring"
        },
        "adminPassword": {
          "type": "securestring"
        },
        "appInsights": {
          "type": "string"
        },
        "collation": {
          "type": "string",
          "defaultValue": "Arabic_CI_AS"
        },
        "edition": {
          "type": "string",
          "defaultValue": "Basic"
        },
        "secretsPermissions": {
          "type": "array",
          "defaultValue": [
            "get",
            "list"
          ]
        },
        "objectiveName": {
          "type": "string",
          "defaultValue": "Basic"
        },
        "keyVaultName": {
          "type": "string"
        }
      },
      "resources": [
            {      
          "type": "Microsoft.KeyVault/vaults",
          "apiVersion": "2019-09-01",
          "name": "[parameters('keyVaultName')]",
          "location": "[resourceGroup().location]",
          "properties": {
            "enabledForDeployment": false,
            "enabledForDiskEncryption": false,
            "enabledForTemplateDeployment": false,
            "tenantId": "[subscription().tenantId]",
            "accessPolicies": [
              {
                "objectId": "[reference(concat('Microsoft.Web/sites/', parameters('appBaseName')), '2018-11-01','Full').identity.principalId]",
                "tenantId": "[subscription().tenantId]",
                "permissions": {
                "secrets": "[parameters('secretsPermissions')]"
                },
              "dependsOn": [
                "[resourceId('Microsoft.Web/sites', parameters('appBaseName'))]"
              ]
              }
            ],
            "sku": {
              "name": "Standard",
              "family": "A"
            },
            "networkAcls": {
              "bypass": "AzureServices",
              "defaultAction": "Allow"
            }
          }
        },
        {
          "type": "Microsoft.KeyVault/vaults/secrets",
          "apiVersion": "2019-09-01",
          "name": "[concat(parameters('keyVaultName'), '/', 'connectionString')]",
          "location": "[resourceGroup().location]",
          "dependsOn": [
            "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
          ],
          "properties": {
            "value": "[parameters('secretValue')]"
          }
        },
        {
          "name": "[parameters('appInsights')]",
          "type": "microsoft.insights/components",
          "location": "[resourceGroup().location]",
          "apiVersion": "2020-02-02",
          "kind": "web",
          "properties": {
            "ApplicationId": "[parameters('appInsights')]",
            "Application_Type": "web",
            "Flow_Type": "Bluefield",
            "Request_Source": "rest"
          }
        },
        {
          "name": "[parameters('appBaseName')]",
          "type": "Microsoft.Web/serverfarms",
          "location": "[resourceGroup().location]",
          "apiVersion": "2015-08-01",
          "sku": {
            "name": "F1"
          },
          "dependsOn": [],
          "tags": {
            "displayName": "appBaseName"
          },
          "properties": {
            "name": "[parameters('appBaseName')]",
            "numberOfWorkers": 1
          }
        },
        {
          "name": "[parameters('appBaseName')]",
          "type": "Microsoft.Web/sites",
          "location": "[resourceGroup().location]",
          "apiVersion": "2015-08-01",
          "identity": { "type": "SystemAssigned" },
          "dependsOn": [
            "[resourceId('Microsoft.Web/serverfarms', parameters('appBaseName'))]",
            "[resourceId('microsoft.insights/components', parameters('appInsights'))]"
          ],
          "tags": {
            "[concat('hidden-related:', resourceId('Microsoft.Web/serverfarms', parameters('appBaseName')))]": "Resource",
            "displayName": "appBaseName"
          },
          "properties": {
            "name": "[parameters('appBaseName')]",
            "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appBaseName'))]",
            "siteConfig": {
              "location": "[resourceGroup().location]",
              "appSettings" : [
                {
                  "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
                  "value": "[reference(concat('microsoft.insights/components/', parameters('appInsights')), '2015-05-01').InstrumentationKey]"
                }],
                "connectionStrings": [
                {
                  "name": "connectionString",
                  "connectionString": "[concat('@Microsoft.KeyVault(SecretUri=https://', parameters('keyVaultName'),'.vault.azure.net/secrets/connectionString)')]",
                  "type": 1
                }
              ]
            }
          }
        },
        {
          "name": "[parameters('sqlName')]",
          "type": "Microsoft.Sql/servers",
          "location": "[resourceGroup().location]",
          "apiVersion": "2014-04-01",
          "dependsOn": [],
          "properties": {
            "administratorLogin": "[parameters('adminLogin')]",
            "administratorLoginPassword": "[parameters('adminPassword')]"
          },
          "resources": [
            {
              "name": "AllowAllWindowsAzureIps",
              "type": "firewallRules",
              "location": "[resourceGroup().location]",
              "apiVersion": "2014-04-01",
              "dependsOn": [
                "[resourceId('Microsoft.Sql/servers', parameters('sqlName'))]"
              ],
              "properties": {
                "startIpAddress": "0.0.0.0",
                "endIpAddress": "0.0.0.0"
              }
            },
            {
              "name": "[parameters('sqlName')]",
              "type": "databases",
              "location": "[resourceGroup().location]",
              "apiVersion": "2014-04-01",
              "dependsOn": [
                "[resourceId('Microsoft.Sql/servers', parameters('sqlName'))]"
              ],
              "properties": {
                "collation": "[parameters('collation')]",
                "edition": "[parameters('edition')]",
                "maxSizeBytes": "1073741824",
                "requestedServiceObjectiveName": "[parameters('objectiveName')]"
              }
            }
          ]
        }
      ],
    "outputs": {}
    }
    

    Output:

    (Successfully deployed)

    enter image description here

    enter image description here

    (Keyvault reference is properly set)

    enter image description here

    (Vault Access Policy is properly set as well)

    enter image description here