☁️ 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 / GKEmodule/db/— wrapper RDS / Azure SQL / Cloud SQLmodule/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
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
# ════════════════════════════════════════════════════════════════════════════
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
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
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
# ── 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 · ← Catalogue Terraform · Parcours DevOps →
ITAG · Non-affiliés HashiCorp / AWS / Microsoft / Google.