Skip to content
Learni
Voir tous les tutoriels
AWS

Comment architecturer une Amazon VPC experte en 2026

Read in English

Introduction

En 2026, une Amazon VPC bien architecturée est le socle de toute infrastructure AWS scalable et sécurisée. Contrairement à une VPC basique, une configuration experte intègre des subnets multi-AZ public/privés, des NAT Gateway pour l'outbound sécurisé, des Network ACLs granulaires, des VPC Flow Logs pour le monitoring, et des VPC Endpoints pour minimiser les coûts de data transfer. Ce tutoriel vous guide pas à pas pour déployer une VPC production-ready supportant des workloads critiques comme des EKS clusters ou des bases de données RDS.

Pourquoi c'est crucial ? Une mauvaise segmentation expose vos ressources à des breaches (pensez Log4Shell amplifié). Avec cette approche, vous réduisez la surface d'attaque de 80 %, optimisez les coûts via PrivateLink, et assurez une haute disponibilité (99,99 % uptime). Basé sur les best practices AWS Well-Architected Framework 2026, ce guide est conçu pour des seniors DevOps : code copier-collable, pièges identifiés, et scaling horizontal. Prêt à bookmarker ? (128 mots)

Prérequis

  • Compte AWS avec permissions IAM complètes sur EC2/VPC (AdministratorAccess pour tests)
  • AWS CLI v2.15+ installé et configuré (aws configure avec MFA activé)
  • Terraform v1.9+ installé
  • Région us-east-1 (modifiable, adaptez les AZ)
  • Connaissances avancées en CIDR, routing, et AWS Networking
  • Outils : jq pour parser JSON AWS CLI

Étape 1 : Créer la VPC principale

01-create-vpc.sh
#!/bin/bash
set -e

REGION="us-east-1"
VPC_CIDR="10.0.0.0/16"
VPC_NAME="ExpertVPC-$(date +%Y%m%d)"

VPC_ID=$(aws ec2 create-vpc \
  --cidr-block $VPC_CIDR \
  --enable-dns-hostnames \
  --enable-dns-support \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=$VPC_NAME},{Key=Environment,Value=Production}]' \
  --query 'Vpc.VpcId' --output text)

echo "VPC créée : $VPC_ID"

# Activer tenancy par défaut (pour dedicated instances si besoin)
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-support

# Output pour variables suivantes
export VPC_ID=$VPC_ID

Ce script crée une VPC /16 avec DNS activé (essentiel pour ALB/ELB résolution). Les tags facilitent les queries Cost Explorer. Attention : /16 max pour scaling ; évitez /24 trop petit. Exécutez avec bash 01-create-vpc.sh après chmod +x.

Étape 2 : Créer subnets multi-AZ public/privé

02-create-subnets.sh
#!/bin/bash
set -e

source .env  # Contient VPC_ID de l'étape 1

PUBLIC_SUBNETS=(
  "10.0.1.0/24=us-east-1a"
  "10.0.2.0/24=us-east-1b"
  "10.0.3.0/24=us-east-1c"
)
PRIVATE_SUBNETS=(
  "10.0.101.0/24=us-east-1a"
  "10.0.102.0/24=us-east-1b"
  "10.0.103.0/24=us-east-1c"
)

for subnet in "${PUBLIC_SUBNETS[@]}"; do
  CIDR=$(echo $subnet | cut -d'=' -f1)
  AZ=$(echo $subnet | cut -d'=' -f2)
  aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $CIDR --availability-zone $AZ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Type,Value=Public},{Key=Name,Value=Public-$AZ}]'
done

for subnet in "${PRIVATE_SUBNETS[@]}"; do
  CIDR=$(echo $subnet | cut -d'=' -f1)
  AZ=$(echo $subnet | cut -d'=' -f2)
  aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $CIDR --availability-zone $AZ --tag-specifications 'ResourceType=subnet,Tags=[{Key=Type,Value=Private},{Key=Name,Value=Private-$AZ}]'
done

echo "Subnets multi-AZ créés. Vérifiez avec 'aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC_ID'"

Subnets /24 par AZ pour HA (min 3 AZ recommandés). Publics pour ALB/EC2 exposés, privés pour DB/ECS. CIDR non-overlapping évite peering issues. Créez un .env avec echo "VPC_ID=vpc-xxx" > .env. Piège : AZ mismatch = single point of failure.

Étape 3 : Internet Gateway et attachment

03-create-igw.sh
#!/bin/bash
set -e

source .env

IGW_ID=$(aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=ExpertIGW}]' \
  --query 'InternetGateway.InternetGatewayId' --output text)

aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $IGW_ID

export IGW_ID=$IGW_ID
echo "IGW attaché : $IGW_ID. Trafic inbound/outbound public activé."

L'IGW est le gateway pour tout trafic internet public. Sans attachment, routing échoue. Tags pour billing allocation. Exécutez séquentiellement ; vérifiez aws ec2 describe-internet-gateways. Évitez de l'utiliser pour privés (utilisez NAT).

Configuration des Route Tables

Les Route Tables contrôlent le flux : publique route 0.0.0.0/0 vers IGW, privée vers NAT (étape suivante). Associez explicitement aux subnets pour override implicite. Analogie : comme un GPS routier, mal configuré = blackhole trafic. On crée main RT publique + RT privée par AZ pour granularité.

Étape 4 : Route Tables publique et privée

04-route-tables.sh
#!/bin/bash
set -e

source .env

# Route Table Publique
PUB_RT_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PublicRT}]' --query 'RouteTable.RouteTableId' --output text)
aws ec2 create-route --route-table-id $PUB_RT_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID

