Une instance AWS EC2 mal configurée reste l’une des portes d’entrée les plus fréquentes pour les attaquants sur le cloud. Selon le rapport Unit 42 Cloud Threat Report (Palo Alto Networks), sur plus de 680 000 identités analysées dans 18 000 comptes cloud, 99 % disposaient de permissions excessives jamais utilisées. Et l’incident Capital One de 2019, encore cité comme cas d’école dans les formations de sécurité cloud en 2025, montre comment une simple faille SSRF combinée à un accès IMDSv1 non protégé a permis d’exfiltrer les données de près de 100 millions de clients via un rôle IAM trop permissif.
Ce tutoriel vous guide pas à pas pour déployer un serveur EC2 en partant d’une base saine plutôt que de sécuriser après coup. Vous allez créer un VPC dédié, un security group minimal, un rôle IAM sans clé d’accès stockée en dur, forcer IMDSv2 dès le lancement, durcir le système d’exploitation et chiffrer le trafic avec Let’s Encrypt. Comptez environ 90 minutes pour suivre les 12 étapes, avec un projet Terraform complet à la fin pour tout reproduire en une commande. La région utilisée est Paris (eu-west-3), et les prix affichés datent de septembre 2026.
Pourquoi sécuriser une instance EC2 dès le lancement en 2026
Le rapport Cost of a Data Breach d’IBM (édition 2024) indique que 40 % des violations de données impliquaient des informations réparties sur plusieurs environnements, cloud public, cloud privé et infrastructure sur site combinés. Ce chiffre pèse directement sur AWS EC2, qui reste le service de calcul le plus utilisé de la plateforme et donc la cible la plus exposée. Le Verizon Data Breach Investigations Report 2025 classe par ailleurs la mauvaise configuration parmi les trois principales causes d’incident “erreur humaine” chez les PME, aux côtés des erreurs d’envoi et de publication de données.
Un exemple concret documenté par Unit 42 en 2024 : un groupe d’extorsion a exploité des fichiers .env exposés sur des serveurs web mal configurés, touchant environ 110 000 domaines. Les identifiants trouvés dans ces fichiers, souvent des clés d’accès AWS collées en dur dans le code, ont ensuite servi à pivoter vers des ressources cloud entières. Ce scénario se reproduit régulièrement avec EC2 quand une instance publique combine un rôle IAM trop large, un security group ouvert et l’absence de chiffrement du trafic.
La bonne nouvelle, c’est qu’AWS a durci ses valeurs par défaut ces deux dernières années. Depuis mars 2024, il est possible d’imposer IMDSv2 au niveau du compte entier, et toute nouvelle famille d’instance lancée depuis mi-2024 utilise IMDSv2 par défaut. Les images Amazon Linux 2023 imposent elles aussi IMDSv2 nativement. Ce tutoriel s’appuie sur ces protections plutôt que de les contourner, ce qui change concrètement la façon de construire une instance EC2 en 2026 par rapport à un tutoriel d’il y a cinq ans. Le livre blanc AWS Security Best Practices détaille l’ensemble du modèle de responsabilité partagée : AWS sécurise l’infrastructure physique et le matériel, mais la configuration du système d’exploitation, des règles réseau et des permissions reste entièrement de votre ressort.
Côté français, cette responsabilité partagée rejoint les recommandations publiées par l’agence nationale de la sécurité des systèmes d’information sur cyber.gouv.fr, qui insiste depuis plusieurs années sur le cloisonnement réseau, la limitation des accès administrateurs et le chiffrement systématique des flux exposés sur Internet. Les principes ne changent pas d’un fournisseur cloud à l’autre : ce sont les mêmes réflexes qui protègent une instance EC2, une VM Azure ou un serveur GCP.
Prérequis : comptes, outils et versions nécessaires
Avant de lancer la première commande, réunissez les éléments suivants. Aucun d’entre eux n’est payant en soi, mais l’utilisation d’EC2 elle-même sera facturée à l’heure dès que l’instance tourne, même en dehors du free tier. Gardez aussi à l’esprit la documentation officielle des concepts EC2 d’AWS si un terme du tutoriel (AMI, instance store, Elastic IP) ne vous est pas familier.
- Un compte AWS actif (une carte bancaire est demandée même pour rester dans le free tier)
- AWS CLI version 2, idéalement 2.32.0 ou plus récent pour bénéficier de l’authentification par identifiants de console. AWS CLI v1 est passé en mode maintenance le 5 août 2026 et sera non supporté à partir du 15 juillet 2027
- Un terminal Linux, macOS ou WSL avec OpenSSH installé
- Terraform (optionnel mais recommandé pour la dernière étape, la version récente disponible sur le site officiel de HashiCorp convient)
- Des bases en ligne de commande et en JSON
- Un budget de quelques centimes à quelques euros selon le type d’instance et la durée de test
Vérifiez votre version d’AWS CLI avant de commencer.
aws --version
# Sortie attendue (exemple) :
# aws-cli/2.36.43 Python/3.12.6 Linux/6.8.0 exe/x86_64.ubuntu.24
Étape 1 : sécuriser le compte racine AWS et activer le MFA
N’utilisez jamais le compte racine pour les opérations quotidiennes. Dans la console IAM, créez un utilisateur dédié avec des permissions administratives limitées, puis activez l’authentification à plusieurs facteurs (MFA) à la fois sur le compte racine et sur cet utilisateur. Générez ensuite une clé d’accès pour cet utilisateur, jamais pour le compte racine, et configurez un profil AWS CLI nommé pour ce tutoriel afin de ne pas toucher votre profil par défaut.
aws configure --profile ec2-tutoriel
AWS Access Key ID [None]: AKIAABCDEFGHIJKLMNOP
AWS Secret Access Key [None]: ****************************************
Default region name [None]: eu-west-3
Default output format [None]: json
Testez immédiatement que le profil fonctionne et qu’il correspond bien à l’utilisateur attendu, pas au compte racine.
aws sts get-caller-identity --profile ec2-tutoriel
# {
# "UserId": "AIDAABCDEFGHIJKLMNOP",
# "Account": "123456789012",
# "Arn": "arn:aws:iam::123456789012:user/ec2-tutoriel"
# }
Étape 2 : installer et configurer AWS CLI v2
Si vous démarrez d’une machine neuve, installez AWS CLI v2 via le paquet officiel de votre distribution ou l’installeur AWS. Sur macOS, un installeur universel gère nativement Apple Silicon comme Intel depuis la version 2.30.0. Une fois installé, définissez le profil créé à l’étape précédente comme profil par défaut de votre session de travail pour éviter de répéter --profile ec2-tutoriel à chaque commande.
export AWS_PROFILE=ec2-tutoriel
export AWS_DEFAULT_REGION=eu-west-3
aws ec2 describe-regions --region eu-west-3 --query "Regions[?RegionName=='eu-west-3']"
La France dispose de sa propre région AWS depuis plusieurs années (Paris, eu-west-3), l’une des huit régions européennes du fournisseur avec Francfort, Zurich, Stockholm, Milan, Madrid, Dublin et Londres. Héberger en eu-west-3 garde les données sur le territoire français, un point qui compte pour les entités soumises à des obligations de résidence des données.
Étape 3 : générer une clé SSH dédiée à l’instance
Ne réutilisez pas une clé SSH existante pour un serveur de production. Générez une paire Ed25519 dédiée, plus courte et plus rapide qu’une clé RSA à sécurité équivalente, puis importez la clé publique dans AWS plutôt que de laisser AWS générer la paire à votre place (ce qui évite de faire transiter la clé privée par les serveurs AWS). La documentation EC2 Key Pairs détaille les deux méthodes si vous préférez laisser AWS générer la clé côté console.
ssh-keygen -t ed25519 -f ~/.ssh/ec2-tutoriel -C "ec2-tutoriel-2026"
aws ec2 import-key-pair \
--key-name ec2-tutoriel \
--public-key-material fileb://~/.ssh/ec2-tutoriel.pub
# {
# "KeyFingerprint": "2f:6a:9c:1e:4b:8d:3f:7a:0c:5e:9b:2d:6f:1a:4c:8e",
# "KeyName": "ec2-tutoriel",
# "KeyPairId": "key-0a1b2c3d4e5f6g7h8"
# }
Protégez le fichier de clé privée avec des permissions restrictives (chmod 600 ~/.ssh/ec2-tutoriel) et ne le versionnez jamais dans un dépôt Git, même privé.
Étape 4 : créer un VPC et un sous-réseau isolés
Chaque compte AWS reçoit un VPC par défaut, souvent trop permissif pour de la production : sous-réseaux publics dans toutes les zones de disponibilité, table de routage ouverte, règles héritées. Créez plutôt un VPC dédié avec un plan d’adressage que vous maîtrisez, ce qui facilite aussi l’interconnexion future avec d’autres environnements. La documentation Amazon VPC couvre les scénarios avancés (peering, sous-réseaux privés, passerelle NAT) si votre projet grandit au-delà d’une simple instance publique.
aws ec2 create-vpc \
--cidr-block 10.20.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=ec2-tutoriel-vpc}]'
# VpcId retourné : vpc-0a1b2c3d4e5f6g7h8
aws ec2 create-subnet \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--cidr-block 10.20.1.0/24 \
--availability-zone eu-west-3a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ec2-tutoriel-subnet}]'
aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=ec2-tutoriel-igw}]'
aws ec2 attach-internet-gateway \
--vpc-id vpc-0a1b2c3d4e5f6g7h8 \
--internet-gateway-id igw-0a1b2c3d4e5f6g7h8
N’oubliez pas la table de routage : sans route 0.0.0.0/0 pointant vers l’Internet Gateway, votre instance restera injoignable malgré une adresse IP publique assignée. C’est l’une des erreurs les plus fréquentes de ce tutoriel, détaillée plus loin dans la section dépannage.
Étape 5 : configurer un security group minimal
Un security group agit comme un pare-feu au niveau de l’instance, avec état (stateful) : si vous autorisez une connexion entrante, la réponse sortante est automatiquement acceptée. La règle d’or reste le moindre privilège réseau : n’ouvrez que les ports strictement nécessaires, et jamais le port SSH à 0.0.0.0/0.
aws ec2 create-security-group \
--group-name ec2-tutoriel-sg \
--description "Acces minimal SSH restreint et HTTPS public" \
--vpc-id vpc-0a1b2c3d4e5f6g7h8
MON_IP=$(curl -s https://checkip.amazonaws.com)
aws ec2 authorize-security-group-ingress \
--group-id sg-0a1b2c3d4e5f6g7h8 \
--protocol tcp --port 22 --cidr "${MON_IP}/32"
aws ec2 authorize-security-group-ingress \
--group-id sg-0a1b2c3d4e5f6g7h8 \
--protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
--group-id sg-0a1b2c3d4e5f6g7h8 \
--protocol tcp --port 80 --cidr 0.0.0.0/0
Le port 80 reste utile uniquement pour la validation Let’s Encrypt et la redirection vers HTTPS, jamais pour servir du contenu en clair. Si votre IP publique change régulièrement (connexion résidentielle sans IP fixe), pensez à mettre à jour la règle SSH ou à basculer vers AWS Systems Manager Session Manager, présenté dans les astuces avancées.
Étape 6 : créer un rôle IAM à moindre privilège
Une instance ne doit jamais embarquer de clé d’accès IAM statique dans un fichier de configuration ou une variable d’environnement. AWS résout ce problème depuis longtemps avec les rôles IAM attachés via un profil d’instance : les identifiants sont générés automatiquement, tournent régulièrement et ne transitent jamais sur le disque en clair.
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
EOF
aws iam create-role \
--role-name ec2-tutoriel-role \
--assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy \
--role-name ec2-tutoriel-role \
--policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
aws iam create-instance-profile --instance-profile-name ec2-tutoriel-profile
aws iam add-role-to-instance-profile \
--instance-profile-name ec2-tutoriel-profile \
--role-name ec2-tutoriel-role
N'attachez que les politiques réellement nécessaires. Le rapport Unit 42 cité plus haut rappelle que la quasi-totalité des identités cloud analysées conservaient des permissions inutilisées : commencez restrictif et élargissez seulement si un besoin précis apparaît.
Étape 7 : choisir l'instance, la région et estimer le coût
AWS a généralisé Graviton4 (processeur ARM maison) sur les familles C8g, M8g, R8g, X8g et I8g, avec les variantes NVMe C8gd, M8gd et R8gd disponibles depuis avril 2025 sur les régions américaines. Le système Nitro v6 qui équipe ces instances pousse certaines variantes jusqu'à 600 Gbps de bande passante réseau. Lors de re:Invent 2025 (fin novembre-début décembre 2025), AWS a présenté Graviton5 et prévisualisé les instances M9g, annoncées avec des performances jusqu'à 25 % supérieures aux M8g et 192 cœurs par puce. Pour ce tutoriel, une instance Graviton (famille t4g ou m7g) suffit largement et coûte moins cher qu'un équivalent x86. La page officielle des types d'instances EC2 liste l'ensemble des familles disponibles région par région, un point à vérifier car toutes les générations ne sont pas encore déployées partout.
Le choix entre architecture ARM (Graviton) et x86 (Intel ou AMD) dépend surtout de la compatibilité de vos dépendances logicielles. La plupart des runtimes modernes, Node.js, Python, Go, Java et les images Docker officielles, proposent des builds ARM64 natifs depuis plusieurs années, ce qui rend la bascule transparente pour une majorité de projets web. Les bibliothèques compilées maison ou les binaires tiers sans variante ARM restent le principal frein : dans ce cas, une famille x86 comme t3 ou m7i reste le choix le plus sûr, quitte à payer un peu plus cher à l'heure.
| Type d'instance | vCPU / RAM | us-east-1 (à l'heure) | eu-west-3 Paris (à l'heure) | Coût mensuel estimé (730h, eu-west-3) |
|---|---|---|---|---|
| t3.micro | 2 vCPU / 1 Gio | 0,0104 $ | 0,0118 $ | ~8,6 $ |
| t4g.micro (Graviton2) | 2 vCPU / 1 Gio | 0,0084 $ | 0,0094 $ | ~6,9 $ |
| m7g.large (Graviton3) | 2 vCPU / 8 Gio | 0,0816 $ | 0,0952 $ | ~69,5 $ |
Le prix en Europe reste généralement 15 à 17 % plus élevé qu'en Virginie (us-east-1), un écart à intégrer dans vos arbitrages si la résidence des données n'est pas contrainte réglementairement. Côté free tier, la règle a changé en 2025 : les comptes créés avant le 15 juillet 2025 gardent l'ancien modèle (750 heures par mois de t2.micro ou t3.micro pendant 12 mois, avec facturation au-delà). Les comptes créés à partir du 15 juillet 2025 basculent sur un modèle par crédits, limité à 6 mois ou jusqu'à épuisement des crédits, sur un périmètre élargi d'instances éligibles (t3.micro, t3.small, t4g.micro, t4g.small, c7i-flex.large, m7i-flex.large). Un essai gratuit séparé sur t4g.small, 750 heures par mois, reste disponible pour tous les comptes jusqu'au 31 décembre 2026.
Étape 8 : lancer l'instance avec Amazon Linux 2023 et IMDSv2 imposé
Amazon Linux 2023 reste la distribution recommandée par AWS, avec un support annoncé jusqu'au 30 juin 2029 et des mises à jour trimestrielles. Elle impose IMDSv2 par défaut, mais autant le préciser explicitement dans la commande de lancement pour ne dépendre d'aucun comportement implicite.
AMI_ID=$(aws ec2 describe-images \
--owners amazon \
--filters "Name=name,Values=al2023-ami-*-arm64" "Name=state,Values=available" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" --output text)
aws ec2 run-instances \
--image-id "$AMI_ID" \
--instance-type t4g.micro \
--key-name ec2-tutoriel \
--subnet-id subnet-0a1b2c3d4e5f6g7h8 \
--security-group-ids sg-0a1b2c3d4e5f6g7h8 \
--iam-instance-profile Name=ec2-tutoriel-profile \
--metadata-options "HttpTokens=required,HttpPutResponseHopLimit=2,HttpEndpoint=enabled" \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ec2-tutoriel-serveur}]'
# {
# "Instances": [{
# "InstanceId": "i-0a1b2c3d4e5f6g7h8",
# "InstanceType": "t4g.micro",
# "State": {"Code": 0, "Name": "pending"}
# }]
# }
HttpTokens=required impose IMDSv2 : toute requête vers le service de métadonnées doit présenter un jeton de session, ce qui bloque les attaques SSRF classiques qui visaient IMDSv1 en 2019 lors de l'incident Capital One. Plutôt que de vérifier manuellement l'état de l'instance toutes les quelques secondes, utilisez la commande d'attente intégrée à l'AWS CLI, qui interroge l'API à intervalle régulier et rend la main dès que l'instance passe à l'état running.
aws ec2 wait instance-running --instance-ids i-0a1b2c3d4e5f6g7h8
echo "Instance prete"
Récupérez ensuite l'adresse IP publique attribuée.
aws ec2 describe-instances --instance-ids i-0a1b2c3d4e5f6g7h8 \
--query "Reservations[0].Instances[0].PublicIpAddress" --output text
# 15.237.xxx.xxx
Étape 9 : durcir le système au premier accès SSH
Connectez-vous avec l'utilisateur par défaut d'Amazon Linux 2023, ec2-user, puis appliquez immédiatement les mises à jour de sécurité et désactivez l'authentification par mot de passe.
ssh -i ~/.ssh/ec2-tutoriel [email protected]
sudo dnf update -y
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Activez ensuite les mises à jour automatiques de sécurité pour ne pas dépendre d'une intervention manuelle à chaque avis ALAS (Amazon Linux Security Advisory). Des bulletins comme AWS-2025-024, publié en août 2026 pour trois failles du runtime conteneur runc, montrent que le rythme de correctifs reste soutenu.
sudo dnf install -y dnf-automatic
sudo sed -i 's/^apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer
Étape 10 : pare-feu applicatif, fail2ban et mises à jour automatiques
Le security group filtre déjà le trafic réseau en amont, mais un pare-feu système local et fail2ban ajoutent une couche de défense en profondeur, utile si une règle du security group est un jour élargie par erreur.
sudo dnf install -y fail2ban firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
sudo tee /etc/fail2ban/jail.local > /dev/null << 'EOF'
[sshd]
enabled = true
port = ssh
maxretry = 4
bantime = 3600
findtime = 600
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Étape 11 : chiffrer le trafic avec Nginx et Let's Encrypt
Installez Nginx comme reverse proxy et obtenez un certificat TLS gratuit avec Let's Encrypt via Certbot. Cette étape suppose qu'un nom de domaine pointe déjà vers l'adresse IP publique de l'instance via un enregistrement A.
sudo dnf install -y nginx
sudo systemctl enable --now nginx
sudo dnf install -y python3-certbot-nginx
sudo certbot --nginx -d votre-domaine.fr --non-interactive \
--agree-tos -m [email protected] --redirect
sudo systemctl status certbot-renew.timer
Certbot configure lui-même le renouvellement automatique via un minuteur systemd. Vérifiez le résultat avec un test de renouvellement à blanc, qui ne modifie rien mais confirme que la procédure fonctionnera dans 90 jours.
sudo certbot renew --dry-run
Étape 12 : supervision, sauvegardes et automatisation
Une instance sécurisée au lancement se dégrade si personne ne la surveille dans la durée. Activez Amazon GuardDuty, dont la fonction Extended Threat Detection a été étendue aux instances EC2 et aux tâches ECS lors de re:Invent 2025 : le service corrèle désormais les signaux au niveau hôte et conteneur pour repérer des séquences d'attaque en plusieurs étapes, pas seulement des événements isolés. Programmez aussi des snapshots EBS automatiques via Data Lifecycle Manager, ce qui évite de perdre des données en cas d'erreur de manipulation ou de compromission.
aws guardduty create-detector --enable
aws dlm create-lifecycle-policy \
--description "Snapshots quotidiens ec2-tutoriel" \
--state ENABLED \
--execution-role-arn arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole \
--policy-details '{
"ResourceTypes": ["VOLUME"],
"TargetTags": [{"Key": "Name", "Value": "ec2-tutoriel-serveur"}],
"Schedules": [{
"Name": "quotidien",
"CreateRule": {"Interval": 24, "IntervalUnit": "HOURS", "Times": ["03:00"]},
"RetainRule": {"Count": 7}
}]
}'
Le projet complet : un script Terraform prêt à l'emploi
Plutôt que d'enchaîner les commandes AWS CLI à chaque nouveau déploiement, l'ensemble des étapes précédentes tient dans un seul fichier Terraform reproductible. Créez un dossier de projet et collez la configuration suivante dans main.tf.
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" {
region = "eu-west-3"
profile = "ec2-tutoriel"
}
resource "aws_vpc" "main" {
cidr_block = "10.20.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = { Name = "ec2-tutoriel-vpc" }
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.20.1.0/24"
availability_zone = "eu-west-3a"
map_public_ip_on_launch = true
tags = { Name = "ec2-tutoriel-subnet" }
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = { Name = "ec2-tutoriel-igw" }
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
resource "aws_security_group" "instance" {
name = "ec2-tutoriel-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["VOTRE_IP_PUBLIQUE/32"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_iam_role" "instance" {
name = "ec2-tutoriel-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_instance_profile" "instance" {
name = "ec2-tutoriel-profile"
role = aws_iam_role.instance.name
}
data "aws_ami" "al2023_arm" {
owners = ["amazon"]
most_recent = true
filter {
name = "name"
values = ["al2023-ami-*-arm64"]
}
}
resource "aws_instance" "serveur" {
ami = data.aws_ami.al2023_arm.id
instance_type = "t4g.micro"
subnet_id = aws_subnet.public.id
key_name = "ec2-tutoriel"
vpc_security_group_ids = [aws_security_group.instance.id]
iam_instance_profile = aws_iam_instance_profile.instance.name
metadata_options {
http_tokens = "required"
http_put_response_hop_limit = 2
http_endpoint = "enabled"
}
tags = { Name = "ec2-tutoriel-serveur" }
}
output "adresse_ip_publique" {
value = aws_instance.serveur.public_ip
}
Remplacez VOTRE_IP_PUBLIQUE par votre adresse réelle, puis lancez le déploiement.
terraform init
terraform plan -out=plan.tfout
terraform apply plan.tfout
# Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
# adresse_ip_publique = "15.237.xxx.xxx"
Une fois vos tests terminés, détruisez l'ensemble des ressources pour éviter toute facturation résiduelle.
terraform destroy
EC2 face aux autres options de calcul AWS
EC2 n'est pas toujours le bon choix. AWS propose plusieurs niveaux d'abstraction au-dessus de la même infrastructure Nitro, et le contrôle fin obtenu avec EC2 se paie en temps de configuration et en responsabilité de maintenance. Lightsail simplifie radicalement le lancement d'un petit serveur avec un tarif forfaitaire tout compris (calcul, stockage, transfert), au prix d'une personnalisation réseau plus limitée. ECS et Fargate évitent complètement de gérer des instances : vous ne payez plus que pour l'exécution des conteneurs, mais vous perdez l'accès SSH direct à la machine. Elastic Beanstalk automatise le déploiement d'une application classique (Node.js, Python, Java) tout en restant, sous le capot, une orchestration d'instances EC2 que vous pouvez inspecter.
| Service | Contrôle du système | Effort de configuration | Cas d'usage typique |
|---|---|---|---|
| EC2 (ce tutoriel) | Total (accès root, réseau, noyau) | Élevé | Serveurs sur mesure, charges spécifiques, conformité stricte |
| Lightsail | Limité (VM préconfigurée) | Faible | Sites vitrines, blogs, petits projets avec budget fixe |
| ECS / Fargate | Aucun accès machine | Moyen | Applications conteneurisées, microservices |
| Elastic Beanstalk | Partiel (EC2 sous-jacent visible) | Faible à moyen | Déploiement rapide d'une stack applicative standard |
Si votre besoin se limite à héberger un site statique ou une petite API sans exigence particulière de personnalisation réseau, Lightsail ou Fargate demandent moins de maintenance qu'une instance EC2 nue. EC2 garde l'avantage dès que vous avez besoin d'un contrôle précis sur le pare-feu système, le noyau, les pilotes réseau ou une architecture réseau multi-VPC, ce qui reste fréquent pour des charges de travail réglementées ou des migrations depuis une infrastructure sur site.
Erreurs fréquentes à éviter
La plupart des incidents de sécurité sur EC2 ne viennent pas d'une faille logicielle exotique, mais d'un raccourci pris pendant la configuration initiale, souvent pour gagner du temps un vendredi soir. Voici les six erreurs qui reviennent le plus souvent dans les retours d'expérience de la communauté AWS et dans les rapports d'incident cités plus haut.
- Garder le VPC par défaut en production. Il est partagé entre tous vos projets, souvent trop ouvert, et rend l'isolation réseau difficile à auditer.
- Ouvrir le port 22 à 0.0.0.0/0. C'est la première chose que scannent les bots dès qu'une IP publique apparaît, en général en quelques minutes.
- Coller des clés d'accès IAM en dur dans le code ou dans l'user-data. L'user-data d'une instance est lisible par quiconque a accès à l'API EC2 sur le compte, ce n'est pas un espace de stockage secret.
- Désactiver IMDSv2 pour "gagner du temps" au débogage. C'est exactement le chemin d'attaque qui a permis l'exfiltration de données chez Capital One en 2019.
- Confondre security group et pare-feu système. Les deux se complètent, ils ne se remplacent pas : un security group filtre le trafic réseau en amont, un pare-feu local comme firewalld protège même si une règle réseau est élargie par erreur plus tard.
- Oublier de limiter le hop limit IMDS à 2. Une valeur trop basse casse l'accès aux métadonnées depuis un conteneur Docker exécuté sur l'instance, une valeur trop haute facilite un relais SSRF multi-saut.
Dépannage : problèmes courants et leurs solutions
Quand quelque chose ne fonctionne pas comme prévu, la méthode la plus rapide reste de vérifier les couches dans l'ordre : d'abord le security group et la table de routage (couche réseau), puis les identifiants IAM et le profil d'instance (couche permissions), enfin les journaux système sur l'instance elle-même via SSH ou la console série EC2. Les VPC Flow Logs et CloudTrail permettent de confirmer si une requête a été bloquée au niveau réseau ou refusée au niveau IAM, ce qui évite de chercher au mauvais endroit. Le tableau suivant couvre les dix problèmes les plus fréquemment rencontrés en suivant ce tutoriel.
| Symptôme | Cause probable | Solution |
|---|---|---|
| "Connection timed out" en SSH | Security group ou IP source obsolète | Vérifiez la règle du port 22 et mettez à jour le CIDR avec votre IP actuelle |
| "Permission denied (publickey)" | Mauvais utilisateur ou mauvaise clé | Utilisez ec2-user pour Amazon Linux 2023 et vérifiez le chemin de la clé privée |
| "curl: (28) Failed to connect" vers 169.254.169.254 | Jeton IMDSv2 manquant dans la requête | Récupérez d'abord un jeton avec PUT sur /latest/api/token, puis passez-le en en-tête X-aws-ec2-metadata-token |
| Instance injoignable malgré une IP publique | Pas d'Internet Gateway ou table de routage incomplète | Vérifiez que la route 0.0.0.0/0 pointe bien vers l'IGW attaché au VPC |
| "UnauthorizedOperation" sur run-instances | Politique IAM de l'utilisateur trop restrictive | Ajoutez les actions EC2 nécessaires (RunInstances, CreateTags) à la politique de l'utilisateur, pas à celle de l'instance |
| Certbot échoue avec "Timeout during connect" | Port 80 fermé dans le security group | Autorisez temporairement le port 80 en entrée le temps de la validation HTTP-01 |
| L'instance t3/t4g devient lente après quelques heures | Crédits CPU "burstable" épuisés | Passez en mode "unlimited" ou migrez vers une instance non burstable comme m7g.large |
| "InsufficientInstanceCapacity" au lancement | Capacité indisponible dans la zone choisie | Changez de zone de disponibilité (eu-west-3a, 3b ou 3c) ou de type d'instance |
| Disque plein après les mises à jour dnf | Volume EBS racine trop petit | Agrandissez le volume via modify-volume puis étendez le système de fichiers avec growpart et xfs_growfs |
| Terraform : "Error: creating EC2 Instance: VPCIdNotSpecified" | subnet_id manquant ou VPC non créé avant l'instance | Vérifiez l'ordre des dépendances entre ressources ou ajoutez un depends_on explicite |
Astuces avancées pour aller plus loin
Une fois la base sécurisée en place, plusieurs options permettent de réduire les coûts ou de renforcer encore la posture de sécurité. AWS Systems Manager Session Manager permet de se connecter à une instance sans ouvrir le port 22 du tout et sans gérer de clé SSH : l'accès passe par l'API AWS et s'appuie sur IAM pour l'autorisation, avec journalisation complète des sessions. Pour des charges de travail tolérantes aux interruptions, les instances Spot proposent des rabais importants par rapport au tarif à la demande, à condition de gérer proprement les coupures avec un avertissement de deux minutes avant récupération de la capacité.
Si votre charge varie dans le temps, un Auto Scaling Group ajuste automatiquement le nombre d'instances selon la demande, en s'appuyant sur les mêmes security groups et rôles IAM que ceux configurés ici. Gardez un œil sur les annonces Graviton5 et M9g issues de re:Invent 2025 : une fois disponibles en disponibilité générale, elles devraient offrir un meilleur rapport performance-prix que les familles Graviton4 utilisées dans ce tutoriel, sans changement de code applicatif puisque l'architecture ARM reste compatible.
Pour garder un œil sur les coûts dans la durée, AWS Compute Optimizer analyse l'utilisation réelle de vos instances (CPU, mémoire, réseau) et recommande un redimensionnement si vous payez pour une capacité que vous n'utilisez pas. Cost Explorer complète cette vue avec un suivi budgétaire par tag, utile pour repérer rapidement une instance oubliée après un test. Enfin, si vous gérez plusieurs comptes AWS pour une organisation, AWS Organizations combiné à un Service Control Policy permet d'imposer certaines de ces règles, comme l'interdiction de désactiver IMDSv2, au niveau de l'ensemble des comptes plutôt qu'instance par instance.
Checklist finale avant de passer en production
Avant d'ouvrir votre instance à de vrais utilisateurs, reprenez chaque point de cette liste une dernière fois. Elle condense les douze étapes précédentes en un contrôle rapide, à refaire idéalement à chaque nouvelle instance plutôt qu'une seule fois pour tout le compte.
- MFA activé sur le compte racine et sur l'utilisateur IAM administrateur
- Aucune clé d'accès IAM statique stockée sur l'instance ou dans le code
- VPC dédié avec table de routage vérifiée, pas le VPC par défaut
- Security group limité aux ports 22 (IP restreinte), 80 et 443
- Rôle IAM attaché via un profil d'instance, avec le minimum de politiques nécessaires
- IMDSv2 imposé (
HttpTokens=required) et hop limit fixé à 2 - Authentification par mot de passe désactivée en SSH, connexion root bloquée
- Mises à jour de sécurité automatiques activées (dnf-automatic ou équivalent)
- fail2ban actif sur le service SSH
- Certificat TLS valide et renouvellement automatique testé avec
certbot renew --dry-run - GuardDuty activé et alertes configurées
- Snapshots EBS automatiques planifiés avec une rétention définie
Questions fréquentes
Quelle est la différence entre un security group et un ACL réseau (NACL) ?
Le security group s'applique au niveau de l'instance et garde un état (stateful) : une réponse à une connexion autorisée passe automatiquement. Le NACL s'applique au niveau du sous-réseau et reste sans état (stateless), il faut donc définir des règles entrantes et sortantes séparément.
Le free tier EC2 est-il toujours gratuit en 2026 ?
Cela dépend de la date de création du compte. Avant le 15 juillet 2025, vous gardez 750 heures par mois de t2.micro ou t3.micro pendant 12 mois. Après cette date, le modèle passe à des crédits limités dans le temps sur un périmètre d'instances élargi.
Faut-il vraiment créer un VPC personnalisé pour un simple test ?
Pour un test de quelques minutes isolé, le VPC par défaut suffit. Dès qu'une instance héberge des données réelles ou reste en ligne plus de quelques heures, un VPC dédié facilite l'audit et limite la surface d'exposition.
Qu'est-ce qu'IMDSv2 et pourquoi l'imposer ?
IMDSv2 exige un jeton de session obtenu via une requête PUT avant tout accès au service de métadonnées de l'instance. Cela bloque les attaques SSRF qui, avec IMDSv1, pouvaient récupérer directement les identifiants du rôle IAM via une simple requête GET.
Quelle instance choisir pour un petit site web en production ?
Un t4g.micro ou t4g.small suffit pour un trafic modéré, avec un passage en "unlimited" si les pics dépassent régulièrement le crédit CPU inclus. Pour un trafic soutenu et stable, m7g.large offre plus de constance sans dépendre du mécanisme de crédits.
Peut-on éviter complètement les clés SSH ?
Oui, via AWS Systems Manager Session Manager, qui repose sur IAM plutôt que sur une paire de clés et journalise chaque session. C'est l'option recommandée pour les environnements où la rotation de clés SSH devient difficile à maintenir à l'échelle.
Combien coûte réellement une instance EC2 sécurisée à l'année ?
Pour un t4g.micro en eu-west-3 tournant en continu, comptez environ 82 dollars par an au tarif à la demande de septembre 2026, hors stockage EBS, snapshots et transfert de données sortant. Les instances réservées ou les Savings Plans réduisent sensiblement ce montant pour un usage prévisible sur la durée.
Amazon Linux 2023 est-il obligatoire pour suivre ce tutoriel ?
Non, mais c'est la distribution recommandée par AWS avec le support le plus long (jusqu'en juin 2029) et IMDSv2 activé par défaut. Ubuntu ou Debian fonctionnent aussi avec les mêmes commandes AWS CLI et Terraform, seules les commandes de gestion de paquets (apt au lieu de dnf) changent.




