MARS 22

ARM - Enrichir vos templates avec vos propres fonctions

Les templates ARM vous permettent de déployer vos infrastructures sur Azure ou Azure Stack, et ils vous évitent de nombreux clics dans le portail.

Un des retours que j’ai souvent à leur sujet c’est :

  • Trop verbeux
  • Trop de json
  • Pas assez de méthode built-in

Ce dernier point peut être en parti résolu par une fonctionnalité méconnue des templates ARM.

Pour la plupart des personnes, un template ARM ressemble à ça :

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {},
    "resources": [],
    "outputs": {}
}

Et bien sachez qu’il y a une propriété de plus qui n’est pas obligatoire, et qu’on peut voir ici :

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {},
    "functions": [],
    "resources": [],
    "outputs": {}
}

Voyons comment créer notre fonction, et oui c’est toujours du json:

{
    "namespace": "woivre",
    "members": {
        "arrayToString": {
            "parameters": [
                {
                    "name": "input",
                    "type": "array"
                }
            ],
            "output": {
                "type": "string",
                "value": "[replace(substring(string(parameters('input')), 1, sub(length(string(parameters('input'))), 2)), '\"', '')]"
            }
        }
    }
}

Ce que l’on peut faire dans les fonctions est assez limité, mais pour de la manipulation de données c’est très efficace.

Au global cela nous donne le template suivant :

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {
        "testValues": [
            "One",
            "Two",
            "Three",
            "Four"
        ]
    },
    "functions": [
        {
            "namespace": "woivre",
            "members": {
                "arrayToString": {
                    "parameters": [
                        {
                            "name": "input",
                            "type": "array"
                        }
                    ],
                    "output": {
                        "type": "string",
                        "value": "[replace(substring(string(parameters('input')), 1, sub(length(string(parameters('input'))), 2)), '\"', '')]"
                    }
                }
            }
        }
    ],
    "resources": [],
    "outputs": {
        "test": {
            "type": "string",
            "value": "[woivre.arrayToString(variables('testValues'))]"
        }
    }
}

Pratique si vous ne voulez pas trop vous répéter dans vos templates.


MARS 20

ARM - Provisionnez un Azure Automation avec un RunAsAccount

Lorsque vous voulez utiliser Azure Automation pour gérer vos ressources Azure, vous devez créer un Service Principal qui vous servira de RunAsAccount. Il est possible de faire cela via le portail Azure, et cela vous créera un compte qui ressemble à celui là.

image

Si vous avez une convention de nommage, le nom de l’application : reference-aa_5cz2xH6ut6qwABcMDEIfJNCdFX2GZIDGHNrMbVunQAY= ne vous convient sûrement pas, ça tombe bien moi non plus.

Pour cela, il faut précréer votre Service principal avant de créer votre compte Automation via un template ARM dans mon cas. Le compte doit respecter les éléments suivants :

  • Avoir un joli nom qui répond à vos contraintes de naming : pretty-app
  • Une HomePage Url correspondant à l’url de votre service sur Azure : https://management.azure.com//subscriptions/##SUBSCRIPTION_ID##/resourceGroups/aa/providers/Microsoft.Automation/automationAccounts/sample-aa
  • Un certificat à renseigner en tant que secret de votre application.

Donner des droits à ce compte sur la souscription Azure que vous souhaitez afin de pouvoir valider le bon fonctionnement de votre compte Applicatif.

