Tous les projets

Déploiement d’une architecture AWS à 3 niveaux avec Terraform

Infrastructure AWS à trois niveaux (web, applicatif, données) répartie sur deux zones de disponibilité et entièrement décrite avec Terraform.

Date
12 octobre 2026
Code source
3-tiers-architecture
Auteur
Eyanam TCHALIM

Contexte et objectifs

Ce projet met en place une infrastructure AWS en architecture 3-tiers (web, applicatif, données), décrite et déployée entièrement avec Terraform, afin qu’elle soit hautement disponible, sécurisée et reproductible.

Objectifs, vérifiables dans le code :

Architecture

Le trafic traverse trois niveaux dupliqués sur deux zones de disponibilité, et seul l’ALB public est exposé à Internet.

Schéma d’architecture : Internet, WAF et Internet Gateway mènent à un Application Load Balancer public. Dans un VPC réparti sur les zones us-east-1a et us-east-1b, la couche web (EC2 en Auto Scaling dans des sous-réseaux publics, avec NAT Gateways) envoie le trafic vers un ALB interne, qui dessert la couche application (EC2 en Auto Scaling dans des sous-réseaux privés), puis la couche données (Amazon RDS en réplication entre les deux zones).
Figure 1 – Architecture 3-tiers : WAF, ALB public, niveaux web, applicatif et données sur deux zones
Trois niveaux sur deux zones, avec un seul point d’entrée public : Internet, Internet Gateway et ALB public protégé par le WAF, puis dans chaque zone un sous-réseau public (instances web et NAT Gateway), un ALB interne, un sous-réseau applicatif et un sous-réseau de données avec RDS MySQL en réplication entre les deux zones.
Figure 2 – Architecture 3-tiers : 2 zones de disponibilité, 6 sous-réseaux

Les flèches pleines suivent le chemin d’une requête : Internet Gateway, ALB public (protégé par le WAF), instances web, ALB interne, instances applicatives, puis base de données. La région par défaut est us-east-1.

Plan d’adressage

Sous-réseauNiveauZonePlage CIDR
public_1Web (public)110.0.1.0/24
public_2Web (public)210.0.2.0/24
app_1Applicatif (privé)110.0.11.0/24
app_2Applicatif (privé)210.0.12.0/24
data_1Données (privé)110.0.21.0/24
data_2Données (privé)210.0.22.0/24

Le VPC utilise la plage 10.0.0.0/16 ; toutes ces plages sont des variables Terraform.

Routage

Services AWS utilisés

L’infrastructure repose sur dix services ou composants AWS, tous créés par Terraform ; les valeurs ci-dessous sont celles par défaut du fichier de variables.

ServiceRôle dans le projetRéglage clé
VPC, Internet Gateway, NAT GatewayRéseau isolé et sorties vers InternetVPC 10.0.0.0/16, six sous-réseaux, une NAT Gateway par zone
Application Load Balancer publicPoint d’entrée unique depuis InternetÉcoute HTTP sur le port 80, sous-réseaux publics, contrôle de santé sur /
Application Load Balancer interneRépartition du trafic vers le niveau applicatifPort 8080, sous-réseaux applicatifs, contrôle de santé sur /health
AWS WAFv2Filtrage des attaques web sur l’ALB publicQuatre groupes de règles gérées AWS et une limitation de débit par IP
EC2 et Auto Scaling (web)Niveau webt3.micro, Amazon Linux 2023 avec Apache, 2 à 4 instances (2 souhaitées), sous-réseaux publics
EC2 et Auto Scaling (applicatif)Niveau applicatift3.micro, 2 à 4 instances (2 souhaitées), sous-réseaux applicatifs
RDS MySQL 8.0Base de données relationnelledb.t3.micro, 20 Go, Multi-AZ, stockage chiffré, sauvegardes sur 7 jours, non publique
Groupes de sécuritéFiltrage en cascade entre niveauxCinq groupes, un par composant
CloudWatchJournaux du WAF et alarmeRétention de 90 jours, alarme sur les requêtes bloquées
Systems Manager (paramètre SSM)Image système toujours à jourDernière AMI Amazon Linux 2023 lue au déploiement

Sécurité

La sécurité repose sur une cascade de groupes de sécurité : chaque niveau n’accepte du trafic que depuis celui qui le précède, et seul l’ALB public reçoit du trafic d’Internet.

Flux autorisés

SourceDestinationPort
InternetALB public80 et 443
ALB publicInstances web80
Instances webALB interne8080
ALB interneInstances applicatives8080
Instances applicativesBase de données3306 (MySQL)

Au-delà du premier flux, les règles désignent le groupe de sécurité du niveau précédent plutôt qu’une plage d’adresses : elles restent valables même si les adresses changent.

Pare-feu applicatif (WAF)

Une Web ACL WAFv2 est associée à l’ALB public. Elle autorise le trafic par défaut et applique, dans l’ordre :

Les journaux du WAF vont dans CloudWatch Logs avec une rétention de 90 jours, et une alarme se déclenche si plus de 100 requêtes sont bloquées sur 5 minutes.

