Terraform - Guide Complet pour la Mise en Place d’une Infrastructure sur AWS IaC

YOUSSOUFOU Ousmanou
8 min readAug 20, 2023

--

Terraform est un outils à la pointe qui permet d’automatiser les infrastructures de systèmes d’informations. J’ai ecrit un article qui montre les avantages d’avoir une infrastructure as code (IaC) que vous pouvez retrouver ici.

Dans cet article, il sera question de mettre cela en pratique. Nous allons coder et déployer les différents éléments d’une infra ( réseaux, workloads, middleware) avec Terraform.

Architecture

Nous allons mettre en place l’architecture suivante qui est une petite infrastructure avec quelques ressources elementaires.

source: dev.to

Nous allons mettre en place un VPC (reseau privé virtuel), deux subnets(un sous reseau public et un sous reseau privé), un internet gateway et un NAT gateway. Nous allons lancer une instance EC2 dans chacune des subnets.

Prérequis

Pour faire ce lab, il faut au prealable avoir Terraform d’installé sur sa machine. Pour ma part, j’ai utilisé la documentation officielle pour l’installer sur ma machine.

Il faut aussi de préférence avoir un editeur adapaté et telecharger le plugin Terraform. pour ma part j’utilise VScode.

Premier pas avec Terraform

Avant de commencer à éditer l’infrastructure, il faut d’abord se connecter à son compte AWS et récupérer les access keys. Si vous ne savez pas comment, jetez un coup d’oeil à ce tutoriel.

Très important ! ne jamais stocker ses clés AWS dans le code Terraform. il existe plusieurs façons de les sécuriser sur le poste de travail. le plus simple est de les déclarer en tant que variables d’environnement, ou en les stockant directement dans le fichier à l‘emplacement ~/.aws/credentials

Sur Windows: C:\Users\username\.aws\credentials
Sur Mac/Linux: ~/.aws/credentials

dans le fichier credentials, vous aurez:

[default]
aws_access_key_id = votre_access_key
aws_secret_access_key = votre_secret_key

Une fois que nous avons configuré les clés aws, nous pouvons commencer à écrire le script Terraform proprement parlé.

Tout d’abord, il faut indiquer à Terraform quel provider utilisé. dans notre cas ca sera AWS.

provider "aws" {
region = "us-east-1" # Remplacez par la région de votre choix
}

Infrastructure réseau

Dans un premier temps, nous allons déclarer un VPC qui est un réseau privé virtuel. Celui ci est isolé est nous est exclusivement dédié. Personne ne peut y accéder sans notre permission. S’il faut ouvrir les accès à l’extérieurs, il existe des outils qui permettent de restreindre aux seules personnes autorisées (à l’instar des Security Group et Network ACL, mais ce n’est pas l’objet de ce article. j’écrirai un qui sera dédié à la sécurisation du réseau sur le cloud).

resource "aws_vpc" "vpc_lab1" {
cidr_block = "10.0.0.0/16" # Plage d'adresses IP pour le VPC

tags = {
Name = "VPC-Lab1"
}
}

Nous allons avoir deux subnets, un sous réseau qui sera public (exposé sur internet) et l’autre subnet en privé.

resource "aws_subnet" "public_subnet_lab1" {
vpc_id = aws_vpc.vpc_lab1.id
cidr_block = "10.0.1.0/24" # Plage d'adresses IP pour le subnet public

tags = {
Name = "PublicSubnet"
}
}

resource "aws_subnet" "private_subnet_lab1" {
vpc_id = aws_vpc.vpc_lab1.id
cidr_block = "10.0.2.0/24" # Plage d'adresses IP pour le subnet privé

tags = {
Name = "PrivateSubnet"
}
}

Pour pouvoir sortir sur internet, nous allons avoir besoin d’un Internet Gateway et d’une NAT Gateway.

resource "aws_internet_gateway" "igw_lab1" {
vpc_id = aws_vpc.vpc_lab1.id
}

resource "aws_nat_gateway" "nat_gateway_lab1" {
allocation_id = aws_eip.my_eip.id
subnet_id = aws_subnet.private_subnet_lab1.id
}