Maintenant, passons à notre template ARM, qui est le suivant :

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {
        "aa-appId": "##_APPLICATION_ID_##",
        "aa-tenantId": "##_TENANT_ID_##",
        "aa-certBase64Value": "##_CERTIFICATE_VALUE_BASE64_##",
        "aa-certThumbprint": "##_CERTIFICATE_THUMBPRINT_##",
        "aa-subId": "##_SUBSCRIPTION_ID_##"
    },
    "resources": [
        {
            "type": "Microsoft.Automation/automationAccounts",
            "apiVersion": "2015-10-31",
            "name": "sample-aa",
            "location": "[resourceGroup().location]",
            "properties": {
                "sku": {
                    "name": "Free"
                }
            },
            "resources": [
                {
                    "name": "AzureRunAsCertificate",
                    "type": "certificates",
                    "apiVersion": "2015-10-31",
                    "dependsOn": [
                        "sample-aa"
                    ],
                    "properties": {
                        "base64Value": "[variables('aa-certBase64Value')]"
                    }
                },
                {
                    "name": "AzureRunAsConnection",
                    "type": "connections",
                    "dependsOn": [
                        "sample-aa",
                        "AzureRunAsCertificate"
                    ],
                    "apiVersion": "2015-10-31",
                    "properties": {
                        "connectionType": {
                            "name": "AzureServicePrincipal"
                        },
                        "fieldDefinitionValues": {
                            "ApplicationId": "[variables('aa-appId')]",
                            "TenantId": "[variables('aa-tenantId')]",
                            "CertificateThumbprint": "[variables('aa-certThumbprint')]",
                            "SubscriptionId": "[variables('aa-subId')]"
                        }
                    }
                }
            ]
        }
    ],
    "outputs": {}
}

Si on détaille un peu on retrouve ici notre account automation :

{
    "type": "Microsoft.Automation/automationAccounts",
    "apiVersion": "2015-10-31",
    "name": "sample-aa",
    "location": "[resourceGroup().location]",
    "properties": {
        "sku": {
            "name": "Free"
        }
    }
}

Maintenant on ajoute le certificat qui sert à nous identifier avec notre service principal

{
    "name": "AzureRunAsCertificate",
    "type": "certificates",
    "apiVersion": "2015-10-31",
    "dependsOn": [
        "sample-aa"
    ],
    "properties": {
        "base64Value": "[variables('aa-certBase64Value')]"
    }
}

Et pour finir, il faut créer le compte dans Azure Automation

{
    "name": "AzureRunAsConnection",
    "type": "connections",
    "dependsOn": [
        "sample-aa",
        "AzureRunAsCertificate"
    ],
    "apiVersion": "2015-10-31",
    "properties": {
        "connectionType": {
            "name": "AzureServicePrincipal"
        },
        "fieldDefinitionValues": {
            "ApplicationId": "[variables('aa-appId')]",
            "TenantId": "[variables('aa-tenantId')]",
            "CertificateThumbprint": "[variables('aa-certThumbprint')]",
            "SubscriptionId": "[variables('aa-subId')]"
        }
    }
}

Et voilà, vous pouvez maintenant utiliser un Azure Automation avec un RunAsAccount qui respecte votre règle de nommage.


MARS 13

Powershell - Astuces avec le module Az pour les Storage Account

Vous n’êtes pas sans savoir que Microsoft a mis à jour son module Powershell AzureRM par Az. Ce module a l’usage a pour principale modification de remplacer vos commandes AzureRM par Az comme on peut le voir ci-dessous :

Connect-AzureRMAccount

Connect-AzAccount

Techniquement pour les migrations de vos scripts c’est assez simple à mettre en oeuvre, donc n’hésitez pas à migrer !

Par ailleurs, le module Az apporte quelques nouveautés plutôt cools notamment pour le Storage. J’avais publié différents articles sur le support de RBAC pour accéder aux data du blob storage :

Et bien maintenant il y a une nouvelle solution, vous pouvez le faire via le module Powershell via les commandes suivantes

Connect-AzAccount # Via un Service Principal ou non

New-AzStorageContext -StorageAccountName $storageDestinationName -UseConnectedAccount

Et voilà comment passer un token AD sans avoir à écrire 30 lignes de powershell. A noter qu’il existe aussi une fonctionnalité similaire pour vos comptes de Storage de dev local

New-AzStorageContext -Local

Et dans une moindre mesure, il est possible de se connecter à un storage de manière anonyme, même si dans ce cas précis, je ne vois pas l’avantage par rapport à des appels REST standards.

New-AzStorageAccount -StorageAccountName $storageDestinationName -Anonymous

Mais bon l’option existe donc si vous voulez l’utiliser, allez-y.


MARS 11

ARM - Nouveautés mars 2019

Un petit article pour vous faire part des nouveautés disponibles sur ARM que je trouve vraiment cool, et surtout que j’attendais particulièrement.

Possibilité d’ajouter un paramètre avec la date currente.

