DEV Community

Cover image for Deliver ARM templates at speed using Template Specs in Azure
Saurabh Shivgunde
Saurabh Shivgunde

Posted on • Updated on

Deliver ARM templates at speed using Template Specs in Azure

A template spec is used to store your Azure Resource Manager (ARM) templates securely in Azure environment. Microsoft.Resources/templateSpecs is the resource type for template specs.

Using template specs you can share ARM templates with users in your organization. They also support versioning which we will see later in this post.

Why to use template specs?

Suppose you are working on Infrastructure development using ARM templates in your organization. There are several issues when trying to share these templates with other teams. If the templates are stored in a repository or storage account, users won't be able to access it unless they have required permissions. Even if permission is granted users will deploy using their own local version of templates which can eventually become outdated as you keep on updating the template.

Template Specs in Azure are protected by Azure Role-Based Access Control (RBAC). So you can securely store the templates in a resource group and control access using RBAC in Azure itself. When the reference architectures in your organization change over time, you can update the template specs with newer versions.

Create a new template spec with linked template

When you create a template spec, you just pass the main template file to the CLI commands. If there are linked templates referenced inside the main template file, those will be packaged together with the main template in a single template spec resource.

Create a main template named azuredeploy.json with the following JSON in your working directory:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "appServicePlanName": {
            "type": "string",
            "metadata": {
                "description": "Enter a name for app service plan"
            }
        },
        "appServiceName": {
            "type": "string",
            "metadata": {
                "description": "Enter a name for app service"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [
    {
        "name": "webappDeployment",
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2020-06-01",
        "properties": {
            "mode": "Incremental",
            "templateLink": {
                "relativePath": "artifacts/webapp.json"
            },
            "parameters": {
                "appServicePlanName": {
                    "value": "[parameters('appServicePlanName')]"
                },
                "appServiceName": {
                    "value": "[parameters('appServiceName')]"
                }
            }
        }
    }
    ],
    "outputs": {}
}
Enter fullscreen mode Exit fullscreen mode

Note the deployment resource in above template references a linked template webapp.json. We will create this linked template next.

In your working directory create a new directory named artifacts and create a template named webapp.json inside the directory with the following JSON:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "appServicePlanName": {
            "type": "string",
            "metadata": {
                "description": "Name of app service plan"
            }
        },
        "appServiceName": {
            "type": "string",
            "metadata": {
                "description": "Name of app service"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [
        {
            "name": "[parameters('appServicePlanName')]",
            "type": "Microsoft.Web/serverfarms",
            "apiVersion": "2019-08-01",
            "kind": "app",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "S1"
            }
        },
        {
            "name": "[parameters('appServiceName')]",
            "type": "Microsoft.Web/sites",
            "apiVersion": "2019-08-01",
            "kind": "app",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]"
            ],
            "properties": {
                "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlan1')]"
            }
        }
    ],
    "outputs": {}
}
Enter fullscreen mode Exit fullscreen mode

Deploy the template spec

To deploy the template spec, you can use various Azure tools like PowerShell, Azure CLI, Azure portal, REST, and other supported SDKs and clients. We will use Powershell to deploy our template spec.

Open a Powershell terminal in your working directory and run the following Powershell cmdlets to create a new resource group:

$rg = "TemplateSpecsRG"

New-AzResourceGroup `
  -Name $rg `
  -Location eastus
Enter fullscreen mode Exit fullscreen mode

Then run the New-AzTemplateSpec cmdlet to create a new template spec based on the above templates:

New-AzTemplateSpec `
  -Name webappSpec `
  -Version "1.0" `
  -ResourceGroupName $rg `
  -Location eastus `
  -TemplateFile "azuredeploy.json"
Enter fullscreen mode Exit fullscreen mode

When the cmdlet executes successfully, you can view the deployed spec using Get-AzTemplateSpec cmdlet:

> Get-AzTemplateSpec -ResourceGroupName $rg -Name webappSpec


Id                    : /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/TemplateSpecsRG/providers/Microsoft.Resou
                        rces/templateSpecs/webappSpec
Name                  : webappSpec
ResourceGroupName     : TemplateSpecsRG
SubscriptionId        : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Location              : eastus
Versions              : 1.0
CreationTime(UTC)     : 2/17/2021 5:42:57 AM
LastModifiedTime(UTC) : 2/17/2021 5:43:02 AM
Enter fullscreen mode Exit fullscreen mode

In the portal too, you can navigate to the resource group and view the template spec resource:

Template Spec resource in the portal

When you go to the template spec resource screen, you can find that it contains a main template and the linked template that we deployed. Note that the version you entered is also displayed as Latest Version.

Alt Text

You can also drill down on the templates and see the content in the portal itself.

Modify the template spec

Now suppose the architecture gets updated and a new storage account needs to be added along with the web app. We will modify the existing template spec to add a new storage account as a linked template.

Modify the azuredeploy.json file and add a new deployment resource. The modified template should like as below:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "appServicePlanName": {
            "type": "string",
            "metadata": {
                "description": "Enter a name for app service plan"
            }
        },
        "appServiceName": {
            "type": "string",
            "metadata": {
                "description": "Enter a name for app service"
            }
        },
        "storageAccountName": {
            "type": "string",
            "metadata": {
                "description": "Enter a name for storage account"
            }
        },
        "storageAccountType": {
            "type": "string",
            "defaultValue": "Standard_LRS",
            "metadata": {
                "description": "Specify the storage account type"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [
        {
            "name": "webappDeployment",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2020-06-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "relativePath": "artifacts/webapp.json"
                },
                "parameters": {
                    "appServicePlanName": {
                        "value": "[parameters('appServicePlanName')]"
                    },
                    "appServiceName": {
                        "value": "[parameters('appServiceName')]"
                    }
                }
            }
        },
        {
            "name": "storageAccountDeployment",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2020-06-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "relativePath": "artifacts/storageAccount.json"
                },
                "parameters": {
                    "storageAccountName": {
                        "value": "[parameters('storageAccountName')]"
                    },
                    "storageAccountType": {
                        "value": "[parameters('storageAccountType')]"
                    }
                }
            }
        }
    ],
    "outputs": {}
}
Enter fullscreen mode Exit fullscreen mode

Create a new template storageAccount.json in the artifacts directory with the following JSON:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "storageAccountName": {
            "type": "string",
            "metadata": {
            "description": "Storage Account Name"
            }
        },
        "storageAccountType": {
            "type": "string",
            "defaultValue": "Standard_LRS",
            "allowedValues": [
            "Standard_LRS",
            "Standard_GRS",
            "Standard_ZRS",
            "Premium_LRS"
            ],
            "metadata": {
            "description": "Storage Account type"
            }
        },
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]",
            "metadata": {
            "description": "Location for all resources."
            }
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2019-04-01",
            "name": "[parameters('storageAccountName')]",
            "location": "[parameters('location')]",
            "sku": {
            "name": "[parameters('storageAccountType')]"
            },
            "kind": "StorageV2",
            "properties": {}
        }
    ],
    "outputs": {}
}
Enter fullscreen mode Exit fullscreen mode

Now re-deploy the template spec with a newer Version:

New-AzTemplateSpec `
  -Name webappSpec `
  -Version "1.1" `
  -ResourceGroupName $rg `
  -Location eastus `
  -TemplateFile "azuredeploy.json"
Enter fullscreen mode Exit fullscreen mode

If you enter the same version as the previous one, it will overwrite the template spec. You can either update the existing version or publish a new version as needed.

Now when you run the Get-AzTemplateSpec cmdlet, you can see two versions for your template spec in the output:

> Get-AzTemplateSpec -ResourceGroupName $rg -Name webappSpec


Id                    : /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/TemplateSpecsRG/providers/Microsoft.Resou
                        rces/templateSpecs/webappSpec
Name                  : webappSpec
ResourceGroupName     : TemplateSpecsRG
SubscriptionId        : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Location              : eastus
Versions              : {1.0, 1.1}
CreationTime(UTC)     : 2/17/2021 5:42:57 AM
LastModifiedTime(UTC) : 2/17/2021 6:00:07 AM
Enter fullscreen mode Exit fullscreen mode

After the cmdlet executes, verify that the Latest Version is updated in the portal and a new artifact storageAccount.json is added to the template spec

Alt Text

This way you can develop and share ARM templates quickly with the users in your organization.

You can also refer to the below Youtube video on Microsoft Azure channel.


Start leveraging template specs right away!

Top comments (0)