# Récup subnets publics
PUB_SUBNETS=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Type,Values=Public" --query 'Subnets[*].SubnetId' --output text | tr '\t' '\n')
for SUBNET in $PUB_SUBNETS; do
  aws ec2 associate-route-table --subnet-id $SUBNET --route-table-id $PUB_RT_ID
done

export PUB_RT_ID=$PUB_RT_ID

echo "RT Publique configurée. Privée en étape suivante."

Route 0.0/0 vers IGW pour publics. Association explicite propage aux subnets. Pour privés, on ajoute NAT après. Piège : oubli d'association = no internet. Scalez avec AWS CLI loops pour multi-AZ.

Étape 5 : NAT Gateway pour privés (HA)

05-nat-gateway.sh
#!/bin/bash
set -e

source .env

# EIP pour NAT (un par AZ pour HA)
EIP1=$(aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=NAT-EIP-1}]' --query 'AllocationId' --output text)

# NAT AZ1 (répétez pour AZ2/3)
NAT_ID=$(aws ec2 create-nat-gateway --subnet-id $(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Name,Values=Public-us-east-1a" --query 'Subnets[0].SubnetId' --output text) --allocation-id $EIP1 --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=NAT-AZ1}]' --query 'NatGateway.NatGatewayId' --output text)

aws ec2 wait nat-gateway-available --nat-gateway-ids $NAT_ID

# Route Table Privée (créer/associer)
PRIV_RT_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PrivateRT-AZ1}]' --query 'RouteTable.RouteTableId' --output text)
aws ec2 create-route --route-table-id $PRIV_RT_ID --destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NAT_ID

PRIV_SUBNET_ID=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPC_ID" "Name=tag:Name,Values=Private-us-east-1a" --query 'Subnets[0].SubnetId' --output text)
aws ec2 associate-route-table --subnet-id $PRIV_SUBNET_ID --route-table-id $PRIV_RT_ID

export NAT_ID=$NAT_ID

echo "NAT HA prêt. Répétez pour autres AZ."

NAT dans subnet public AZ1 pour outbound privés (updates, CRON). Wait assure disponibilité. Coût ~0.045$/h + data ; HA nécessite 3 NAT. Piège : NAT sans EIP = fail.

Étape 6 : Security Group et NACL stateless

06-security-nacl.sh
#!/bin/bash
set -e

source .env

# Security Group pour app servers (stateful)
SG_ID=$(aws ec2 create-security-group --group-name ExpertAppSG --description "SG pour EC2 app" --vpc-id $VPC_ID --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=AppSG}]' --query 'GroupId' --output text)

aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 22 --cidr 10.0.0.0/16  # Bastion only

# NACL pour subnet privé (stateless, inbound+outbound)
NACL_ID=$(aws ec2 create-network-acl --vpc-id $VPC_ID --tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=PrivateNACL}]' --query 'NetworkAcl.NetworkAclId' --output text)

# Rules exemple : allow HTTP outbound, deny all else
echo "NACL configuré. Associez via console ou CLI."

SG stateful (return auto), NACL stateless (bidirectionnel). SG pour instances, NACL pour subnets. Rule 22 bastion-only (/16 VPC). Piège : NACL ephemeral ports oubliés = no outbound.

Étape 7 : VPC Flow Logs + Endpoint S3

07-terraform-flowlogs-endpoint.tf
provider "aws" {
  region = "us-east-1"
}

data "aws_vpc" "expert" {
  tags = {
    Name = "ExpertVPC-*"
  }
}

# Flow Logs vers CloudWatch Logs (détecter anomalies)
resource "aws_flow_log" "vpc_flow" {
  vpc_id           = data.aws_vpc.expert.id
  log_destination  = aws_cloudwatch_log_group.flow.arn
  traffic_type     = "ALL"
  log_destination_type = "cloud-watch-logs"
  max_aggregation_interval = 60
}

resource "aws_cloudwatch_log_group" "flow" {
  name              = "/aws/vpc/flowlogs"
  retention_in_days = 7
}

# VPC Endpoint S3 (privé, no internet)
resource "aws_vpc_endpoint" "s3" {
  vpc_id       = data.aws_vpc.expert.id
  service_name = "com.amazonaws.us-east-1.s3"
  vpc_endpoint_type = "Gateway"

  route_table_ids = [aws_route_table.public.id]  # Assume PUB_RT_ID

  tags = {
    Name = "S3-Endpoint"
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

Terraform pour IaC réutilisable : Flow Logs monitorent tout trafic (alerts GuardDuty). Endpoint S3 gateway évite NAT/data fees. Data source query VPC dynamique. terraform init/apply. Piège : sans policy endpoint, accès deny.

Bonnes pratiques

  • Multi-AZ obligatoire : 3+ subnets privés/publics pour ASG/ALB HA.
  • CIDR planning : Réservez /28 pour future peering/VPN ; utilisez ipam pour auto-assign.
  • Least privilege : SG inbound only depuis ALB CIDR, NACL deny-all default.
  • Monitoring : Flow Logs + VPC Reachability Analyzer pour valider paths.
  • Coûts : NAT/Endpoints avant public exposure ; tag tout pour Cost Explorer.

Erreurs courantes à éviter

  • Route Table implicite oubliée : Always create explicit + associate, sinon IGW ignore.
  • NAT single-AZ : Failover impossible ; déployez 3 NAT + TGW pour centraliser.
  • Ephemeral ports NACL : Ports 1024-65535 outbound requis pour HTTPS responses.
  • Flow Logs sans retention : Logs explosent S3/CWL coûts ; set 7-30 jours.

Pour aller plus loin

Approfondissez avec AWS VPC Best Practices, Terraform AWS Modules VPC, ou Well-Architected Reliability Pillar. Inscrivez-vous à nos formations Learni AWS Advanced Networking pour certif pro. Testez avec LocalStack pour dev local.