"parameters": {
    "time": {
        "type": "string",
        "defaultValue": "[utcNow()]",
        "metadata": {
            "description": "This returns the current UTC time of deployment. This function may only be used in the defaultValue of a parameter."
        }
    },
    "date": {
        "type": "string",
        "defaultValue": "[utcNow('dd-MM-yy')]",
        "metadata": {
            "description": "Standard dateTime format strings are supported: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings"
        }
    }   
}

A noter que celui-ci ne marche que dans l’objet paramètre et non pas dans la partie variable. Du coup il est maintenant possible d’ajouter la date de création de vos ressources dans vos tags.

Il est maintenant possible d’ajouter un peu d’aléa grâce à la génération de guid dans vos templates

"parameters": {
    "guid": {
        "type": "string",
        "defaultValue": "[newGuid()]",
        "metadata": {
            "description": "This will generate a new GUID each time this template is deployed. This function may only be used in the defaultValue of a parameter."
        }
    },
    "trulyUnique": {
        "type": "string",
        "defaultValue": "[uniqueString(newGuid())]",
        "metadata": {
            "description": "This will generate a new uniqueString() each time this template is deployed. This is not idempotent, use with care."
        }
    },
    "trulyUniqueGuid": {
        "type": "string",
        "defaultValue": "[guid(newGuid())]",
        "metadata": {
            "description": "This will generate a new guid each time this template is deployed. The guid() function can be idempotent, used this way it is not."
        }
    }
}

Voilà il y a aussi d’autres nouveautés liées à ARM, je vous laisse aller voir le blog dédié à celles-ci: https://azure.microsoft.com/en-us/updates/azure-resource-manager-template-language-additions/


FEVR 06

ARM - Rejoindre un domaine Active Directory avec prestaging

Créer des machines virtuelles sur Azure est plutôt simple. Cela se corse lorsque vous voulez les créer avec diverses règles de sécurité “built-in”.

Par exemple, dans mon cas, je souhaite associer ma VM fraichement créée à un active directory on premise (connecté via un Express Route) dans une OU spécifique avec l’obligation de faire du préstaging de machine dans mon OU.

Pour cela j’ai utiisé l’extension JsonADDomainExtension fournie par Microsoft qui est présente dans les QuickStart ARM https://github.com/Azure/azure-quickstart-templates/tree/master/201-vm-domain-join-existing.

Cet exemple est parfait pour créer une nouvelle VM dans mon OU. Le prestaging demande un peu plus d’exploration, en effet tout se base sur la variable domainJoinOptions qui est fixée à 3. Si vous faîtes une recherche sur votre moteur préférée vous allez trouver des notions de magic number 3 ce qui ne va pas vous aider.

En allant plus loin vous allez tomber sur cette documentation qui vous liste les différentes options : https://docs.microsoft.com/en-us/windows/desktop/api/lmjoin/nf-lmjoin-netjoindomain

Celle qui nous intéresse dans ce cas précis est l’option 20 :

  • NETSETUP_DOMAIN_JOIN_IF_JOINED
  • 0x00000020
  • Allows a join to a new domain even if the computer is already joined to a domain.

Du coup cela me donne en ARM le code suivant :

{
    "name": "[concat(parameters('vmName'),'/', 'JoinADDomain')]",
    "apiVersion": "2015-06-15",
    "type": "Microsoft.Compute/virtualMachines/extensions",
    "location": "[variables('location')]",
    "tags": "[variables('consolidateTags')]",
    "condition": "[parameters('joinActiveDirectory')]",
    "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'), '/extensions/AzureDiskEncryption')]"
    ],
    "properties": {
        "publisher": "Microsoft.Compute",
        "type": "JsonADDomainExtension",
        "typeHandlerVersion": "1.3",
        "autoUpgradeMinorVersion": true,
        "settings": {
            "Name": "[parameters('domainActiveDirectory')]",
            "User": "[parameters('domainOperator')]",
            "Restart": "true",
            "Options": "20",
            "OUPath": "[parameters('domainOUPath')]"
        },
        "protectedSettings": {
            "Password": "[parameters('domainOperatorPassword')]"
        }
    }
}