📅 Date de réalisation : 04 November 2025
🎯 Problématique & Contexte métier
Comment connecter des infrastructures cloud déployées dans plusieurs régions géographiques, tout en permettant une résolution de noms interne transparente, sécurisée, et gérée via Infrastructure as Code ?
Le défi
Dans un scénario multi-région (ex: filiales internationales, DRP, compliance géo), on doit :
- Déployer des réseaux isolés mais interconnectés
- Permettre aux services de communiquer entre régions sans passer par Internet
- Offrir une résolution DNS interne cohérente (
service-us.paul.lab,db-india.paul.lab) - Gérer les accès sécurisés (NSG par subnet, pas de ports ouverts inutilement)
- Optimiser les coûts (Spot VMs, sizing adapté)
- Automatiser tout le cycle de vie → reproductibilité, audit, rollback
👉 Ce projet répond à tous ces besoins avec une seule commande terraform apply.
📸 Galerie de captures d’écran
💡 Objectifs techniques
✅ Déployer 3 VNets dans 3 régions Azure (France Central, East US, Central India)
✅ Créer un peering full-mesh (tous les VNets interconnectés) avec setproduct()
✅ Configurer des subnets public/private avec NSG adaptés (RDP/HTTP uniquement en public)
✅ Déployer VMs Linux (Ubuntu) dans les subnets privés → Apache2 via cloud-init
✅ Déployer VMs Windows (Server 2022) dans les subnets publics → IIS via Custom Script Extension
✅ Utiliser des Spot Instances pour réduire les coûts de test
✅ Mettre en place une zone DNS privée (paul.lab) hébergée en France, liée à tous les VNets
✅ Créer des enregistrements A dynamiques pour toutes les VMs → résolution par nom
✅ Appliquer des naming conventions et tags cohérents
✅ Utiliser des variables dynamiques (maps) → extensible à N régions/subnets
✅ Éviter count → privilégier for_each partout
✅ Sécuriser les secrets avec sensitive = true
🏗️ Architecture globale
Schéma d’architecture
🧩 Découpage logique du code Terraform
Le code est entièrement modulaire via des blocs dynamiques pilotés par une seule variable map :
vnets = {
france = {
region = "francecentral"
vnet_cidr = "10.0.0.0/16"
subnets = {
"public" = "10.0.0.0/24"
"private" = "10.0.1.0/24"
}
},
india = { ... },
us = { ... }
}
1. Resource Groups & VNets
resource "azurerm_resource_group" "this" { for_each = var.vnets ... }
resource "azurerm_virtual_network" "this" { for_each = var.vnets ... }
→ Un RG + un VNet par région, nommés automatiquement (rg-france, vnet-france, etc.)
2. Subnets & NSG
resource "azurerm_subnet" "this" {
for_each = merge([
for key, value in var.vnets : {
for x, y in value.subnets :
"${key}-${x}" => {
vnet_key = key # ex: france, us, india
subnet_name = x # ex: private/public
cidr = y # "10.0.0.0/24"
}
}
]...)
...
}
resource "azurerm_network_security_group" "nsg" {
dynamic "security_rule" {
for_each = each.value.is_public ? ["rdp_rule"] : []
...
}
}
→ Les NSG sont créés conditionnellement : règles RDP/HTTP uniquement sur les subnets publics.
3. Peering Full-Mesh
resource "azurerm_virtual_network_peering" "this" {
for_each = {
for pair in setproduct(keys(var.vnets), keys(var.vnets)) :
"${pair[0]}-to-${pair[1]}" => { ... }
if pair[0] != pair[1]
}
...
}
→ Tous les VNets sont peerés entre eux → communication cross-région directe et sécurisée.
VMs Linux (Apache2)
resource "azurerm_linux_virtual_machine" "ubuntu" {
custom_data = base64encode(templatefile("web-server-cloud-init.txt", { ... }))
}
→ Script cloud-init injecté pour installer Apache2 et afficher un message personnalisé par région.
5. VMs Windows (IIS) + Spot Instance
resource "azurerm_windows_virtual_machine" "windows" {
priority = "Spot"
eviction_policy = "Deallocate"
...
}
resource "azurerm_virtual_machine_extension" "windows_iis" {
settings = jsonencode({
commandToExecute = "powershell -Command \"Install-WindowsFeature Web-Server...\""
})
}
→ Coût réduit grâce au mode Spot + installation automatisée d’IIS.
6. Private DNS Zone + Records
resource "azurerm_private_dns_zone" "internal" { name = var.domainename ... }
resource "azurerm_private_dns_a_record" "ubuntu" {
records = [ azurerm_linux_virtual_machine.ubuntu[each.key].private_ip_address ]
}
→ Résolution DNS interne fonctionnelle : ping apache2-us.paul.lab depuis n’importe quelle VM.
🔄 Workflow de déploiement
git clone https://github.com/stanilpaul/terraform_azure_labs.git
cd terraform_azure_labs/1.Virtual_Network_Peering_Three_Different_regions+Private_DNS_Zone
az login
terraform init
terraform validate
terraform plan
terraform apply -auto-approve
# 5. Test manuel :
# - RDP vers la VM Windows publique via son IP publique
# - Depuis cette VM, accède aux sites Apache via leurs noms DNS :
# → http://apache2-france.paul.lab
# → http://apache2-us.paul.lab
# → http://apache2-india.paul.lab
⏱️ Temps de déploiement total : ~10 minutes ⏱️ Temps manuel équivalent : 1h20 (comme documenté dans les étapes manuelles)
🛠️ Technologies & Outils utilisés
| Catégorie | Outils & Technologies |
|---|---|
| Cloud | Microsoft Azure (Multi-Region) |
| IaC | Terraform v1.3+, for_each, setproduct, merge, templatefile |
| Langage | HCL (HashiCorp Language) |
| OS | Ubuntu 22.04 LTS, Windows Server 2022 |
| Init Scripts | Cloud-init (Linux), CustomScriptExtension (Windows) |
| Réseau | VNet Peering, NSG, Private DNS Zone, Public IPs |
| Coûts | Spot Instances pour Windows VM |
| Sécurité | NSG conditionnels, pas de SSH/RDP exposé sauf besoin |
| Validation | terraform validate, tests manuels post-déploiement |
✅ Résultat fonctionnel
- ☑️ 3 VNets déployés dans 3 régions, totalement interconnectés via peering
- ☑️ Communication cross-région sans passer par Internet (latence optimale, sécurité accrue)
- ☑️ Résolution DNS interne fonctionnelle entre toutes les VMs
- ☑️ Sites web accessibles :
- Via IP publique (Windows IIS)
- Via nom DNS interne (Linux Apache2, depuis la VM Windows)
- ☑️ NSG appliqués correctement : seul le trafic nécessaire est autorisé
- ☑️ Coûts optimisés grâce aux Spot Instances
- ☑️ Infrastructure 100% reproductible, versionnable, et documentée
Démonstration vidéo (2 min)
Dans la vidéo :
- Je lance le terraform apply complet
- Je montre les ressources créées dans le portail Azure
- Je fais un RDP vers la VM Windows
- Depuis celle-ci, je ping les VMs Linux par leur nom DNS
- J’ouvre les sites Apache via Edge en utilisant les URLs DNS
- Je valide que tout est interconnecté et fonctionnel
➡️ Preuve que l’automatisation Terraform remplace avantageusement les déploiements manuels.
📈 Bonnes pratiques mises en œuvre
| Pratique | Implémentation dans le projet |
|---|---|
| Infrastructure as Code | ☑️ 100% Terraform |
| Dynamisme & Extensibilité | ☑️ Ajouter une région ? Juste modifier la map vnets |
| Sécurité réseau | ☑️ NSG conditionnels, pas de ports inutiles ouverts |
| Gestion des coûts | ☑️ Spot VM pour les environnements non prod |
| Naming convention | ☑️ rg-{region}, vnet-{region}, vm-{os}-{region} |
| Résolution de noms | ☑️ Private DNS Zone + enregistrements A dynamiques |
| Évitement de count | ☑️ for_each utilisé partout |
| Documentation implicite | ☑️ Variables bien typées + descriptions |
| Sécurité des secrets | ☑️ admin_password marqué comme sensitive |
| Reproductibilité | ☑️ terraform destroy puis apply → même résultat |
🚧 Limites & Axes d’amélioration
| Ce que j’ai fait | Ce qu’on ferait en production |
|---|---|
Mot de passe en clair dans tfvars |
➤ Azure Key Vault + azurerm_key_vault_secret |
| Accès RDP depuis Internet | ➤ Azure Bastion ou P2S VPN |
| Pas de CI/CD | ➤ Pipeline GitHub Actions pour apply auto sur PR merge |
| Pas de monitoring | ➤ Azure Monitor + alertes sur uptime VM |
| Pas de backup | ➤ Azure Backup pour les disques OS/data |
| Script IIS basique | ➤ DSC ou Ansible pour une configuration plus robuste |
| Pas de tests automatisés | ➤ Terratest pour valider la connectivité cross-région |
📚 Sources & Inspirations
- Microsoft Learn - VNet Peering
- Microsoft Learn - Private DNS Zones
- HashiCorp Learn - Dynamic Blocks
- Azure Spot VMs Documentation
🧑💻 Pourquoi ce projet compte pour mon profil d’ingénieur cloud
“Ce projet n’est pas juste un lab technique. C’est une démonstration concrète de ma capacité à :”
- ☑️ Concevoir des architectures multi-région complexes avec Terraform
- ☑️ Maîtriser les fonctions avancées de HCL (setproduct, merge, templatefile)
- ☑️ Automatiser des scénarios réalistes d’entreprise (interconnexion, DNS, sécurité)
- ☑️ Optimiser les coûts sans sacrifier la fonctionnalité (Spot VMs)
- ☑️ Produire du code propre, maintenable, et extensible
- ☑️ Documenter rigoureusement mes choix techniques → valeur ajoutée pour les équipes
📎 Annexes
🧠 Ce que j’ai appris grâce à ce projet
“L’automatisation révèle les failles invisibles en manuel.”
- Maîtriser setproduct() pour générer des combinaisons (ici, peerings full-mesh)
- Comprendre les limites des for_each imbriqués → solution avec merge([…])
- Gérer les dépendances implicites (ex: DNS records après création des VMs → depends_on)
- Utiliser try() pour éviter les erreurs si une ressource n’existe pas encore
- La puissance du templatefile() pour injecter du contexte dans les scripts
- L’importance de la convention de nommage des clés (“${region}-${subnet}”) pour référencer facilement les ressources
➡️ Ce projet confirme ma transition vers un ingénieur cloud capable de concevoir, automatiser, et industrialiser des architectures multi-région sécurisées.