Données et secrets

Fiabilité et performance

Chaque niveau est dupliqué sur deux zones de disponibilité, de sorte que la perte d’une zone laisse l’autre en service.

NiveauMécanisme de résilience
EntréeL’ALB public est déployé dans les deux sous-réseaux publics
WebUn groupe Auto Scaling réparti sur les deux sous-réseaux publics, minimum 2 instances
ApplicatifUn ALB interne et un groupe Auto Scaling répartis sur les deux sous-réseaux applicatifs, minimum 2 instances
Sorties InternetUne NAT Gateway par zone, avec sa propre table de routage
DonnéesRDS Multi-AZ : une instance de secours dans l’autre zone, avec bascule automatique

Mise en œuvre

Le code est découpé en huit fichiers, un par domaine fonctionnel, pour faciliter la lecture, la maintenance et les revues.

FichierContenu
providers.tfTerraform 1.5.0 ou plus, fournisseur AWS en version 5.x, région, étiquettes par défaut, zones de disponibilité, AMI Amazon Linux 2023 lue dans SSM
variables.tfRégion, nom d’environnement, plages CIDR, paramètres du WAF, tailles et capacités des niveaux, paramètres de la base, avec une validation sur le mot de passe
network.tfVPC, Internet Gateway, six sous-réseaux, deux NAT Gateways, tables de routage
security.tfCinq groupes de sécurité, Web ACL WAFv2, journaux et alarme
web-tier.tfALB public, groupe cible, écouteur HTTP, modèle de lancement, groupe Auto Scaling, association du WAF
app-tier.tfALB interne, groupe cible, écouteur sur le port 8080, modèle de lancement, groupe Auto Scaling
database.tfGroupe de sous-réseaux et instance RDS MySQL
outputs.tfIdentifiants du VPC et des sous-réseaux, des NAT Gateways, ARN de la Web ACL, noms DNS des deux ALB, point d’accès et port de la base

Toutes les valeurs variables sont des variables Terraform avec une valeur par défaut, sauf le mot de passe de la base. Un même code peut donc servir pour dev, staging et production en changeant environment_name et les tailles. Chaque ressource est nommée et étiquetée à partir de ce préfixe, avec l’étiquette ManagedBy = terraform.

Déploiement

Le déploiement suit le flux Terraform standard, depuis le répertoire qui contient les fichiers .tf. Le mot de passe de la base est passé par une variable d’environnement :

Terminal
export TF_VAR_db_password='<mot-de-passe-d-au-moins-8-caracteres>'

terraform init                # télécharge le fournisseur AWS
terraform plan -out=tfplan    # affiche le plan sans rien appliquer
terraform apply tfplan        # applique le plan validé

Pour supprimer l’environnement après une démonstration, terraform destroy retire toutes les ressources ; l’instantané final de la base est conservé.

Extrait : la base de données

database.tf (extrait)
multi_az                = true   # bascule automatique en cas de défaillance
backup_retention_period = 7      # sauvegardes automatiques sur 7 jours
storage_encrypted       = true   # chiffrement du stockage
publicly_accessible     = false  # aucune exposition à Internet
skip_final_snapshot     = false  # instantané final conservé à la suppression

Le bloc commenté dans providers.tf propose un état distant dans S3 avec verrouillage DynamoDB, recommandé dès que plusieurs personnes ou une production sont concernées.

Coûts et optimisation

En fonctionnement permanent, la configuration par défaut coûte environ 186 $ par mois avant trafic ; les NAT Gateways en représentent plus d’un tiers, et détruire l’environnement hors des périodes d’utilisation est le levier le plus efficace.

Estimation des coûts

Hypothèses : région us-east-1, 730 heures par mois, tarifs à la demande relevés le 12 octobre 2026, configuration par défaut du fichier de variables, sans trafic.

PosteCalculProduction (par défaut)Test allégé
NAT Gateways0,045 $/h par passerelle65,70 $ (2)32,85 $ (1)
Load balancers (public et interne)0,0225 $/h chacun32,85 $32,85 $
RDS MySQL db.t3.micro0,017 $/h, doublé en Multi-AZ24,82 $ (Multi-AZ)12,41 $ (une zone)
Instances EC2 t3.micro0,0104 $/h par instance30,37 $ (4)15,18 $ (2)
Adresses IPv4 publiques0,005 $/h par adresse21,90 $ (6)14,60 $ (4)
WAF5 $ la Web ACL + environ 1 $ par règle10,00 $10,00 $
Total mensuelenviron 186 $environ 118 $

Les six adresses IPv4 de la colonne Production se répartissent ainsi : deux pour les NAT Gateways, deux pour l’ALB public (une par zone) et deux pour les instances web, qui reçoivent une adresse publique dans les sous-réseaux publics.

Coûts variables non inclus : traitement des données par les NAT Gateways (0,045 $ par Go), capacités des load balancers (LCU), requêtes inspectées par le WAF (0,60 $ par million), stockage disque des instances et de la base, sauvegardes au-delà de l’espace inclus, journaux CloudWatch. Les tarifs proviennent de la page officielle du WAF et de sources tierces qui reprennent les tarifs AWS ; confirmez-les avec l’AWS Pricing Calculator avant de publier des montants.

