
Une EC2 ne devrait jamais “tout pouvoir faire” par défaut. Dès qu’une machine doit lire un bucket S3, interroger une API AWS ou décrire d’autres ressources, vous devez choisir exactement quelles permissions lui donner. Sinon, la moindre fuite de credentials ou la moindre erreur de configuration ouvre beaucoup trop de droits. Ce guide introduit donc le trio essentiel d’AWS côté identité : policy, rôle et instance profile.
L’enchaînement peut sembler abstrait au début, donc retenez cette image simple : la policy est la liste des droits, le rôle est le conteneur qui porte ces droits, et l’instance profile est l’adaptateur qui permet d’attacher ce rôle à une EC2. Le but du guide est de rendre cette chaîne concrète, pas seulement de vous faire copier trois ressources HCL.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer une police IAM avec
aws_iam_policy_document(JSON as code) - Créer un rôle IAM avec une trust policy pour EC2
- Attacher une police à un rôle avec
aws_iam_role_policy_attachment - Créer un instance profile pour lier le rôle à une EC2
- Ajouter le profil à une instance via
iam_instance_profile - Vérifier les ARNs dans les outputs
Pourquoi IAM arrive à ce moment du parcours
Section intitulée « Pourquoi IAM arrive à ce moment du parcours »Après le provider et le réseau, la question suivante est logique : que peut faire l’instance une fois démarrée ? Dans AWS, la réponse passe par IAM. Contrairement à un script local ou à un environnement de test bricolé, une EC2 ne devrait pas embarquer des clés statiques dans ses fichiers.
Ce guide montre donc la bonne direction dès le début : donner à l’instance un rôle ciblé, avec des permissions explicites et réutilisables.
Prérequis
Section intitulée « Prérequis »- Terraform ≥ 1.11 installé
- AWS CLI configuré
- Avoir lu Déployer une première EC2 et Security groups, subnet et instance, ou comprendre
data,resourceetoutputs
Objectif
Section intitulée « Objectif »Construire une infrastructure avec :
- Une policy IAM qui permet de lire depuis S3 et décrire des instances
- Un rôle IAM qui assume cette policy
- Un instance profile qui lie le rôle
- Une EC2 qui hérite des permissions via le profil
Durée estimée : 15 minutes Coût : Gratuit (tier gratuit AWS)
Préparation
Section intitulée « Préparation »Créez le répertoire du lab :
mkdir -p ~/terraform-aws-iam-ec2cd ~/terraform-aws-iam-ec2Étape 1 — Déclarer le provider
Section intitulée « Étape 1 — Déclarer le provider »Créez versions.tf :
terraform { required_version = ">= 1.11.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } }}
provider "aws" { region = var.aws_region}Étape 2 — Déclarer les variables
Section intitulée « Étape 2 — Déclarer les variables »Créez variables.tf :
variable "aws_region" { description = "AWS region" type = string default = "us-east-1"}
variable "instance_name" { description = "Name tag for the EC2 instance" type = string default = "lab03-instance-with-iam"}
variable "instance_type" { description = "EC2 instance type" type = string default = "t2.micro"}
variable "role_name" { description = "Name of the IAM role" type = string default = "lab03-ec2-role"}Étape 3 — Créer la policy document
Section intitulée « Étape 3 — Créer la policy document »Créez main.tf avec la data source aws_iam_policy_document :
# Créer une policy IAM document (JSON policy as code)data "aws_iam_policy_document" "s3_read_policy" { statement { effect = "Allow" actions = [ "s3:GetObject", "s3:ListBucket" ] resources = [ "arn:aws:s3:::*", "arn:aws:s3:::*/*" ] }
statement { effect = "Allow" actions = ["ec2:DescribeInstances"] resources = ["*"] }}Ce bloc définit :
- Statement 1 : Lire depuis S3 (
ListBucket,GetObject) sur tous les buckets - Statement 2 : Décrire les instances EC2 (lire les métadonnées)
La data source génère automatiquement le JSON — pas besoin de l’écrire manuellement.
Étape 4 — Créer le rôle IAM
Section intitulée « Étape 4 — Créer le rôle IAM »Toujours dans main.tf, ajoutez :
resource "aws_iam_role" "lab03_role" { name = var.role_name
assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } Action = "sts:AssumeRole" } ] })
tags = { Name = var.role_name }}Ce bloc crée :
- Un rôle IAM = conteneur de permissions
- Une trust policy = qui peut utiliser ce rôle ?
Principal: { Service: "ec2.amazonaws.com" }= Les instances EC2 peuvent assumer ce rôleAction: "sts:AssumeRole"= Permission pour les EC2 de prendre le rôle
Étape 5 — Créer la policy IAM resource
Section intitulée « Étape 5 — Créer la policy IAM resource »Toujours dans main.tf, ajoutez :
resource "aws_iam_policy" "s3_read_policy" { name = "lab03-s3-read-policy" description = "Allow EC2 to read from S3 and describe instances" policy = data.aws_iam_policy_document.s3_read_policy.json
tags = { Name = "lab03-s3-read-policy" }}Ce bloc :
- Crée une policy managée AWS à partir du document défini plus haut
policy = data.aws_iam_policy_document.s3_read_policy.json: utilise le JSON généré
Étape 6 — Attacher la policy au rôle
Section intitulée « Étape 6 — Attacher la policy au rôle »Toujours dans main.tf, ajoutez :
resource "aws_iam_role_policy_attachment" "attach_s3_policy" { role = aws_iam_role.lab03_role.name policy_arn = aws_iam_policy.s3_read_policy.arn}Ce bloc dit :
- “Attache la policy
s3_read_policyau rôlelab03_role” - L’EC2 pourra maintenant faire ce que la policy autorise
Étape 7 — Créer l’instance profile
Section intitulée « Étape 7 — Créer l’instance profile »Toujours dans main.tf, ajoutez :
resource "aws_iam_instance_profile" "lab03_profile" { name = "lab03-ec2-profile" role = aws_iam_role.lab03_role.name}L’instance profile :
- Est le lien entre rôle IAM et EC2
- Contient un ou plusieurs rôles (généralement un seul)
- Est attaché à une instance, pas directement au rôle
Étape 8 — Créer l’EC2 avec le profil
Section intitulée « Étape 8 — Créer l’EC2 avec le profil »Toujours dans main.tf, ajoutez :
# Lire l'AMI Ubuntu la plus récentedata "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical (Ubuntu)
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] }
filter { name = "virtualization-type" values = ["hvm"] }}
resource "aws_instance" "lab03_vm" { ami = data.aws_ami.ubuntu.id instance_type = var.instance_type iam_instance_profile = aws_iam_instance_profile.lab03_profile.name
tags = { Name = var.instance_name }}Clé :
iam_instance_profile = aws_iam_instance_profile.lab03_profile.name: l’EC2 hérite des permissions du profil
Étape 9 — Définir les outputs
Section intitulée « Étape 9 — Définir les outputs »Créez outputs.tf :
output "iam_role_arn" { description = "ARN of the IAM role" value = aws_iam_role.lab03_role.arn}
output "iam_role_name" { description = "Name of the IAM role" value = aws_iam_role.lab03_role.name}
output "iam_policy_arn" { description = "ARN of the IAM policy" value = aws_iam_policy.s3_read_policy.arn}
output "instance_profile_arn" { description = "ARN of the instance profile" value = aws_iam_instance_profile.lab03_profile.arn}
output "instance_id" { description = "EC2 Instance ID" value = aws_instance.lab03_vm.id}
output "instance_arn" { description = "EC2 Instance ARN" value = aws_instance.lab03_vm.arn}
output "instance_iam_instance_profile" { description = "IAM instance profile name attached to the instance" value = aws_instance.lab03_vm.iam_instance_profile}Étape 10 — Variables
Section intitulée « Étape 10 — Variables »Créez terraform.tfvars :
aws_region = "us-east-1"instance_name = "lab03-instance-with-iam"instance_type = "t2.micro"role_name = "lab03-ec2-role"Vérification
Section intitulée « Vérification »-
Initialiser :
Fenêtre de terminal terraform init -
Valider :
Fenêtre de terminal terraform validate -
Appliquer :
Fenêtre de terminal terraform apply -auto-approveSortie attendue (fin) :
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.Outputs:iam_policy_arn = "arn:aws:iam::276757567417:policy/lab03-s3-read-policy"iam_role_arn = "arn:aws:iam::276757567417:role/lab03-ec2-role"iam_role_name = "lab03-ec2-role"instance_arn = "arn:aws:ec2:us-east-1:276757567417:instance/i-046ec132d2c5984af"instance_iam_instance_profile = "lab03-ec2-profile"instance_id = "i-046ec132d2c5984af"instance_profile_arn = "arn:aws:iam::276757567417:instance-profile/lab03-ec2-profile" -
Vérifier dans la console AWS (optionnel) :
Fenêtre de terminal # Voir le rôle crééaws iam get-role --role-name lab03-ec2-role# Voir l'instance profileaws iam get-instance-profile --instance-profile-name lab03-ec2-profile
Anatomie
Section intitulée « Anatomie »Trust Policy vs Resource Policy
Section intitulée « Trust Policy vs Resource Policy »| Type | Rôle | Exemple |
|---|---|---|
| Trust policy | ”Qui peut utiliser ce rôle ?” | EC2 service, Lambda, utilisateurs |
| Resource policy | ”Quelles actions sont autorisées ?” | S3 read, EC2 describe |
Dans ce lab :
- Trust policy du rôle : “les EC2 peuvent l’assumer”
- Resource policy (la policy S3) : “lire depuis S3 et décrire instances”
aws_iam_policy_document
Section intitulée « aws_iam_policy_document »Cet data source génère du JSON IAM à partir de HCL lisible. Avant :
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::*", "arn:aws:s3:::*/*"] } ]}Avec aws_iam_policy_document, c’est généré automatiquement et testable.
Bonnes pratiques
Section intitulée « Bonnes pratiques »1. Principe du moindre privilège
Section intitulée « 1. Principe du moindre privilège »# ❌ Trop permissifactions = ["*"]
# ✅ Spécifiqueactions = [ "s3:GetObject", "s3:ListBucket"]2. Restreindre les ressources
Section intitulée « 2. Restreindre les ressources »# ❌ Toutresources = ["*"]
# ✅ Spécifiqueresources = [ "arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]3. Utiliser des rôles pour chaque service
Section intitulée « 3. Utiliser des rôles pour chaque service »# ❌ Un rôle pour toutrole_name = "general-role"
# ✅ Rôles spécialisésresource "aws_iam_role" "ec2_s3_role" { ... }resource "aws_iam_role" "lambda_dynamo_role" { ... }4. Documenter les policies
Section intitulée « 4. Documenter les policies »data "aws_iam_policy_document" "example" { description = "Allow EC2 to read production S3 bucket only" # ...}Dépannage
Section intitulée « Dépannage »| Symptôme | Cause | Solution |
|---|---|---|
Error: User is not authorized to perform: iam:CreateRole | Utilisateur AWS sans permissions IAM | Demander IAMFullAccess ou permissions iam:CreateRole, iam:CreatePolicy, etc. |
Error: EntityAlreadyExists: Role with name lab03-ec2-role already exists | Rôle existe déjà | Changer role_name ou terraform destroy d’abord |
| EC2 créée mais profil absent | Timing ou oubli iam_instance_profile | Ajouter iam_instance_profile = aws_iam_instance_profile.lab03_profile.name |
| Policy attachée mais EC2 ne peut pas lire S3 | Trust policy manquante | Vérifier que assume_role_policy permet EC2 |
Nettoyage
Section intitulée « Nettoyage »terraform destroy -auto-approveSortie attendue :
Destroy complete! Resources: 5 destroyed.Nettoyez les fichiers :
rm -rf .terraform* terraform.tfstate*À retenir
Section intitulée « À retenir »- IAM = sécurité AWS — toujours utiliser le moindre privilège
- Policy document genère du JSON depuis du HCL lisible
- Rôle IAM = conteneur de permissions avec trust policy
- Instance profile = lien entre rôle et EC2
- Trust policy répond “Qui peut utiliser ce rôle ?”
- Resource policy répond “Qu’est-ce qui est autorisé ?”
- Attacher plutôt que d’intégrer : utilisez
aws_iam_role_policy_attachmentpour la réutilisabilité