Le plan directeur qu'on remet au nouvel opérateur

Un port sérieux ne loue pas un terrain vague. Quand un opérateur obtient une concession, on lui remet un quai déjà viabilisé : le tirant d'eau est connu, le courant arrive au bollard, la voie ferrée est posée jusqu'au bord, le règlement portuaire s'applique dès le premier conteneur débarqué.

L'opérateur apporte ses grues, ses équipes et ses clients. Il n'apporte ni les réseaux, ni le balisage, ni la douane.

L'inverse existe aussi, et il se pratique beaucoup en informatique. On donne un abonnement à une équipe, un rôle Contributeur, un lien vers le portail, et bonne chance.

Trois mois plus tard, le bilan est connu d'avance. Deux plages d'adresses qui se chevauchent et qu'on ne pourra jamais appairer. Trois espaces de travail de journaux, dont deux que personne ne lit. Un pare-feu par équipe, facturé par équipe. Aucune convention de nommage, donc aucune refacturation possible. Et une reconstruction qui prendrait des semaines, parce que personne ne sait exactement ce qui a été cliqué.

La zone d'atterrissage, c'est le plan directeur du port appliqué au cloud : le terrain est préparé avant que le premier navire n'accoste.

Une zone d'atterrissage n'est pas un modèle de document ni une liste de bonnes pratiques. C'est un environnement déjà gouverné, déjà raccordé et déjà supervisé, dans lequel une équipe peut déployer sans redemander la permission à personne.

Ce qui est garanti avant la première ressource

Sur un port, le plan directeur ne décrit pas les cargaisons. Il décrit ce qui existe avant elles et ce qui existera après : les chenaux, les postes d'amarrage, les clôtures, les points de raccordement.

La promesse d'une zone d'atterrissage tient dans le même registre. Tout ce qui est commun est déjà en place, et surtout, il est déjà appliqué.

Concrètement, une équipe qui reçoit sa zone d'atterrissage hérite de cinq décisions déjà prises. Sa position dans la hiérarchie des groupes d'administration détermine les stratégies qui la contraignent. Ses droits sont attribués à des groupes, et non à des personnes. Son espace d'adressage est réservé dans un plan global, déjà raccordé au moyeu. Sa collecte de journaux part vers l'espace de travail commun. Et le socle de sécurité s'applique sans qu'elle ait à le demander.

Ce qui reste à sa charge, c'est son application. C'est exactement le partage du port : l'exploitant tient l'infrastructure commune, le concessionnaire tient son terminal.

