3
votes

Below I have a (simplified) Azure ARM Template to deploy a website which has in its appSettings the storage account. I originally passed the key via a string output parameter which works fine.

Storage Template

"outputs": {
    "storageKey": {
        "type": "string",
        "value": "[listKeys(resourceid(resourceGroup().name, 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value]"
    }
}

Root template

{
    "apiVersion": "[variables('apiVersion')]",
    "type": "Microsoft.Resources/deployments",
    "name": "[concat(resourceGroup().Name, '-', variables('tdfConfiguration')[copyIndex()]['roleName'], '-storage')]",
    "copy": {
        "name": "storageCopy",
        "count": "[length(variables('tdfConfiguration'))]"
    },
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('storageAccountTemplateUri')]",
            "contentVersion": "1.0.0.0"
        },
        "parameters": {
            "storageAccountName": { "value": "[variables('tdfConfiguration')[copyIndex()]['componentName']]" },
            "storageAccountLocation": { "value": "[resourceGroup().location]" },
            "storageAccountType": { "value": "[variables('storageAccountType')]" }
        }
    }
},

{
    "apiVersion": "[variables('apiVersion')]",
    "type": "Microsoft.Resources/deployments",
    "name": "[concat(resourceGroup().Name, '-', variables('tdfConfiguration')[copyIndex()]['roleName'], '-website')]",
    "copy": {
        "name": "webSiteCopy",
        "count": "[length(variables('tdfConfiguration'))]"
    },
    "dependsOn": [
        "[concat('Microsoft.Resources/deployments/', resourceGroup().Name, '-', variables('tdfConfiguration')[copyIndex()]['roleName'], '-serviceplan')]",
        "[concat('Microsoft.Resources/deployments/', resourceGroup().Name, '-', variables('tdfConfiguration')[copyIndex()]['roleName'], '-storage')]"
    ],
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('webSiteTemplateUri')]",
            "contentVersion": "1.0.0.0"
        },
        "parameters": {
            "azureWebJobsStorageAccountKey": { "value": "[reference(concat(resourceGroup().Name, '-', variables('tdfConfiguration')[copyIndex()]['roleName'], '-storage')).outputs.storageKey.value]" }

        }
    }
},

I'm worried that passing that around as a string may expose it in some deployment logs. However if I switch it to a securestring output parameter I can no longer access the value. So it seems like I need to listkeys in the root template, but if I change my website parameters to

  "azureWebJobsStorageAccountKey": { "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts',variables('tdfConfiguration')[copyIndex()]['componentName']), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value]" }

it fails because even though the storage account is listed as a dependsOn, it attempts to resolve this value immediately without waiting for the storage account to be deployed. Any ideas?

1

1 Answers

3
votes

list* functions will wait for the resource to be available if it is being created in the same template. but you are using nested templates so it has no way of knowing the resource is provisioned or not, so it just assumes its provisioned (standard behavior when you use list* functions).

dont pass it in as a value (it makes no sense really), just use the same expression inside the deployment and it will work. because the deployment will start only after the previous deployment was finished and the storage account will be there already.

Also, I dont see why you are doing this with nested templates, I dont see any reason for doing this in your case, you are over complicating your deployment\code for no benefit (and even created a problem for yourself because of that). Just drop nested deployments and use resources.