resource "aws_eip" "my_eip" {
vpc = true
}

Mais en plus de ces deux éléments, pour sortir sur internet, on doit configurer les routes dans chaque subnet.

Pour mettre en place le routage, nous avons besoin de ces trois éléments dans chaque sous réseau : la table de routage, les routes, et les associations entre la table de routage et le subnet.

# routage pour le subnet privé

# Creation de la table de routage
resource "aws_route_table" "private_route_table" {
vpc_id = aws_vpc.vpc_lab1.id
}

# Association de la table de routage avec le sous resau privé
resource "aws_route_table_association" "private_subnet_association" {
subnet_id = aws_subnet.private_subnet_lab1.id
route_table_id = aws_route_table.private_route_table.id
}

# Mis en place des routes
resource "aws_route" "private_nat_route" {
route_table_id = aws_route_table.private_route_table.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_gateway_lab1.id
}


# routage pour le subnet public

# Creation de la table de routage
resource "aws_route_table" "public_route_table" {
vpc_id = aws_vpc.vpc_lab1.id
}

# Association de la table de routage avec le sous resau public
resource "aws_route_table_association" "public_subnet_association" {
subnet_id = aws_subnet.public_subnet_lab1.id
route_table_id = aws_route_table.public_route_table.id
}

# Mis en place des routes
resource "aws_route" "public_igw_route" {
route_table_id = aws_route_table.public_route_table.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw_lab1.id
}

Après ceci, nous avons finalisé la mise en place du réseau. cela veut dire que nous avons préparé la place pour déployer les ressources de notre infra.

Avant de continuer, si vous voulez aller plus loin avec Terraform ou que vous voulez l’implémenter dans votre boite, je peux vous accompagner. écrivez moi sur mon compte linkedIn ou par mail au youssoufa.ousman@gmail.com

Infrastructure de calcul

Avant construire nos instance, nous avons besoin de mettre en place des règles de Security Groups. Par défaut, tout trafic est bloqué à destination des instances. C’est pourquoi nous avons besoin de spécifier quel port est ouvert sur chaque instance.

Dans ce exemple, nous allons ouvrir le port 80 sur internet et le port 22 sur mon IP à moi(ce qui me permettra d’aller en SSH sur la machine) de l’instance frontend. De même, nous allons ouvrir le port 22 sur l’IP de l’instance backend.

resource "aws_security_group" "public_sg" {
name = "PublicSecurityGroup"
description = "Security group for public subnet instances"
vpc_id = aws_vpc.vpc_lab1.id

ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["x.x.x.x./32"] # remplacer x.x.x.x par votre adresse public. c-a-d celle de votre box internet
}
egress{
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"] # Autorise tout le trafic sortant
}
}

resource "aws_security_group" "private_sg" {
name = "PrivateSecurityGroup"
description = "Security group for private subnet instances"
vpc_id = aws_vpc.vpc_lab1.id

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.public_sg.id] # permet à la machine frontend d'acceder à celle du backend en SSH
}
egress{
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"] # Autorise tout le trafic sortant
}
}

Dans cette dernière partie, nous allons écrire le script qui permet de déployer les instances EC2 (machines virtuelles sur AWS). Comme l’indique l’architecture plus haute, une VM sera déployée dans le subnet public(frontend) et l’autre dans le subnet privé (backend).

resource "aws_instance" "instance_frontend" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = aws_subnet.public_subnet_lab1.id
vpc_security_group_ids = [aws_security_group.public_sg.id]
key_name = "lab1_key_pair"
root_block_device {
delete_on_termination = true
}
tags = {
Name = "instance_frontend"
}
# cette instruction permet de creer aws_key_pair avant la VM
depends_on = [aws_key_pair.lab1_key_pair]
associate_public_ip_address = true # Attribue une adresse IP publique

# Le user data permet d'executer le script d'installatin du web server lors de lancement de la machine
user_data = <<-EOF
#!/bin/bash
sleep 60
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
echo "<html><body><h1>Hello from your instance!</h1></body></html>" > /var/www/html/index.html
EOF
}

