Azure ARM Template - accessing a resource Id created by one ARM template in another ARM template

Jaya picture Jaya · Jul 29, 2016 · Viewed 11.8k times · Source

We deploy azure resources using an ARM template as part of our build process before deploying the actual application.

So far all our application resources are self contained within a resource group. e.g. A web app that requires a sql server and a storage account are clubbed into one resource group.

However we have come across a scenario/need where we need to share a resource eg. storage account across resource groups. Resource Group A has the storage account and Resource Group B's web app requires the connection string/app keys pertaining to the storage account in its appconfig.json/web.config.

Question

How do I build the connection string for the app in resource group B to connect to a resource in resource group A as I need to obtain the Id of the resource group A in B

Here is how i build the connection string if they are in the same resource group

  "variables"
{
  "storageAccounts_id": "[concat(**resourceGroupA**().id,'/providers/Microsoft.Storage/storageAccounts/', variables('storageAccntName'))]",
},
"resources": [
    {
      "apiVersion": "2015-08-01",
      "type": "config",
      "name": "connectionstrings",
      "dependsOn": [
        "[resourceId('Microsoft.Web/sites', variables('MyWebSiteName'))]"
      ],
      "properties": {
      "AzureWebJobsDashboard": {
        "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccntName'),';AccountKey=',concat(listKeys(variables('storageAccounts_id'),'2015-05-01-preview').key1))]",
        "type": "Custom"
      },
      }
    }
  ]

Notes: I did go through this site https://azure.microsoft.com/en-us/documentation/articles/resource-group-linked-templates/ about linked templates, but it does not suit our current build process which uses Octo (unless there is something I may be missing) which deployes the ARM first then the application (web).

Answer

MPavlak picture MPavlak · Oct 27, 2017

For this scenario where the storage account name is known and does not depend on the resource group (eg, uniqueString(resourceGroup().id)), then you can simply use the longer form for resourceId(). The full form looks like:

resourceId([subscriptionId], [resourceGroupName], resourceType, resourceName1, [resourceName2]...)

so we can optionally supply subscriptionId and resourceGroupName.

listKeys(resourceId(parameters('ResourceGroupAName'), 'Microsoft.Storage/storageAccounts', variables('ccPaymentStorageName'))

If it was in a different subscription, you could also specify the subscription.

listKeys(resourceId(parameters('SubscriptionId'), parameters('ResourceGroupAName'), 'Microsoft.Storage/storageAccounts', variables('ccPaymentStorageName'))

If your storage account name depends on the resource group like

"storageName": "[concat('mystorage', uniqueString(resourceGroup().id))]" // in Resource Group A

then you'll either need to always run the template that creates this account and output the storageName and the resourceGroup or find a way to reference the other resource group to get it's id so that the name can be re-created.

I have been able to use something like this to "re-create" the resource group id so I can generate the proper name of the storage account.

"otherResourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('ResourceGroupName'))]"

Then I can use that to generate the name appropriately:

"storageAccountName": "[concat('mystorage', uniqueString(variables('otherResourceGroupId')))]"