Automate Azure App Configuration Deployment

Florian CAILLAUD
Published by Florian CAILLAUD
Category : ARM Template / Azure / Azure Key Vault DevOps
31/08/2021

Introduction

 

Azure App Configuration is an Azure service used to centralize the configuration for a set of applications in the Cloud.
The advantage of this type of resource is in externalizing the configuration. Therefore, it is neither present directly in the code nor scattered across many Azure services. The application configuration can then be managed dynamically and centrally. This helps, for example, to avoid redeploying or restarting applications in order to update the configuration.
In this context, Azure App Configuration can be used to implement « feature flag » deployment strategies. We can also simply build flat or hierarchical configurations, potentially with secret values (link to Azure Key Vault).

In addition, Azure App Configuration is scalable and therefore natively manages an increasing workload. This service also offers version management.

Applications generally use this resource at run time. It can, however, be used for deployment purposes. The distinction between Azure App Configuration, Azure Key Vault and variable groups (or other pipeline variables) must nevertheless be made in Azure DevOps.

In Azure DevOps, only the configuration values dedicated to deployment will be stored. It is also possible to include secret values or make a link to Azure Key Vault. Azure Key Vault, for its part, will be used to store secret values or certificates.

If the use of Azure App Configuration is justified, here are a few tips on how to deploy this resource.

 

Azure App Configuration ARM template

 

This type of resource can be created directly from the Azure portal. It is good practice, however, to set up automatic deployment of the resource. To do this, we use an ARM template describing our App Configuration.

Here is a minimal App Configuration template:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "configStoreName": {
      "type": "string"
    },
    "keyValueNames": {
      "type": "array",
      "defaultValue": [ "myKey", "myKey$myLabel" ]
    },
    "keyValueValues": {
      "type": "array",
      "defaultValue": [ "Key-value without label", "Key-value with label" ]
    },
    "contentType": {
      "type": "string",
      "defaultValue": "the-content-type",
      "metadata": {
        "description": "Specifies the content type of the key-value resources. For feature flag, the value should be application/vnd.microsoft.appconfig.ff+json;charset=utf-8. For Key Value reference, the value should be application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8. Otherwise, it's optional."
      }
    },
    "tags": {
      "type": "object",
      "defaultValue": {
        "tag1": "tag-value-1",
        "tag2": "tag-value-2"
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.AppConfiguration/configurationStores",
      "apiVersion": "2020-07-01-preview",
      "name": "[parameters('configStoreName')]",
      "location": "[resourceGroup().location]",
      "sku": {
        "name": "standard"
      }
    },
    {
      "type": "Microsoft.AppConfiguration/configurationStores/keyValues",
      "apiVersion": "2020-07-01-preview",
      "name": "[concat(parameters('configStoreName'), '/', parameters('keyValueNames')[copyIndex()])]",
      "copy": {
        "name": "keyValueCopy",
        "count": "[length(parameters('keyValueNames'))]"
      },
      "dependsOn": [
        "[parameters('configStoreName')]"
      ],
      "properties": {
        "value": "[parameters('keyValueValues')[copyIndex()]]",
        "contentType": "[parameters('contentType')]",
        "tags": "[parameters('tags')]"
      }
    }
  ]
}

There are several things to note here.

First, you can have one template per environment with static initial values. But these values can also be configurable (see keyValueNames and keyValueValues in the template). They will be defined on the fly at deployment time. Deployment can take place using PowerShell, Azure DevOps or GitHub. Each one will have its variable mechanism.
It is also possible to deploy only one or several key/value pairs using only the Microsoft.AppConfiguration/configurationStores/keyValues resource in our template.

Each key can then be linked to a label for better organization. It can refer to a version or an environment, for example. To add this label, it must be placed after the name of the value and a ‘$’ (myKey$myLabel in the template above).

Note: certain characters are not permitted in an ARM template. When defining keys, labels, and especially values, it is often necessary to use special characters. In that case, the value must initially be URL encoded (replacing special characters with %…). The % symbols must then be replaced by ~ and the ~ must be replaced by ~7E. For example, for a key AppName:DbEndPoint and a label Test, the value AppName~3ADbEndPoint$Test will be used.

 

ARM Deployment

 

As mentioned above, there are several ways to deploy this ARM template.
With PowerShell, we must log into the desired Azure subscription. We then use the command New-AzResourceGroupDeployment specifying the target resource group, template, and settings file (doc) if appropriate.
On Azure DevOps, the ARM template deployment task is used within a pipeline (with the designer or a YAML script). The following information will be required:
  • the Service Connection (defined in the project to allow access to the target resource group)
  • la subscription,
  • the resource group and then the associated template and settings file (designer doc, YAML doc).
Here, the values of the settings can be redefined on the fly using pipeline variables or variable groups.
And finally, with GitHub, setting up a GitHub Action is necessary (doc). The mechanism is very similar to that of Azure DevOps.