resource "aws_instance" "instance_backend" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = aws_subnet.private_subnet_lab1.id
vpc_security_group_ids = [aws_security_group.private_sg.id]
key_name = "lab1_key_pair"
root_block_device {
delete_on_termination = true
}
tags = {
Name = "instance_backend"
}
# cette instruction permet de creer aws_key_pair avant la VM
depends_on = [aws_key_pair.lab1_key_pair]
}

# Exemple d'utilisation de variables
variable "instance_type" {
description = "Type d'instance à utiliser"
default = "t2.micro"
}
variable "ami_id" {
description = "ID de l'AMI à utiliser"
default = "ami-08a52ddb321b32a8c" # Remplacez par l'AMI par défaut
}

Une fois que les instances sont deployées, nous avons besoin de nous connecter à ces dernières pour les administrer. Pour cela, nous avons besoin des clés SSH.

Si vous etes sous Linux, c’est tres simple de générer la paire de clé avec la commande ssh-keygen -t rsa. Si vous êtes sous windows, je vous invite à suivre ce tutoriel pour générer votre paire de clés.

La clés publique ainsi générée est attribué aux instances lors de leur déploiement. Aussi, veillez garder la clé privée jalousement sur votre machine et ne partager avec personne, car elle permet d’administrer la machine créée.

  resource "aws_key_pair" "lab1_key_pair" {
key_name = "lab1-keypair" # Nom de la paire de clés
public_key = file("~/.ssh/id_rsa.pub") # Chemin vers la clé publique
}

Une fois la paire de clés générée, le code ci-dessus permet de créer une ressource correspondante coté AWS.

Ceci marque la fin du script Terraform pour l’infrastruture que nous souhaitons mettre en place. Nous allons pouvoir déployer notre infra.

Exécution

Nous enregistrons le script dans un fichier qui s’appelle main.tf et passons au déploiement des ressources.

lancez la commande Terraform init et ensuite Terraform plan

Le Terraform plan nous montre le plan l’exécution du script, les ressources à créer, à supprimer ou à changer.

Au total, il y’aura 17 ressources à deployer. Si nous sommes d’accord avec ce plan, nous pouvons lancer le Terraform apply

nous patientons jusqu’a la création de toutes les ressources. après cela, nous pouvons aller consulter dans la console AWS et effectuer les tests.

Terraform a terminé le déploiement des ressources. allons voir coté console AWS.

Quand nous tapons sur l’IP publique dans le navigateur, nous obtenons une page HTML avec le message que nous avons mis dans la partie user data de l’instantce frontend.

De même, nous pouvons aussi aller sur le serveur frontend en ssh comme le montre la capture suivante.

Et enfin, nous pouvons aussi nous connecter au serveur backend depuis le frontend(mode bastion) en ssh. on utilise le serveur exposé sur internet comme bastion. En ssh cela donne: ssh -J ec2-user@54.242.33.110 ec2-user@10.0.2.88 (veuillez remplacer les IPs privées et publiques par les IPs de vos instances respectives).

Nous arrivons au terme de cet article dans lequel nous avons implanté une infrastructure complète sur AWS avec Terraform. Cette automatisation nous permet de redéployer notre infra à chaque instant que nous avons besoin (recouvrement après désastre ou cas d’un ransomware).

Vous pouvez retrouver l’ensemble de ce script dans mon repo github suivant: https://github.com/YoussoufouOusmanou/Iac-Terraform-aws/tree/main

Comme vous avez pu le constater, ce code n’est pas modulaire, les ressources ne sont pas séparées et ne sont pas réutilisable. c’est pourquoi dans le prochain article sur le sujet, nous allons écrire des modules qui pourrons être appelés par une fonction principal pour déployer les différentes briques de l’infra.

Si vous avez des questions, écrivez moi sur mon compte linkedIn je vous répondrai avec plaisir.

N’hésitez pas à me laisser des suggestions sur l’article en commentaire.

--

--

YOUSSOUFOU Ousmanou

AWS Cloud and DevOps Engineer. I help you automate tasks on AWS Cloud.