Skip to content

Latest commit

 

History

History
204 lines (181 loc) · 7.15 KB

File metadata and controls

204 lines (181 loc) · 7.15 KB

Azure Resource Manager Templates

  • Azure Resource Manager (ARM) templates are infrastructure as code (JSON) in Azure.
  • You can define dependencies to define their deploy order.
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "", // (Required) Your own version to ensure right template is deployed
    "apiProfile": "", // API versions for resource types.
    "parameters": {  }, // prompted when deployment is executed.
    "variables": {  },
    "functions": [  ],
    "resources": [  ], // (Required) Resource types that are deployed or updated
    "outputs": {  } // Values that you want to return after deployment.
}
  • You can use visual editor in Azure Portal
    • Template Deployment => Custom Deployment => Edit Template
  • You can deploy your template on the portal
    • or use Azure CLI: az group deployment create --name testdeployment --resource-group test-rg --template-file test-template.json

Deployment using Azure Pipelines

  • Two ways to deploy templates with Azure Pipelines:
    1. Add task that runs an Azure PowerShell script
      • AzurePowerShell task to execute Deploy-AzureResourceGroup.ps1
      • Consistency throughout the development life cycle because you use the same script that is included in the Visual Studio project
    2. Add tasks to copy and deploy tasks
      • AzureFileCopy task to copy templates to blob storage
      • AzureResourceGroupDeployment to create or update resource group using URL of the template

Nested templates

  • 💡 Recommended way to deploy multiple ARM templates.
  • Reasons
    • Template can grow long and unmanageable
    • Difficult to deploy the template for customized environments
      • E.g. an environment needs everything template except one component.
    • Automation becomes difficult to accomplish
  • Solution
    • Modularize your templates for the minimum e.g. per resource
    • You then create a main template and add you can
      • nest other templates into the main template by defining them there
      • or add URL's to child templates as linked template
        • Pros: Child templates are reusable!
        • Cons: All templates must exist in the remote.
  • To create multiple instances of a resource with a nested template
    • you can add a copy element to copy an existing child template.

Managing secrets

  • E.g. username & password for a VM.
  • Use Azure Key Vault service
  • Flow
    1. Create a vault
      • In Access Policy, enable "Azure Resource Manager for template deployment"
    2. Create a secret e.g. examplesecret
    3. Reference it in ARM template

Referencing in ARM template

With static resource ID

  • You can reference it in ARM template such as:
      "adminPassword": {
          "reference": {
              "keyVault": {
              "id": "/subscriptions/<subscription-id>/resourceGroups/examplegroup/providers/Microsoft.KeyVault/vaults/<vault-name>"
              },
              "secretName": "examplesecret"
          }
      }
  • Pros
    • Existing ARM templates are not changed.
    • Only parameter files are changed to include Azure Key Vault references.
  • Cons
    • Within the parameter file, Azure Key Vault resource ID must be hard-coded.
    • The hard-coded resource ID includes the subscription ID, which might be considered as a sensitive data.

With dynamic resource ID

  • Use this when you do not want to hardcode the Key Vault ID with e.g. subscription id.
  • Dynamically construction ID does not work in ARM template, neither in parameters file.
  • Nested templates are the key to using this dynamic id.
Using linked template
  • Notice templateLink
    • It links to another ARM file that will use secret value as string
    • Template must exist in the remote location
{
    "apiVersion": "2015-01-01",
    "name": "nestedTemplate",
    "type": "Microsoft.Resources/deployments",
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[concat(parameters('templateBaseUri'), 'my-nested-template.json')]",
            "contentVersion": "1.0.0.0"
        },
        "parameters": {
            "resourcegroup": {
                "value": "[parameters('resourcegroup')]"
            },
            "vaultName": {
                "value": "[parameters('vaultName')]"
            },
            "secretToPass": {  // here vault ID & secret name is dynamically generated
                "reference": {
                    "keyVault": {
                        "id": "[resourceId(subscription().subscriptionId,  parameters('resourcegroup'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
                    },
                    "secretName": "examplesecret"
                }
            }
        }
    }
  • Pros
    • There is no hard-coded value required.
  • Cons
    • Additional linked templates should be written increasing maintenance effort.
Using nested template
  • Another option is to have a nested template
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
      "vaultName": {
        "type": "string",
        "metadata": {
          "description": "The name of the keyvault that contains the secret."
        }
      },
      "secretName": {
        "type": "string",
        "metadata": {
          "description": "The name of the secret."
        }
      },
      "vaultResourceGroupName": {
        "type": "string",
        "metadata": {
          "description": "The name of the resource group that contains the keyvault."
        }
      },
      "vaultSubscription": {
        "type": "string",
        "defaultValue": "[subscription().subscriptionId]",
        "metadata": {
          "description": "The name of the subscription that contains the keyvault."
        }
      }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2018-05-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "template": { // nested child template
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminPassword": { // gets from the parent
              "type": "securestring"
            }
          },
          // ... stripped rest of the template
        },
        "parameters": {
          "adminPassword": { // here vault ID & secret name is dynamically generated
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
  }
}