flowchart TB MG["Groupes d'administration
stratégies et étiquettes héritées"] subgraph PF["Zones d'atterrissage de plateforme"] ID["Abonnement identité"] CX["Abonnement connectivité
moyeu, pare-feu, passerelles"] OP["Abonnement gestion
journaux, coffres, sauvegarde"] end subgraph LZ["Zones d'atterrissage applicatives"] R1["Rayon 1
production"] R2["Rayon 2
hors production"] R3["Rayon 3
bac à sable"] end MG --> PF MG --> LZ CX <--> R1 CX <--> R2 CX <--> R3 OP -.-> R1 OP -.-> R2 OP -.-> R3 classDef racine fill:#b5651d,stroke:#8a4d16,color:#f5f2ec; classDef plateforme fill:#d89253,stroke:#8a4d16,color:#2c3338; classDef rayon fill:#f5f2ec,stroke:#8a4d16,color:#1a1a1a; class MG racine; class ID,CX,OP plateforme; class R1,R2,R3 rayon;

La topologie dessinée ici est la plus répandue : un moyeu central qui porte le raccordement au réseau interne, le filtrage sortant et les services partagés, et des rayons appairés qui portent les charges de travail. Le moyeu appartient à la plateforme, les rayons appartiennent aux équipes.

Un rayon est surtout une unité reproductible. Le vingtième se crée comme le deuxième, avec le même code et les mêmes paramètres. À défaut, la zone d'atterrissage n'existe pas vraiment : il n'y a qu'un premier environnement soigné.

Une zone d'atterrissage se mesure à ce qu'une équipe n'a plus à décider, et au temps qu'il faut pour en produire une de plus.

Les huit domaines de conception

Le plan directeur d'un port ne dit pas où poser les grues. Il dit où passent les quais, l'eau, le courant, les rails et les clôtures, qui paie quoi, et qui a le droit d'entrer où.

Le cadre d'adoption du cloud publié par Microsoft découpe la même chose en huit domaines de conception. Aucun n'est optionnel : chacun est tranché explicitement, ou tranché par défaut par la première équipe qui déploie.

Domaine Décision à prendre Conséquence si on la reporte
Facturation et locataire Nombre de locataires, forme du contrat d'achat, qui a le droit de créer un abonnement Des abonnements sans propriétaire identifié, et une refacturation impossible à reconstituer après coup
Identité et accès Annuaire de référence, groupes porteurs des rôles, comptes d'accès d'urgence Des droits attribués à des personnes, des Propriétaires partout, aucune revue possible
Organisation des ressources Arborescence des groupes d'administration, découpage en abonnements, nommage, étiquettes Une hiérarchie refaite un an plus tard, donc des abonnements à déplacer et des stratégies à rejouer
Topologie réseau et connectivité Plan d'adressage global, moyeu classique ou service de réseau étendu, raccordement au site, résolution de noms Des plages qui se chevauchent, un appairage refusé, et un redéploiement complet pour en sortir
Sécurité Chiffrement, gestion des secrets, exposition des services de données sur Internet, plans de protection activés Des services de données publics par défaut, remis en conformité un par un, à la main
Gestion Supervision, agents, sauvegarde, correctifs, rétention Un parc sans journaux le jour où on en a besoin, et une sauvegarde décidée machine par machine
Gouvernance Stratégies, initiatives, portées d'application, exemptions traçables Un audit permanent au lieu d'un refus, et une dérive constatée trois trimestres trop tard
Automatisation de plateforme Dépôt, pipelines, identités de déploiement, modules réutilisables Une plateforme construite au portail, non reproductible, dont la reconstruction devient un projet

Deux domaines concentrent l'essentiel des regrets. Le réseau, parce qu'un plan d'adressage se change en redéployant, et l'organisation des ressources, parce qu'elle porte tout le reste.

La hiérarchie, les stratégies et l'étiquetage sont traités en détail dans Gouvernance Azure : hiérarchie, stratégies et étiquetage. Ce billet-ci part du principe que ces décisions sont prises et s'occupe de les livrer.

Reporter une décision de zone d'atterrissage ne la supprime pas. Elle est simplement transférée à la première équipe qui déploie, qui la prendra pour elle seule, sans savoir qu'elle décide pour tout le monde.

Plateforme d'un côté, applications de l'autre

Le port sépare nettement ce qui relève de l'exploitation commune et ce qui est concédé. Le chenal, le balisage, le poste électrique et la douane sont au port. Les portiques, les entrepôts et les clients sont au terminal.

Cette frontière a un nom côté Azure : zones d'atterrissage de plateforme d'un côté, zones d'atterrissage applicatives de l'autre.

Les premières sont peu nombreuses et durables. Trois abonnements suffisent dans la plupart des organisations : l'identité, la connectivité, la gestion. Elles sont exploitées par une équipe plateforme et changent rarement.

Les secondes sont nombreuses et jetables. Une par charge de travail, souvent une par charge de travail et par environnement.

Fourni par la plateforme Décidé par l'équipe applicative
Position dans la hiérarchie et stratégies héritées Services utilisés à l'intérieur de l'abonnement
Plage d'adresses réservée et appairage au moyeu Découpage en sous-réseaux à l'intérieur de la plage
Filtrage sortant, résolution de noms privée Règles applicatives dans ses propres groupes de sécurité
Espace de travail de journaux et rétention de base Contenu applicatif journalisé, tableaux de bord, alertes métier
Rôles de base et groupes d'accès Attributions fines à l'intérieur de son périmètre
Étiquettes obligatoires et convention de nommage Étiquettes propres à son cycle de vie

Le découpage en abonnements se raisonne avec les trois limites vues au billet précédent : limite de facturation, limite de quota, limite de sécurité. En pratique, un abonnement par charge de travail et par environnement reste la ligne de départ la plus saine, quitte à regrouper ensuite les petits périmètres.

Reste à produire ces abonnements sans que ce soit un rituel. C'est le rôle de la distribution d'abonnements : une équipe remplit une demande, un processus automatisé crée l'abonnement, le place dans le bon groupe d'administration, lui alloue une plage d'adresses depuis le plan global, l'appaire au moyeu, y pose les rôles, les étiquettes obligatoires et les paramètres de diagnostic, puis le remet prêt à l'emploi.

La différence entre un délai de deux jours et un délai de trois semaines n'est pas cosmétique. Quand obtenir un environnement conforme prend trois semaines, les équipes contournent, et le contournement devient la norme.

Si obtenir une zone d'atterrissage conforme est plus long que d'en bricoler une, la gouvernance a déjà perdu, quel que soit le nombre de stratégies déployées.

Décrire l'infrastructure comme du code

Le plan directeur du port n'est pas un souvenir dans la tête du capitaine. C'est un jeu de plans, versionné, avec des révisions datées, qu'on peut rééditer à l'identique et sur lequel on discute avant de creuser.

Trois outils font ce travail sur Azure, et on les compare presque toujours sur le mauvais critère.

ARM en JSON est le format natif : c'est ce que le gestionnaire de ressources consomme réellement. Verbeux, difficile à relire en revue, mais c'est le socle sur lequel tout le reste s'appuie.

Bicep est un langage dédié qui se compile en ARM. Même modèle d'exécution, même couverture des ressources, syntaxe lisible, modules, types et validation à la compilation.

Terraform est un outil indépendant du fournisseur, avec son propre langage et surtout son propre fichier d'état.

Critère ARM en JSON Bicep Terraform
Langage JSON, verbeux, expressions imbriquées Langage dédié, lisible, modules typés HCL, commun à tous les fournisseurs
État Aucun fichier à gérer, l'état de référence est dans Azure Identique à ARM Fichier d'état à héberger, verrouiller et protéger
Périmètre Azure uniquement Azure uniquement Plusieurs fournisseurs dans un même plan
Aperçu avant application Opération what-if Opération what-if Commande de planification
Ressources retirées du code Supprimées seulement en mode complet ou via une pile de déploiement Idem Détruites par défaut au prochain passage
Nouveautés de la plateforme Disponibles dès la publication de l'interface Idem Selon la couverture du fournisseur, complétée par le fournisseur générique
Compétence à entretenir Faible mais pénible Faible, proche du modèle Azure Plus large, l'état devient un objet d'exploitation

La ligne de partage se joue ailleurs que dans la syntaxe. Deux questions la tracent : qui détient l'état de référence, et que devient une ressource qu'on retire du code.

Voici un modèle Bicep court, déployé à la portée d'un abonnement, qui crée un groupe de ressources étiqueté et lui rattache un module.

targetScope = 'subscription'

@description('Trigramme de la charge de travail, repris dans le nom des ressources.')
param workload string

@allowed([
  'dev'
  'prd'
])
param env string

param location string = 'francecentral'

var tags = {
  workload: workload
  environment: env
  managedBy: 'bicep'
  costCenter: 'PF-0042'
}

resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: 'rg-${workload}-${env}-${location}'
  location: location
  tags: tags
}

