Aztfexport : un outil pour exporter des ressources Azure dans Terraform

Dans un précédent article, nous avons vu le provider AzAPI qui donne une alternative pour déployer des ressources Azure qui ne seraient pas encore disponibles dans le provider Terraform azureRM.
À peu près au même moment, les équipes Microsoft ont proposé un outil pour générer le code Terraform de ressources Azure déjà existantes. Cet outil, connu initialement sous le nom de Terrafy, a été renommé aztfexport et permet donc, en théorie, de répondre à une demande importante des populations techniques en phase d’adoption de l’Infrastructure as Code.
On notera au passage l’ajout d’une fonctionnalité native dans Terraform 1.5.x pour l’import des ressources et la génération de la configuration associée, mais cela fera l’objet d’un prochain article.
Pour le moment, regardons de plus près aztfexport.
Gérer des ressources Azure existantes dans Terraform
Avant de plonger dans l’usage de l’outil, voici un peu de contexte.
Lorsque nous commençons notre voyage dans l’adoption de l’IaC, que ce soit avec Terraform ou un autre outil, nous avons avant tout besoin d’une gouvernance forte.
L’infrastructure Azure créée ne devrait pas l’être avec un autre outil que celui choisi pour l’IaC.
L’outil choisit sur un scope défini devrait être utilisé sur ce même scope sans exception (d’où l’importance de la gouvernance pour définir ce scope notamment).
Ceci étant dit, toute règle entrainant ses exceptions, il arrivera sans aucun doute que certaines ressources soient créées manuellement, ou à travers un autre outil de scripting, comme PowerShell ou Azure CLI.
Ce cas a bien entendu rapidement été inclus dans la stratégie IaC et, par corollaire, dans l’évolution de Terraform, ce qui nous a permis d’avoir la fonctionnalité d’import de ressource dans le state Terraform.
Malgré tout, l’existence de cette fonctionnalité ne lui enlève en rien son caractère pénible et une forte probabilité d’erreur. Après tout, importer manuellement des objets dans un outil qui gère de l’automatisation est contre-intuitif.
Cela étant dit, le workflow d’import de ressources dans Terraform est comme suit :

La documentation Terraform et du provider concerné fournit en général un exemple pour réaliser l’import d’une ressource. Ci-dessous, par exemple, un cas d’usage avec un virtual network :
La commande est relativement simple et claire, mais montre bien, lorsque l’on s’attarde sur le resource id, qu’elle induit une bonne probabilité d’erreur. D’autre part, il faut encore écrire la configuration associée à la ressource importée.
Heureusement, voici aztfexport.
Concepts aztfexport
L’outil aztfexport est là pour nous simplifier (grandement) l’import et la génération automatique de configuration Terraform associée. Par rapport au workflow précédent, pour faire simple, on se débarrasse de toutes les étapes en bleu.
Il est possible d’importer dans Terraform (ou d’exporter depuis Azure, d’où le nom) une ressource unique, des ressources depuis un resource group, ou un set de ressources customisable.
Sous le capot, l’outil s’appuie sur Terraform, bien entendu, et sur deux autres outils écrits en Go. Tout d’abord aztft identifie le type d’une ressource en lisant son resource id. Ensuite, la commande « terraform import » est invoquée, et pour finir l’outil tfadd génère la configuration HCL pour chacune des ressources importées.

Nous en avons à présent fini avec les concepts. Rien de bien méchant, mais un potentiel énorme pour optimiser le workflow d’import de ressources Azure.
Installation
L’installation de aztfexport peut être réalisée de plusieurs manières. En ce qui me concerne, j’ai une préférence pour l’usage de packet manager comme apt. Tout cela est très bien documenté sur le GitHub de aztfexport.
Pour une installation avec apt par exemple, on doit réaliser les étapes suivantes :
À ce stade, nous sommes prêts pour importer des ressources.
Test de l’outil
Pour illustrer notre propos, prenons un cas d’usage simple.
Nous avons ci-après des zones DNS Azure (privées et publiques), qui ont été créées à la main et que nous souhaiterions passer dans un workflow de gestion via Terraform.

Les lecteurs attentifs auront noté qu’il y a une option pour importer toutes les ressources d’un resource group. Mais avant tout, il est nécessaire d’être authentifié sur Azure, et dans le bon abonnement :
Ensuite, nous pouvons tester l’import de nos ressources, en spécifiant le resource group cible :
```bash yumemaru@azure$ aztfexport resource-group rg-dns ```
L’écran suivant devrait s’afficher :

Puis celui-ci, lorsque l’initialisation est complète :
Nous avons la possibilité de scroller sur chacune des ressources listées et d’utiliser des options, affichées en bas de l’écran. L’option « r » nous permet de voir une des ressources, dans le cas suivant une zone dns :
Après avoir revu les ressources proposées, nous pouvons initier l’import.

L’action d’import est finalisée en appuyant sur une touche quelconque.

Nous avons ensuite les fichiers suivants :
yumemaru@azure$ tree
.
├── aztfexportResourceMapping.json
├── aztfexportSkippedResources.txt
├── main.tf
├── provider.tf
├── terraform.tf
└── terraform.tfstate
Dans le main.tf, nous trouvons les ressources importées dans le state Terraform (ou exportées depuis Azure). Nous y reviendrons un peu plus tard.
Dans le fichier provider.tf, nous avons le strict minimum, dans la mesure où notre méthode d’authentification est az cli :
Et de même pour le fichier terraform.tf qui sélectionne automatiquement une version de provider.
On notera le fichier terraform.tfstate qui montre bien que notre state est, à ce stade, encore local.
Enfin, nous avons 2 fichiers additionnels.
aztfexportSkippedResources.txt contient les ressources Azure que nous n’avons pas importées.
Nous avons donc à présent nos ressources dans le state Terraform. Nous pouvons donc lancer un Terraform plan / apply et ajouter ou enlever des ressources. Commençons par un Terraform init :
Puis un Terraform plan :
Aucun changement n’est détecté comme prévu.
Puisque nous avons quelques anciens « cname », non utilisés avant leur import, nous pouvons les enlever de la configuration en commentant la section concernée :
Le plan nous renvoie cette fois-ci les changements suivants :
Retournons à présent sur notre main.tf
On peut remarquer, sans surprise, que l’ensemble des arguments ont des valeurs écrites en dur.
L’essentiel à retenir
Tout d’abord, nous pouvons à présent considérer que nos ressources sont managées par Terraform. Le contrat est donc rempli.
Concernant la configuration Terraform, la présence de valeur en dur, ainsi que l’organisation brute des ressources impliquent un besoin de refactoring.
On peut aussi relever le state local par défaut qui devrait être la priorité à migrer afin de garder un historique de la configuration (même si, puisque l’on importe facilement, on pourrait toujours recommencer).
Enfin, comme mentionné dans la documentation de l’outil, il n’est pas garanti que les configurations générées puissent être utilisées comme templates pour reproduire d’autres sets de ressources similaires.
Nous espérons que cet article vous aura été utile et vous donnons rendez-vous pour un prochain article dans lequel nous aborderons la version Terraform native de l’import, rendue disponible avec Terraform 1.5.