Suivi des coûts

Solutions de réduction, avec leur compromis

LevierEffetCompromis
Détruire l’environnement hors démonstration (terraform destroy)Supprime tous les coûts fixes ; l’instantané final de la base reste conservéIl faut recréer l’environnement avant chaque utilisation
Une seule NAT Gateway en testÉconomise environ 33 $ par moisPlus aucune redondance sur les sorties Internet, et du trafic entre zones
RDS en une seule zone en testDivise par deux le coût de la basePas de bascule automatique
Une instance par niveau en test (web_min_size, app_min_size)Économise la moitié du coût EC2Aucune redondance dans le niveau
Savings Plans en productionEnviron 28 % de moins sur une instance t3.micro avec un engagement d’un anEngagement sur la durée
Retirer la route vers la NAT des sous-réseaux de donnéesRéduit le trafic traité par la NAT et la surface d’expositionLa base ne peut plus joindre Internet, ce qui n’est pas nécessaire pour RDS
Points de terminaison VPCLe point de terminaison S3 de type passerelle est gratuit et évite du trafic NATLes points de terminaison de type interface sont facturés à l’heure
Instances web en sous-réseaux privésSupprime deux adresses IPv4 publiques et réduit l’expositionLeur sortie passe par la NAT
Rétention des journaux WAF à 30 jours (log_retention_in_days)Réduit le stockage CloudWatchHistorique plus court

Compromis coût et résilience

Le projet choisit de payer la haute disponibilité : deux NAT Gateways, une base Multi-AZ et deux instances par niveau représentent environ 68 $ par mois de plus que le profil de test. Ce choix se défend en production, mais pas pour un environnement de démonstration, d’où l’intérêt d’externaliser ces paramètres en variables.

Résultats

Le code et l’état Terraform confirment un déploiement complet de l’architecture : 46 ressources gérées, réparties sur deux zones, avec les paramètres de résilience attendus.

Point vérifiéConstatSource
Ressources déployées46 ressources gérées et 3 sources de donnéesSauvegarde de l’état Terraform
Répartition par niveauDeux sous-réseaux par niveau, un dans chaque zonenetwork.tf
Base de donnéesMySQL 8.0, Multi-AZ, stockage chiffré, sauvegardes sur 7 jours, non publiqueÉtat Terraform et database.tf
Capacité des niveauxWeb et applicatif : 2 à 4 instances, 2 souhaitéesÉtat Terraform (groupes Auto Scaling)
Exposition à InternetUn seul point d’entrée : l’ALB public, derrière le WAFsecurity.tf et web-tier.tf
Sorties produites10 sorties : VPC, sous-réseaux, NAT Gateways, Web ACL, noms DNS des ALB, point d’accès de la baseoutputs.tf
Fin de vieL’état courant ne contient plus aucune ressource : l’environnement a été détruit après les essaisterraform.tfstate

Ces constats portent sur la configuration et l’état Terraform. Les fichiers fournis ne contiennent aucune mesure de performance, de charge ou de bascule : ajoutez-en (test de charge, exercice de bascule Multi-AZ) pour étayer les objectifs de disponibilité.

Enseignements et évolutions

Le projet atteint son objectif de base, mais la lecture du code laisse huit points à durcir avant une utilisation en production.

Enseignements

Limites constatées et pistes d’amélioration

Limite constatée dans le codePiste d’amélioration
L’état local terraform.tfstate contient le mot de passe de la base en clairNe jamais le versionner (l’ajouter à .gitignore), activer l’état distant chiffré du bloc commenté de providers.tf, et laisser RDS gérer le mot de passe dans Secrets Manager
L’ALB public n’a qu’un écouteur HTTP, alors que le groupe de sécurité ouvre déjà le port 443Ajouter un écouteur HTTPS avec un certificat ACM et rediriger le port 80 vers 443
Le modèle de lancement du niveau applicatif écrit seulement un fichier de journal : rien n’écoute sur le port 8080 ni sur /healthDéployer l’application (image, script de démarrage ou conteneur) pour que les contrôles de santé réussissent
Les groupes Auto Scaling utilisent le contrôle EC2 et n’ont aucune politique de mise à l’échellePasser le contrôle de santé en mode ELB et ajouter une politique de suivi de cible (CPU ou requêtes par cible)
Les sous-réseaux de données sont routés vers la NAT Gateway, alors que le code les décrit comme isolésLeur donner une table de routage sans route par défaut
Tous les groupes de sécurité laissent sortir tout le traficRestreindre le trafic sortant aux destinations nécessaires
Les instances web ont une adresse publique et aucun moyen d’administration (ni clé SSH, ni profil d’instance)Les placer en sous-réseaux privés et leur associer un profil d’instance pour Systems Manager Session Manager
L’instantané final de la base porte un nom fixe : une seconde suppression échouera si cet instantané existe déjàUtiliser un identifiant horodaté

Évolutions