# ☁️ Multi-cloud reference (AWS + Azure) — Terraform **Format** : Terraform (.tf) · 3 providers · workspaces strategy **Auteur** : Équipe pédagogique ITAG · DevOps Pack **Mise à jour** : 2026 --- ## 🎯 Description Pattern de référence pour un déploiement multi-cloud (AWS + Azure + GCP) avec Terraform. Workspaces, remote state (S3 + DynamoDB lock), modules abstraits, IAM least-privilege transversal. ## 📋 Contenu ### Architecture cible - **AWS** : VPC, EKS, RDS, S3 - **Azure** : VNet, AKS, Azure SQL, Storage Account - **GCP** : VPC, GKE, Cloud SQL, GCS ### Modules abstraits - `module/network/` — interface uniforme (vpc_id, subnet_ids, cidr) - `module/k8s/` — wrapper EKS / AKS / GKE - `module/db/` — wrapper RDS / Azure SQL / Cloud SQL - `module/storage/` — S3 / Blob / GCS ### Remote state - Backend S3 + DynamoDB lock (cross-cloud accessible) - Workspaces : `dev`, `staging`, `prod` - State outputs partagés via `terraform_remote_state` ### IAM cross-cloud - AWS : OIDC trust pour GitHub Actions - Azure : Federated identity credential - GCP : Workload Identity Federation - Pas de keys long-lived → tout via OIDC ## 💾 Code Terraform complet ### providers.tf ```hcl terraform { required_version = ">= 1.6" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } azurerm = { source = "hashicorp/azurerm" version = "~> 3.0" } } } provider "aws" { region = var.aws_region default_tags { tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" Cloud = "AWS" } } } provider "azurerm" { features {} # Définir ARM_SUBSCRIPTION_ID, ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID # en variables d'environnement ou via un service principal } ``` ### main.tf ```hcl # ════════════════════════════════════════════════════════════════════════════ # AWS — RÉSEAU # ════════════════════════════════════════════════════════════════════════════ resource "aws_vpc" "main" { cidr_block = "10.1.0.0/16" enable_dns_hostnames = true enable_dns_support = true tags = { Name = "${var.project_name}-${var.environment}-vpc" } } resource "aws_subnet" "aws_main" { vpc_id = aws_vpc.main.id cidr_block = "10.1.1.0/24" availability_zone = "${var.aws_region}a" tags = { Name = "${var.project_name}-${var.environment}-subnet" } } # ════════════════════════════════════════════════════════════════════════════ # AWS — STOCKAGE S3 # ════════════════════════════════════════════════════════════════════════════ resource "aws_s3_bucket" "main" { bucket = var.aws_bucket_name tags = { Name = var.aws_bucket_name Environment = var.environment } } resource "aws_s3_bucket_versioning" "main" { bucket = aws_s3_bucket.main.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_server_side_encryption_configuration" "main" { bucket = aws_s3_bucket.main.id rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } } resource "aws_s3_bucket_public_access_block" "main" { bucket = aws_s3_bucket.main.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } # ════════════════════════════════════════════════════════════════════════════ # AZURE — GROUPE DE RESSOURCES # ════════════════════════════════════════════════════════════════════════════ resource "azurerm_resource_group" "main" { name = var.azure_rg_name location = var.azure_location tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" Cloud = "Azure" } } # ════════════════════════════════════════════════════════════════════════════ # AZURE — RÉSEAU # ════════════════════════════════════════════════════════════════════════════ resource "azurerm_virtual_network" "main" { name = "${var.project_name}-${var.environment}-vnet" address_space = ["10.2.0.0/16"] location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name tags = { Environment = var.environment ManagedBy = "Terraform" } } resource "azurerm_subnet" "main" { name = "${var.project_name}-${var.environment}-subnet" resource_group_name = azurerm_resource_group.main.name virtual_network_name = azurerm_virtual_network.main.name address_prefixes = ["10.2.1.0/24"] } # ════════════════════════════════════════════════════════════════════════════ # AZURE — STOCKAGE # ════════════════════════════════════════════════════════════════════════════ resource "azurerm_storage_account" "main" { name = lower(replace("${var.project_name}${var.environment}sa", "-", "")) resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location account_tier = "Standard" account_replication_type = "LRS" min_tls_version = "TLS1_2" blob_properties { versioning_enabled = true } tags = { Environment = var.environment ManagedBy = "Terraform" } } resource "azurerm_storage_container" "main" { name = "${var.project_name}-${var.environment}-container" storage_account_name = azurerm_storage_account.main.name container_access_type = "private" } ``` ### variables.tf ```hcl variable "aws_region" { description = "AWS region for resource deployment" type = string default = "us-east-1" } variable "azure_location" { description = "Azure region for resource deployment" type = string default = "West Europe" } variable "project_name" { description = "Project name used as prefix for all resources" type = string default = "multicloud-demo" } variable "environment" { description = "Deployment environment (dev / staging / prod)" type = string default = "dev" validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "environment must be one of: dev, staging, prod." } } variable "aws_bucket_name" { description = "Globally unique name for the AWS S3 bucket" type = string default = "myapp-assets-dev-2026" } variable "azure_rg_name" { description = "Name of the Azure Resource Group" type = string default = "myapp-dev-rg" } ``` ### outputs.tf ```hcl output "aws_vpc_id" { description = "ID of the AWS VPC" value = aws_vpc.main.id } output "aws_bucket_arn" { description = "ARN of the AWS S3 bucket" value = aws_s3_bucket.main.arn } output "aws_bucket_name" { description = "Name of the AWS S3 bucket" value = aws_s3_bucket.main.bucket } output "azure_rg_id" { description = "ID of the Azure Resource Group" value = azurerm_resource_group.main.id } output "azure_storage_account_name" { description = "Name of the Azure Storage Account" value = azurerm_storage_account.main.name } output "azure_vnet_id" { description = "ID of the Azure Virtual Network" value = azurerm_virtual_network.main.id } ``` ### backend.tf ```hcl # ── REMOTE STATE S3 (décommenter pour activer) ──────────────────────────────── # terraform { # backend "s3" { # bucket = "mon-terraform-state-bucket" # key = "multicloud/terraform.tfstate" # region = "us-east-1" # encrypt = true # dynamodb_table = "terraform-locks" # table DynamoDB pour les locks # } # } # # Créer la table DynamoDB avec le CLI avant d'initialiser : # aws dynamodb create-table \ # --table-name terraform-locks \ # --attribute-definitions AttributeName=LockID,AttributeType=S \ # --key-schema AttributeName=LockID,KeyType=HASH \ # --billing-mode PAY_PER_REQUEST \ # --region us-east-1 ``` ## 💼 Cas d'usage - Stratégie multi-cloud pour grand compte - DR (disaster recovery) cross-cloud - Vendor lock-in mitigation - Préparation Terraform Pro certification ## 📥 Télécharger ce template [Télécharger le fichier .md](/templates/view.php?file=terraform-multi-cloud&dl=1) · [← Catalogue Terraform](/templates.php?cat=terraform) · [Parcours DevOps →](/parcours/tech-devops.php) --- *ITAG · Non-affiliés HashiCorp / AWS / Microsoft / Google.*