module network 'modules/vnet.bicep' = {
  name: 'vnet-${workload}-${env}'
  scope: rg
  params: {
    location: location
    tags: tags
    addressPrefix: '10.20.0.0/16'
  }
}

output resourceGroupName string = rg.name

Peu de choses comptent vraiment dans ce fichier. Le targetScope fixe la portée du déploiement. Les étiquettes sont construites une fois puis passées au module, pour qu'aucune ressource n'y échappe. Et le module lui-même reste la seule façon d'obtenir vingt rayons identiques plutôt que vingt variantes.

Sur les modules, il existe une base publiée et maintenue par Microsoft, les Azure Verified Modules, disponibles pour Bicep et pour Terraform. Microsoft publie aussi des implémentations de référence complètes de zone d'atterrissage, dans les deux langages. Partir de là évite de réécrire un socle qui existe déjà.

Le choix Bicep ou Terraform occupe des réunions entières et n'est presque jamais le sujet. Ce qui décide, c'est la gestion de l'état et le sort des ressources retirées du code.

Déployer : modes, portées, vagues

Aucun port ne change le balisage de tous ses chenaux la même nuit. On modifie un chenal, on regarde passer quelques navires, puis on étend.

Le déploiement sur Azure obéit à trois notions qu'on confond régulièrement.

La portée. Un déploiement s'applique à un groupe de ressources, à un abonnement, à un groupe d'administration ou au locataire. C'est ce que fixe targetScope, et ce que détermine la commande utilisée. Une zone d'atterrissage se déploie forcément à plusieurs portées : les groupes d'administration et les stratégies au-dessus, les ressources en dessous.

Le mode. L'incrémentiel ajoute et met à jour, sans jamais supprimer ce que le modèle ne décrit plus. Le mode complet supprime, dans le groupe de ressources visé, tout ce qui n'apparaît pas dans le modèle. Ce mode complet n'existe qu'à la portée d'un groupe de ressources : au-dessus, seul l'incrémentiel est disponible.

L'incrémentiel est le défaut, et c'est aussi la raison pour laquelle un environnement dérive tranquillement. Le code décrit douze ressources, l'abonnement en contient dix-neuf, et personne ne sait d'où viennent les sept autres.

L'aperçu. L'opération what-if calcule et affiche ce que le déploiement changerait, avant de le faire. Elle se relit comme une revue de code, sauf qu'elle porte sur l'environnement réel.

# Aperçu : ce que le déploiement changerait, sans rien appliquer
az deployment sub what-if \
  --location francecentral \
  --template-file main.bicep \
  --parameters workload=cat env=prd

# Application, une fois l'aperçu relu par quelqu'un d'autre que l'auteur
az deployment sub create \
  --name socle-cat-prd \
  --location francecentral \
  --template-file main.bicep \
  --parameters workload=cat env=prd

Pour traiter un ensemble de ressources comme un tout, il existe les piles de déploiement. Une pile gère un lot de ressources comme une seule entité : elle sait ce qu'elle a créé, elle décide du sort de ce qui sort de sa définition, et elle peut refuser les modifications faites en dehors d'elle.

az stack group create \
  --name socle-cat-prd \
  --resource-group rg-cat-prd-francecentral \
  --template-file main.bicep \
  --action-on-unmanage deleteResources \
  --deny-settings-mode denyDelete

Les deux options en fin de commande sont le cœur du sujet. La première dit ce qui arrive aux ressources retirées du modèle. La seconde empêche qu'une main extérieure supprime ce que la pile gère, y compris depuis le portail.

Reste le rythme. Une modification de socle ne se pousse pas partout d'un coup, même quand elle est manifestement correcte.

flowchart LR C["Dépôt de code
revue et fusion"] --> V["Validation
compilation et analyse"] V --> W["Aperçu what-if
relu par un tiers"] W --> V1["Vague 1
bac à sable"] V1 --> O1{"Signaux au vert ?"} O1 -->|non| STOP["Arrêt, retour au code"] O1 -->|oui| V2["Vague 2
hors production, une région"] V2 --> O2{"Signaux au vert ?"} O2 -->|non| STOP O2 -->|oui| V3["Vague 3
production, région par région"] classDef etape fill:#d89253,stroke:#8a4d16,color:#2c3338; classDef vague fill:#b5651d,stroke:#8a4d16,color:#f5f2ec; classDef echec fill:#a0413e,stroke:#8a4d16,color:#f5f2ec; class C,V,W etape; class V1,V2,V3 vague; class STOP echec;

Entre deux vagues, il faut un temps d'observation réel, celui pendant lequel un défaut a une chance de se manifester. Une vague enchaînée sur la précédente en quatre minutes ne protège de rien : elle ne fait que propager plus proprement.

Et il faut décider, à froid, ce qui a le droit de sauter les vagues. La réponse saine est : rien. La réponse honnête est : une procédure d'urgence existera de toute façon, alors autant l'écrire, la tracer et la contraindre.

Le déploiement par vagues n'est pas une lenteur administrative. C'est le seul mécanisme qui transforme une erreur globale en incident local.

Configurer ce qui tourne dedans

Le quai est livré, les rails sont posés, le courant arrive. Restent les portiques et leurs réglages, qui ne relèvent plus du plan directeur mais de l'exploitation quotidienne.

Provisionner et configurer sont deux métiers distincts, et le second commence là où le modèle de déploiement s'arrête. Une machine virtuelle créée par Bicep est une ressource conforme. Ce qui tourne à l'intérieur n'est pas encore décidé.

Besoin Service Limite à connaître
Exécuter un script au premier démarrage d'une machine Extension de script personnalisé Rien ne garantit la convergence dans le temps, le script ne rejoue pas tout seul
Vérifier en continu qu'un réglage système reste conforme Configuration de machine, exposée par Azure Policy L'audit est le comportement par défaut, la correction se demande explicitement
Orchestrer une tâche d'exploitation planifiée Runbooks Azure Automation Ce n'est pas un ordonnanceur d'entreprise, et le code des runbooks se gouverne comme le reste
Appliquer et suivre les correctifs d'un parc Azure Update Manager Suppose des fenêtres de maintenance décidées et des redémarrages assumés
Changer un paramètre applicatif sans redéployer App Configuration et bascules de fonctionnalité Devient une dépendance d'exécution de l'application, avec le cache et la reprise qui vont avec
Étendre tout cela à des machines hors d'Azure Azure Arc Exige un agent et une connectivité sortante maîtrisée

Un mot sur la configuration d'état de type DSC hébergée dans Azure Automation : Microsoft oriente désormais vers la configuration de machine. Si un socle existant repose dessus, c'est une migration à planifier, pas une découverte à faire dans l'urgence.

L'autre approche, souvent la meilleure, consiste à déplacer la configuration en amont : une image durcie, construite et versionnée, publiée dans une galerie de calcul, plutôt qu'une machine générique corrigée après démarrage par une pile de scripts. Le sujet des images est traité avec les machines virtuelles, plus loin dans la série.

Une ressource déployée conforme n'est pas une machine conforme. Le modèle décrit la ressource, la configuration décrit ce qui tourne dedans, et les deux dérivent séparément.

Scénario B : Salesforce, 11 mai 2021

Le 11 mai 2021, les services de Salesforce deviennent injoignables pour une grande partie de ses clients. La panne dure plusieurs heures et le rétablissement s'étale, service après service.

L'éditeur a publié un compte rendu d'incident détaillé, présenté par son responsable technique. Ce que ce compte rendu décrit mérite d'être lu par tous ceux qui déploient de l'infrastructure par du code.

À l'origine, un changement de configuration DNS. Rien d'exotique, rien d'expérimental. Le processus habituel de l'entreprise prévoit un déploiement progressif : le changement part sur un périmètre restreint, on observe, puis on étend, centre de données après centre de données.

Ce changement-là n'a pas suivi ce chemin. Il a été poussé via une procédure d'urgence, un dispositif de correction rapide qui permettait de contourner le déploiement progressif et d'appliquer la modification partout en même temps.

La configuration s'est révélée défectueuse. Les serveurs DNS sont devenus indisponibles, et avec eux tout ce qui en dépendait, c'est-à-dire à peu près tout.

Le compte rendu insiste sur la suite, qui est le vrai coût de l'affaire. La remise en état a demandé des interventions manuelles, site par site, parce que les moyens d'accès et de réparation à distance reposaient précisément sur ce qui venait de tomber. La panne n'a pas duré longtemps parce qu'elle était difficile à comprendre, mais parce qu'elle était difficile à atteindre.

Parmi les mesures annoncées ensuite figure la suppression de cette possibilité de contournement pour ce type de changement, et le renforcement des contrôles automatiques appliqués avant déploiement.

Ce compte rendu se transpose presque tel quel sur une zone d'atterrissage Azure.

D'abord, l'automatisation n'est pas en cause. Un changement DNS appliqué à la main sur des dizaines de sites aurait produit le même effet, plus lentement. Ce qui a échoué, c'est le périmètre d'application.

Ensuite, une procédure d'urgence qui dispose de plus de droits que la procédure normale est une porte dérobée officielle. Sur Azure, elle prend des visages familiers : un rôle Propriétaire permanent sur le groupe d'administration racine, un déploiement lancé depuis un poste avec des droits élevés, un paramètre modifié au portail juste pour dépanner et jamais reporté dans le code.

Enfin, il y a la dépendance circulaire entre le composant modifié et le moyen de le réparer. La résolution de noms, l'identité et le réseau du moyeu appartiennent tous les trois à cette catégorie. Un changement sur eux mérite un mode de réparation qui ne passe pas par eux.

Le chemin d'urgence doit être plus contraint que le chemin normal, jamais moins. S'il permet d'aller plus vite et plus loin, il finira par être emprunté pour de mauvaises raisons, et il le sera le pire jour.

Points clés

  • Une zone d'atterrissage se juge à ce qu'une équipe n'a plus à décider : position dans la hiérarchie, adressage, droits, journaux, garde-fous, et au délai pour en produire une de plus.
  • Les huit domaines de conception se tranchent avant la première charge de travail. Reporter une décision revient à la déléguer à la première équipe qui déploie, sans qu'elle sache qu'elle décide pour tout le monde.
  • ARM, Bicep et Terraform se départagent sur la détention de l'état et sur le sort des ressources retirées du code, pas sur la syntaxe.
  • Le mode incrémentiel n'efface jamais rien : sans mode complet ni pile de déploiement, l'écart entre le code et la réalité grandit à chaque passage.
  • Le déploiement par vagues transforme une erreur globale en incident local. Le dispositif qui permet de le contourner mérite plus de contrôles que le déploiement ordinaire.

Dans la série

Palier 1 : Ouvrir le port. Domaine : Gouvernance.


Pour aller plus loin