Master Expert Technologie de l'information EPITECH 2020.
Co-fondateur et CTO d'une startup dans l'Edtech 2019 - fin 2022. (+3 ans)
Formation PSPO-1 Agile Scrum 2022.
Co-fondateur et CTO d'une startup dans la Deeptech fin 2022 - aujourd'hui.
Mettre en place un déploiement automatique d'application
Maitriser la Stratégie DevOps et évoluer vers le DevSecOps
Les enjeux de la sécurité pour tous les environnements
Implémenter une chaine de surveillance orientée Cybersécurité
Chaque séance débutera par la présentation d'un concept et de l'intérêt d'utilisation de celui-ci.
Après la théorie, nous verrons alors la pratique en réalisant des exercices sur un repository gitlab.
Nous verrons ensemble la correction des travaux pratiques. N'hésitez pas à poser vos questions.
Définir toute son infrastructure via des fichiers de configuration.
Automatiser la création, l'édition et la suppression des ressources de l'infrastructure dans le cloud.
Suivre les différentes versions de l'infrastructure en fonction de la solution.
Automatise le déploiement sur tous les grands Clouds.
Est capable de gérer des grands cluster avec Kubernetes.
S'intègre facilement dans les pipelines CI / CD.
Est devenu une référence comme outil d'IaC.
Des fonctionnalités internes pour gérer des situations complexes.
Plusieurs outils CI / CD ont déjà des intégrations.
CaC et IaC sont deux moyens de gérer les ressources de l'infrastructure, mais ils se concentrent sur des choses différentes :
Le CaC gère la configuration, les logiciels et les paramètres au sein des serveurs, comme les paramètres des utilisateurs et les configurations des applications. Ansible et Puppet sont des exemples d'outils CaC.
Conclusion : alors que l'IaC met en place l'environnement, le CaC s'assure que le logiciel au sein de cet environnement fonctionne correctement.
Terraform a été mis en open-source en 2014 sous la Mozilla Public License (v2.0). Puis, le 10 août 2023, avec peu ou pas de préavis, HashiCorp a changé la licence pour Terraform de la MPL à la Business Source License (v1.1), une licence non open source.
OpenTofu est un fork de la version Open source de Terraform et est géré par la fondation Linux. C'est donc une bonne alternative à Terraform aujourd'hui.
La migration à OpenTofu est extrêmement simple car il n'y a pas de différence de fonctionnement avec Terraform.
HCL, ou HashiCorp Configuration Language, est un langage lisible par l'homme pour les outils DevOps. Il est utilisé pour coder la gestion de l'infrastructure et l'orchestration des services de manière claire et gérable.
HCL est conçu pour trouver un équilibre entre un langage de configuration générique comme JSON ou YAML et un langage de script de haut niveau.
Plusieurs produits HashiCorp, dont Terraform, utilisent HCL comme langage de configuration principal. Sa syntaxe et sa structure claires permettent de créer des modules de ressources et des configurations.
La syntaxe de base du langage de configuration HCL comprend la définition de blocs, d'attributs et d'expressions.
Les blocs sont des unités fondamentales telles que la ressource, le module et le provider, identifiées par des mots-clés et placées entre accolades.
Les attributs sont des paires clé-valeur à l'intérieur des blocs, où les clés sont des chaînes et les valeurs peuvent être des chaînes, des nombres ou d'autres types de données.
Les expressions permettent d'intégrer des variables, des fonctions et des références à d'autres ressources, ce qui permet des configurations dynamiques.
resource "aws_instance" "ec2" { # <-- Bloc ressource : type "aws_instance", nom "ec2"
ami = data.aws_ami.amazon_linux_2.id # <-- Expression : référence à une autre ressource
instance_type = var.instance_type # <-- Expression : variable d'entrée
key_name = "staging" # <-- Attribut string
user_data = <<-EOF # <-- Bloc d'attribut multi-lignes (heredoc)
#!/bin/bash
yum update -y
yum install -y awscli jq docker
service docker start
export GITLAB_PASSWORD=$(echo $(aws secretsmanager get-secret-value --secret-id GITLAB_CONTAINER_REGISTRY --query SecretString --output text --region eu-west-3) | jq -r '.password')
echo $(aws secretsmanager get-secret-value --secret-id workspace/staging --query SecretString --output text --region eu-west-3) | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" > .env
docker login registry.gitlab.com -u vm-singularity -p $GITLAB_PASSWORD
docker run --env-file .env -d -p 80:80 registry.gitlab.com/marvelab/workspace:${var.hash}
EOF
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name # <-- Référence à une autre ressource
vpc_security_group_ids = [aws_security_group.ec2.id] # <-- Liste avec référence
# Bloc d'attributs imbriqué pour les tags
tags = {
Name = "${var.namespace}_EC2_${var.environment}" # <-- Interpolation de variables
}
user_data_replace_on_change = true # <-- Attribut booléen
}
Les Providers sont des plugins qui permettent d'interagir avec diverses API externes. Ils gèrent le cycle de vie des ressources en définissant les types de ressources et les sources de données.
Chaque Provider nécessite une configuration, qui comprend généralement des détails d'authentification et des URLs.
Les Providers sont spécifiés dans le bloc provider, et plusieurs Providers peuvent être utilisés dans un seul projet Terraform pour gérer les ressources sur différentes plateformes.
Permet de découvrir, de partager et d'utiliser les modules et Providers Terraform.
La configuration est réalisée dans le bloc provider de vos fichiers de configuration Terraform. Ce bloc comprend des paramètres tels que les identifiants d'authentification, la région et d'autres paramètres spécifiques au provider.
Les providers doivent être initialisés à l'aide de terraform init pour télécharger et installer les plugins nécessaires.
Des configurations multiples peuvent être gérées en créant des alias de provider, ce qui permet de gérer les ressources dans différents environnements ou comptes au sein d'un même provider.
La spécification des versions des Providers dans Terraform garantit un comportement cohérent et prévisible dans différents environnements. La version doit être définie dans le bloc required_providers.
Cette approche permet d'éviter les changements inattendus ou les problèmes de compatibilité dus aux mises à jour des providers, améliorant ainsi la stabilité et la fiabilité de la gestion de l'infrastructure.
# Bloc principal de configuration de Terraform
terraform {
# Déclaration des providers nécessaires pour ce projet
required_providers {
aws = {
# Le provider AWS est développé par HashiCorp (source officielle)
source = "hashicorp/aws"
# Spécifie la version du provider AWS compatible
version = "~> 4.16"
}
}
# Version minimale de Terraform requise pour exécuter ce projet
required_version = ">= 1.2.0"
}
# Configuration du provider AWS
# Ce bloc précise comment Terraform va interagir avec AWS
provider "aws" {
# Région AWS cible : ici, eu-west-3 correspond à la région "Paris"
region = "eu-west-3"
# Optionnel : vous pouvez ajouter un profil si vous utilisez ~/.aws/credentials
# profile = "mon-profil"
# Terraform utilisera automatiquement vos identifiants AWS si :
# - vous les avez définis via les variables d’environnement AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY
# - ou vous avez un fichier ~/.aws/credentials correctement configuré
}
Représente des composants de l'infra comme les VMs, les buckets, les bases de données ou les VPS.
Chaque déclaration génère l'élément côté Provider après execution de Terraform.
Chaque resource est configurable en fonction du Provider.
Lorsque Terraform crée un nouvel objet d'infrastructure représenté par un bloc de ressources, l'identifiant de cet objet réel est enregistré dans le State de Terraform, ce qui permet de le mettre à jour et de le détruire en réponse à des changements futurs.
Pour les blocs de ressources qui ont déjà un objet d'infrastructure associé dans le State, Terraform compare la configuration réelle de l'objet avec les arguments donnés dans la configuration et, si nécessaire, met à jour l'objet pour qu'il corresponde à la configuration.
L'application d'une configuration Terraform va :
Pour accéder à une ressource dans un fichier de configuration, on utilise une Expression qui a la syntaxe suivante : <RESOURCE TYPE>.<NAME>.<ATTRIBUTE>
On peut accéder à une ressource pour ses attributs en lecture seule obtenues à partir de l'API distante ; il s'agit souvent d'éléments qui ne peuvent être connus avant la création de la ressource, comme l'id de la ressource.
De nombreux providers incluent également des Data sources, qui sont un type spécial de ressources utilisées uniquement pour rechercher des informations.
## Get most recent AMI for an ECS-optimized Amazon Linux 2 instance
data "aws_ami" "amazon_linux_2" {
most_recent = true
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-ecs-hvm-*-x86_64-ebs"]
}
owners = ["amazon"]
}
resource "aws_instance" "ec2" {
ami = data.aws_ami.amazon_linux_2.id # <-- Expression d'accès
instance_type = var.instance_type
...Les méta-arguments dans les ressources Terraform fournissent un contrôle supplémentaire sur la façon dont les ressources sont gérées et interagissent dans la configuration :
Permet de spécifier le nombre d'instances d'une ressource particulière à créer. Terraform génère dynamiquement plusieurs instances de la ressource, indexées de 0 à count-1.
Cette fonction est utile pour gérer des infrastructures qui nécessitent plusieurs ressources identiques ou similaires, telles que la création de plusieurs machines virtuelles ou de plusieurs buckets. Vous pouvez créer des ressources de manière conditionnelle en définissant la valeur en fonction de variables ou d'expressions.
Chaque instance de la ressource peut être référencée de manière unique à l'aide de la valeur count.index.
Déclare explicitement les dépendances entre les ressources, en s'assurant qu'une ou plusieurs ressources sont créées ou détruites seulement après que les ressources dépendantes spécifiées ont été appliquées avec succès.
Ceci est crucial pour gérer les dépendances de ressources qui ne sont pas automatiquement détectées par l'analyse implicite des dépendances de Terraform.
Permet de créer plusieurs instances d'une ressource en fonction d'un ensemble ou d'une map. Contrairement à count, qui utilise un simple entier, for_each permet une création de ressources plus granulaire et dynamique, puisque chaque instance est associée à une paire clé-valeur spécifique d'un objet ou d'une map.
Ce méta-argument est particulièrement utile pour créer des ressources avec des configurations uniques dérivées d'une map obtenu par un Data source par exemple.
Spécifie la configuration du provider à utiliser pour une ressource, en remplaçant la sélection du provider par défaut basée sur le nom du type de ressource.
Ceci est utile dans les scénarios où plusieurs configurations du même provider sont nécessaires, comme la gestion des ressources dans différentes régions ou environnements. En définissant l'argument provider, vous pouvez vous assurer que la ressource utilise la configuration spécifiée du fournisseur, identifiée par son alias.
Personnalise le comportement des ressources lors de leur création, de leur mise à jour et de leur suppression. Il comprend des paramètres tels que create_before_destroy, qui garantit qu'une nouvelle ressource est créée avant que l'ancienne ne soit détruite, ce qui évite les temps d'arrêt.
prevent_destroy protège les ressources contre les suppressions accidentelles, et ignore_changes spécifie les attributs à ignorer lors des mises à jour, ce qui permet d'apporter des modifications externes sans déclencher de changements dans Terraform.
Terraform utilise des variables pour rendre les configurations plus flexibles et réutilisables. Les variables peuvent être déclarées dans des fichiers .tf et se voir attribuer des valeurs par différentes méthodes, notamment des valeurs par défaut, des flags de ligne de commande, des variables d'environnement ou des fichiers .tfvars distincts. Elles prennent en charge plusieurs types de données tels que les chaînes de caractères, les nombres, les bools, les listes et les maps. Les variables peuvent être référencées dans toute la configuration à l'aide du préfixe var.<myVariable>.
Ce système permet à l'infrastructure en tant que code d'être plus dynamique et de s'adapter à différents environnements ou cas d'utilisation.
Les variables d'entrée Terraform sont des paramètres pour les modules, déclarés à l'aide de blocs de variables. Elles prennent en charge plusieurs types de données, des valeurs par défaut et des descriptions. Les utilisateurs fournissent des valeurs lorsqu'ils invoquent des modules ou exécutent Terraform.
Elles peuvent être marquées comme sensibles pour des raisons de sécurité et sont généralement définies dans un fichier variables.tf.
Exemple : Définir lors l'exécution que les instances EC2 seront de type T3.micro.
Les contraintes de type de variable Terraform spécifient les types de données autorisés pour les variables d'entrée. Elles incluent les types primitifs (string, number, bool), les types complexes (list, set, map, object), et any pour les types non spécifiés.
Les contraintes peuvent imposer des structures spécifiques, des types imbriqués ou des plages de valeurs. Elles sont définies dans l'argument de type du bloc de variables, ce qui permet de détecter rapidement les erreurs et de garantir une utilisation correcte des variables dans toutes les configurations.
# Déclaration d'une variable nommée "buckets"
variable "buckets" {
# On impose une contrainte de type stricte à cette variable :
# il s'agit d'une LISTE d'OBJETS, chacun représentant un bucket à créer
type = list(object({
# Chaque objet de la liste doit obligatoirement avoir une clé "name"
# de type chaîne de caractères (string)
name = string
# Clé facultative : "enabled"
# de type booléen, qui indique si le bucket est actif ou non
# Valeur par défaut : true (si non précisée dans l’appel)
enabled = optional(bool, true)
# Clé facultative : "website", qui elle-même est un objet complexe
website = optional(object({
index_document = optional(string, "index.html")
error_document = optional(string, "error.html")
routing_rules = optional(string)
# Valeur par défaut pour l’objet website : objet vide {}
}), {})
}))
}
Les valeurs locales peuvent être considérées comme un nom attribué à toute expression afin de pouvoir l'utiliser plusieurs fois directement par le nom dans votre module terraform. Les valeurs locales sont appelées locals et peuvent être déclarées à l'aide du bloc locals. Les valeurs locales peuvent être des constantes littérales, des attributs de ressources, des variables ou d'autres valeurs locales. Les valeurs locales sont utiles pour définir des expressions ou des valeurs que vous devez utiliser plusieurs fois dans le module, car elles permettent d'actualiser facilement la valeur en mettant simplement à jour la valeur locale. On peut accéder à une valeur locale en utilisant l'argument local comme local.<nom_de_la_valeur>.
locals {
# Ids for multiple sets of EC2 instances, merged together
instance_ids = concat(aws_instance.blue.*.id, aws_instance.green.*.id)
}
locals {
# Common tags to be assigned to all resources
common_tags = {
Service = local.service_name
Owner = local.owner
}
}
# Utilisation :
resource "aws_instance" "blue" {
# ...
tags = local.common_tags
}
Les variables d'environnement peuvent être utilisées pour modifier le comportement par défaut de terraform, par exemple augmenter la verbosité, mettre à jour le chemin du fichier journal, définir l'espace de travail, etc.
TF_VAR_name permet de donner une valeur à certaines variables comme par exemple :
export TF_VAR_region=us-west-1
export TF_VAR_ami=ami-049d8641
export TF_VAR_alist='[1,2,3]'
export TF_VAR_amap='{ foo = "bar", baz = "qux" }'
Les règles de validation peuvent être utilisées pour spécifier des validations personnalisées pour une variable. L'ajout de règles de validation a pour but de rendre la variable conforme aux règles. Les règles de validation peuvent être ajoutées à l'aide d'un bloc de validation dans un block variable.
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
Un output expose les valeurs sélectionnées d'une configuration ou d'un module, les rendant accessibles aux utilisateurs ou à d'autres modules.
Définies dans des blocs de sortie, généralement dans un fichier outputs.tf, ils peuvent faire référence à des attributs de ressources ou à d'autres valeurs calculées.
Les sorties sont affichées après les opérations d'application, peuvent être interrogées à l'aide de commande Terraform et sont essentielles pour transmettre des informations entre les modules ou à des systèmes externes.
# Déclaration d'une sortie (output) dans Terraform
# Les outputs permettent d'exposer certaines valeurs après l'exécution.
output "name" {
# La valeur que Terraform affichera en sortie
# Il peut s’agir d’un nom de ressource, d’un attribut, d’une variable, etc.
# Exemple concret : aws_s3_bucket.mon_bucket.bucket
value = expression
# (Facultatif) Une description textuelle de la sortie
# Utile pour la documentation et la compréhension dans les grands projets
description = "Optional description"
# (Facultatif) Marque cette sortie comme sensible
# Cela empêche Terraform d'afficher la valeur dans la console ou les logs
# Exemple d'utilisation : mots de passe, clés d’API, tokens
sensitive = bool
}
L'attribut sensitive est une fonctionnalité utilisée pour protéger les informations sensibles dans les configurations Terraform. Lorsqu'une sortie est marquée comme sensible, Terraform obscurcit sa valeur dans la sortie de la console, en l'affichant sous la forme <sensitive> au lieu de la valeur réelle.
Cette fonction est essentielle pour protéger les données sensibles telles que les mots de passe ou les clés d'API.
Terraform possède un CLI permettant d'exécuter des commandes.
Voici les commandes principales à connaître pour vérifier, planifier, lancer et détruire votre infrastructure :
terraform fmtterraform validateterraform planterraform applyterraform destroyFormate automatiquement les fichiers de configuration dans un style cohérent. Elle ajuste l'indentation, aligne les arguments et trie les blocs et les arguments par ordre alphabétique. La commande réécrit les fichiers de configuration Terraform (.tf et .tfvars) dans le répertoire courant et ses sous-répertoires.
Elle est utilisée pour maintenir un style cohérent entre les projets et les équipes, améliorant la lisibilité et réduisant les conflits de fusion.
Bonne pratique : utiliser un git hook pour automatiser le lancement de la commande avant chaque commit.
Permet de vous assurer que votre code Terraform est syntaxiquement correct avant de le déployer.
Vous évitez ainsi les erreurs de configuration dues à des attributs manquants ou à des dépendances incorrectes, ce qui vous permet de gagner du temps, d'améliorer l'efficacité et de réduire les coûts.
Bonne pratique : utiliser un git hook pour automatiser le lancement de la commande avant chaque commit.
Crée un plan d'exécution, montrant les changements que Terraform va apporter à votre infrastructure.
Il compare l'état actuel avec l'état souhaité défini dans les fichiers de configuration et produit une liste détaillée des ressources à créer, modifier ou supprimer. Il est important de noter qu'il n'apporte aucun changement réel à l'infrastructure, mais qu'il aide à identifier les problèmes potentiels avant d'appliquer les changements. Le plan peut être enregistré dans un fichier en vue d'une exécution ou d'une révision ultérieure.
Bonne pratique : Lancer la commande dans un job de votre CI pour valider les modifications d'infrastructure proposées.
Mets en œuvre les changements définis dans vos fichiers de configuration Terraform. Elle crée, met à jour ou supprime les ressources d'infrastructure spécifiées afin qu'elles correspondent à l'état souhaité.
Avant d'effectuer les changements, elle affiche un plan similaire à terraform plan et demande une confirmation, sauf si l'option -auto-approve est utilisée.
Apply met à jour le fichier d'état pour refléter l'état actuel de l'infrastructure, ce qui permet à Terraform de suivre et de gérer les ressources au fil du temps. Il gère les dépendances entre les ressources, en les créant dans le bon ordre.
Supprime toutes les ressources gérées par une configuration Terraform. Elle crée un plan de suppression de toutes les ressources et demande une confirmation avant l'exécution. Cette commande est utile pour nettoyer des environnements temporaires ou mettre hors service des infrastructures entières.
Elle supprime les ressources dans l'ordre inverse de leurs dépendances pour garantir un démantèlement correct.
Après la destruction, Terraform met à jour le fichier state pour refléter les changements, mais il est important de gérer ou de supprimer ce fichier si le projet est complètement déclassé.
Permet de suivre l'état actuel de votre infrastructure gérée. Il est généralement stocké dans un fichier nommé terraform.tfstate, qui associe les ressources du monde réel à votre configuration.
Cet état permet à Terraform de déterminer quels changements sont nécessaires pour obtenir la configuration souhaitée.
Il contient des informations sensibles et doit être stocké de manière sécurisée, souvent dans des backends distants comme S3 ou Terraform Cloud.
Terraform est un très bon outil pour réaliser du CI / CD dans un projet. Il permet d'automatiser le déploiement de l'infrastructure à chaque nouvelle version de votre application.
Pour cela, je vous propose de consulter un exemple simple d'un déploiement d'une image Docker sur AWS via Github Actions :
Et la slide suivante pour voir le job permettant le déploiement.
deploy-image:
runs-on: ubuntu-latest
needs: build-image
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-3
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
- name: Terraform Init
run: terraform init
- name: Terraform Format
run: terraform fmt -check
- name: Terraform Plan
run: terraform plan -input=false
- name: Terraform Apply
run: terraform apply -auto-approve -input=false
# Add condition here to avoid to deploy when checking a PR.En premier lieu, nous allons maintenant installer Terraform sur votre machine : https://developer.hashicorp.com/terraform/install
Vérifiez que vous Terraform est bien installé avec la commande suivante : terraform -v
Ensuite, créez le dossier "TP-local" et créez à l'intérieur le "main.tf" qui sera le fichier principal de votre infrastructure :
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
provider "local" {}
resource "local_file" "test_file" {
content = "Hello depuis Terraform !"
filename = "${path.module}/hello.txt"
}Pour l'instant, nous allons utiliser le provider "local" qui permet de réaliser des changements en local sur votre machine.
Dans le fichier main.tf, la resource local_file permet de générer un nouveau fichier.
Initialisez le projet avec la commande :
terraform init
Lancez les commandes suivantes :
terraform fmtterraform validateterraform planterraform apply
Vérifiez que les changements, que remarquez-vous ?
Nous allons maintenant modifier notre "infrastructure", changer le contenu de votre fichier hello.txt qui a pour nom "test_file" dans votre configuration.
Relancez les différentes commandes précédentes.
Que remarquez-vous ?
Nous allons maintenant ajouter une commande qui va s'exécuter automatiquement.
Ajoutez dans votre main.tf le code suivant :
Ajoutez les dépendances nécessaire avec la commande :
terraform init -upgrade
Exécutez à nouveau la configuration, qu'observez-vous ?
resource "null_resource" "example" {
provisioner "local-exec" {
command = "echo 'Commande exécutée !'"
}
}
Maintenant que nous avons terminé avec cette configuration, vous allez pouvoir la détruire, pour cela exécutez la commande :
terraform destroy
Qu'observez-vous ?
Oui, le fichier terraform.tfstate est toujours présent avec sa sauvegarde, nous allons les supprimer car nous n'allons plus utiliser cette configuration.
Nous allons maintenant créer une infrastructure en utilisant Docker pour simuler ce que l'on va pouvoir réaliser avec un Cloud Provider. Remplacez le contenu de main.tf par celui-ci :
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "3.5.0"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = true
}
resource "docker_container" "nginx" {
name = "nginx-terraform"
image = docker_image.nginx.image_id
ports {
internal = 80
external = 8080
}
}
Attention, pour MacOS et Windows, cela peut ne pas fonctionner sans plus de configuration.
Pour Windows, vous devez allez via General > Expose Daemon on tcp://localhost:2375 et ajouter dans le block provider "docker" la ligne :
host = "tcp://localhost:2375".
Pour MacOS, vous devez mettre le bon chemin :
host = "unix://${pathexpand("~/.docker/run/docker.sock")}"
Exécutez cette configuration.
Que remarquez-vous ?
Appelez-moi pour que valider ensemble.
Bravo, vous avez terminé ce premier TP !
Je vous invite maintenant à supprimer l'infrastructure actuelle et de passer aux exercices.
Ajoutez des variables Terraform à la place des valeurs codées en dur suivantes :
Le nom de l’image Docker (nginx:latest)
Le nom du conteneur
Le port externe exposé
Le port interne du conteneur
Vous devez :
Déclarer chaque variable dans le fichier variables.tf
Fournir des valeurs par défaut
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez un output nommé nginx_container_id à votre configuration Terraform.
Celui-ci doit afficher l’identifiant (id) du conteneur nginx créé avec la ressource docker_container.nginx.
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez une commande à votre configuration Terraform qui permet de tester automatiquement que le serveur Nginx déployé sur le port spécifié répond avec une page d’index.
La commande doit tester l’URL :
http://localhost:<external_port>
Et vérifier que la réponse contient le mot Welcome (présent dans l’index par défaut de Nginx).
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez un deuxième conteneur Docker nommé client, basé sur l’image appropriate/curl, qui exécutera une commande pour appeler le serveur nginx (déjà déployé).
Pour cela, vous devez :
Créer un réseau Docker dédié.
Connecter les deux conteneurs à ce réseau.
Faire en sorte que le conteneur client utilise curl pour interroger http://nginx:80 et sleep ensuite.
Vérifier que la communication fonctionne dans le conteneur client.
Appelez-moi pour que l'on puisse valider ensemble.
Reprenez l'exercice précédent, puis :
Modifiez le conteneur client pour qu’il soit déployé en plusieurs exemplaires (ex. 3) à l’aide de count.
Assurez-vous que chaque conteneur :
ait un nom unique (client-0, client-1, etc.),
soit connecté au même réseau Docker que nginx,
exécute un curl http://nginx suivi d’un sleep de 30 secondes.
Le nombre de clients doit être paramétrable via une variable.
Appelez-moi pour que l'on puisse valider ensemble.
Reprenez l'exercice précédent, transformez le count par un for_each qui doit boucler sur une liste de nom pour vos serveurs.
Chaque serveur doit posséder le bon nom :
server-<nom>
Appelez-moi pour que l'on puisse valider ensemble.
Vous êtes en train de créer un module Terraform qui déploie des machines virtuelles. Chaque machine doit être définie avec : un nom, un nombre de vCPU (min. 2, max. 64), une taille de disque (en Go, min. 20), une région (parmi : "eu-west-1", "us-east-1", "ap-southeast-1").
Créez une variable machines de type liste d'objets contenant les 4 attributs cités.
Ajoutez une validation personnalisée sur : les vcpu (entre 2 et 64),
le disk_size (>= 20), la region.
Appelez-moi pour que l'on puisse valider ensemble.
Pour utiliser un Provider comme AWS, il faut le configurer pour qu'il puisse se connecter à notre compte AWS.
Pour cela, la documentation du Provider indique plusieurs manières de faire :
Je recommande d'utiliser la méthode 2 qui est pour moi plus sécurisé.
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "us-east-1"
}
# Create a VPC
resource "aws_vpc" "example" {
cidr_block = "10.0.0.0/16"
}
# terminal
% export AWS_ACCESS_KEY_ID="anaccesskey"
% export AWS_SECRET_ACCESS_KEY="asecretkey"
% terraform planExemple de configuration :
Le Provider AWS possède plus de 1499 ressources, c'est pour cela que nous n'allons voir que les plus simples durant cet atelier.
Débutons par la ressource de base, l'instance AWS qui est une instance EC2 :
Lien vers la documentation complète
(Le panel de gauche permet de rechercher à l'intérieur)
Un exemple est disponible à la slide suivante.
resource "aws_instance" "ec2" {
# ID de l'AMI Amazon Linux 2, récupéré dynamiquement via un data source
ami = data.aws_ami.amazon_linux_2.id
# Type d'instance défini via une variable (ex: t2.micro, t3.medium, etc.)
instance_type = var.instance_type
# Nom de la clé SSH permettant d'accéder à l'instance
key_name = "staging"
# Script shell exécuté au démarrage de l'instance (cloud-init)
user_data = <<-EOF
#!/bin/bash
yum update -y # Mise à jour des paquets
yum install -y awscli jq docker # Installation de l’AWS CLI, jq (JSON parser) et Docker
service docker start # Démarrage du service Docker
EOF
# Profil IAM attaché à l’instance pour lui donner des permissions AWS (ex: accès à S3)
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
# Liste des IDs de groupes de sécurité associés à l’instance
vpc_security_group_ids = [aws_security_group.ec2.id]
# Étiquettes (tags) appliquées à l’instance pour l'organisation et le suivi
tags = {
Name = "${var.namespace}_EC2_${var.environment}" # Exemple : "dev_EC2_staging"
}
# Forcer le remplacement de l'instance si le user_data change
user_data_replace_on_change = true
}
Pour nous connecter à nos instances, nous allons avoir besoin de clés SSH. Voici comment générer et configurer une paire de clé :
ssh-keygen -t rsa -b 4096 -f ~/.ssh/my-ec2-key
Ne jamais partager la clé privée.
Exemple de configuration avec AWS :
provider "aws" {
region = "eu-west-3"
}
resource "aws_key_pair" "my_key" {
key_name = "my-ec2-key"
public_key = file("~/.ssh/my-ec2-key.pub")
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0" # à adapter à la région
instance_type = "t2.micro"
key_name = aws_key_pair.my_key.key_name
tags = {
Name = "Terraform-Instance"
}
}
Pour éviter d'utiliser directement un vrai compte AWS qui pourrait être coûteux ou laborieux quand vous devez réaliser des tests, nous allons utiliser un outil très puissant : Localstack.
Installez Localstack en suivant les instructions dans le Readme du projet.
Vérifiez l'installation de Localstack avec la commande :
localstack -v
Puis démarrez l'environnement local :
localstack start
Nous allons maintenant installer le CLI d'AWS.
Pour MacOS :
brew install awscli
Pour Windows :
https://awscli.amazonaws.com/AWSCLIV2.msi
Pour Linux :
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Vérifiez la bonne installation du CLI :
aws --version
Nous allons devoir ajouter des configurations non nécessaire normalement vu que nous allons être sur un faux environnement d'AWS dans le main.tf :
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
access_key = "test"
secret_key = "test"
region = "us-east-1"
# LocalStack endpoint configuration
s3_use_path_style = true
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
s3 = "http://localhost:4566"
ec2 = "http://localhost:4566"
}
}Nous allons créer une ressource emblématique d'AWS, un bucket S3 pour pouvoir stocker des fichiers.
Pour cela, nous allons créer le fichier s3.tf :
# Create an S3 bucket
resource "aws_s3_bucket" "demo_bucket" {
bucket = "my-bucket"
}
# Enable versioning for the bucket
resource "aws_s3_bucket_versioning" "demo_bucket_versioning" {
bucket = aws_s3_bucket.demo_bucket.id
versioning_configuration {
status = "Enabled"
}
}
# Upload a file to the bucket
resource "aws_s3_object" "demo_object" {
bucket = aws_s3_bucket.demo_bucket.id
key = "hello-world.txt"
source = "./test-file.txt"
etag = filemd5("./test-file.txt")
}Dans la slide précédente, on peut voir que l'on upload un fichier sur notre Bucket, nous allons donc créer le fichier test-file.txt :
Lancez l'initialisation du projet Terraform, planifiez et appliquez les changements. Vérifiez vos changements avec les commandes suivantes pour Linux et MacOS :
AWS_ACCESS_KEY_ID="test" AWS_SECRET_ACCESS_KEY="test" AWS_DEFAULT_REGION="us-east-1" aws --endpoint-url=http://localhost:4566 s3 ls
AWS_ACCESS_KEY_ID="test" AWS_SECRET_ACCESS_KEY="test" AWS_DEFAULT_REGION="us-east-1" aws --endpoint-url=http://localhost:4566 s3 ls s3://my-bucket
Hello, World! This is a test file for my Terraform and LocalStack demo.Pour Windows :
& { $env:AWS_ACCESS_KEY_ID = "test"; $env:AWS_SECRET_ACCESS_KEY = "test"; $env:AWS_DEFAULT_REGION = "us-east-1"; aws --endpoint-url=http://localhost:4566 s3 ls }
& { $env:AWS_ACCESS_KEY_ID = "test"; $env:AWS_SECRET_ACCESS_KEY = "test"; $env:AWS_DEFAULT_REGION = "us-east-1"; aws --endpoint-url=http://localhost:4566 s3 ls s3://my-bucket }
Maintenant que notre bucket est fonctionnel, nous allons créer une instance EC2 qui lancera un Nginx, créez le fichier ec2.tf :
# Generate SSH key
resource "tls_private_key" "key" {
algorithm = "RSA"
rsa_bits = 4096
}
# Create key pair
resource "aws_key_pair" "deployer" {
key_name = "deployer-key"
public_key = tls_private_key.key.public_key_openssh
}
# Store private key locally
resource "local_file" "private_key" {
content = tls_private_key.key.private_key_pem
filename = "${path.module}/deployer-key.pem"
file_permission = "0600"
}
# Create EC2 instance with Nginx
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t2.micro"
security_groups = [aws_security_group.web.name]
key_name = aws_key_pair.deployer.key_name
user_data = <<-EOF
#!/bin/bash
# Install and configure Nginx
yum update -y
amazon-linux-extras install -y nginx1
systemctl start nginx
systemctl enable nginx
# Create a simple webpage
echo "<h1>Hello from Terraform and LocalStack!</h1>" > /usr/share/nginx/html/index.html
EOF
tags = {
Name = "nginx-server"
}
}
Avec AWS, la connexion à une instance doit être géré par des ressources réseau comme un groupe de sécurité, créez sg.tf :
# Create a security group for the EC2 instance
resource "aws_security_group" "web" {
name = "nginx-sg"
description = "Allow web and SSH traffic"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow HTTP traffic"
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow SSH traffic"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound traffic"
}
tags = {
Name = "nginx-sg"
}
}
Pour vérifier que notre instance EC2 fonctionne correctement, nous allons récupérer des informations, malheureusement localstack ne va pas jusqu'à simuler une vraie VM capable d'exécuter nginx, nous allons juste vérifier si elle est bien lancé.
Créez outputs.tf :
output "instance_id" {
description = "ID of the EC2 instance"
value = aws_instance.web.id
}
output "instance_public_ip" {
description = "Public IP of the EC2 instance"
value = aws_instance.web.public_ip
}
output "ssh_command" {
description = "SSH command to connect to the instance"
value = "ssh -i deployer-key.pem ec2-user@${aws_instance.web.public_ip}"
}Lancez l'application de la nouvelle configuration et vérifiez que l'instance EC2 est bien présente :
AWS_ACCESS_KEY_ID="test" AWS_SECRET_ACCESS_KEY="test" AWS_DEFAULT_REGION="us-east-1" aws --endpoint-url=http://localhost:4566 ec2 describe-instances --instance-ids <Instance ID>
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez des variables Terraform à la place des valeurs codées en dur suivantes :
Le type d'instance EC2
Le nom de l'instance EC2
Le nom du bucket S3
Le port par défaut pour le groupe de sécurité
Vous devez :
Déclarer chaque variable dans le fichier variables.tf
Fournir des valeurs par défaut
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez un output nommé bucket_id à votre configuration Terraform.
Celui-ci doit afficher l’identifiant (id) du bucket créé avec la ressource aws_s3_bucket.demo_bucket.
Appelez-moi pour que l'on puisse valider ensemble.
Grâce aux exercices précédents, une application web statique est déployée sur une instance EC2 avec Nginx. Nous allons maintenant déployer une nouvelle instance EC2 qui contiendra une base de donnée.
Vous devez :
Créer une nouvelle instance EC2
Changer la configuration pour qu'on puisse facilement l'identifier comme le serveur de la base de donnée.
Appelez-moi pour que l'on puisse valider ensemble.
Maintenant que vous avez validé plusieurs configurations grâce à Localstack, le but est de mettre en place sur un vrai compte AWS la dernière configuration et de vérifier son bon fonctionnement.
Arrêtez et retirer la configuration en lien avec Localstack et les buckets et déployez directement sur le compte AWS fournit pour l'atelier.
Créez une paire de clé et liez les à votre instance EC2 pour vous permettre de vous connecter via SSH à l'instance.
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez un S3 bucket à votre infrastructure.
Créez un fichier en local "test-file.txt" avec comme contenu "Hello World" et ajoutez dans la configuration l'upload du fichier sur le bucket S3.
Appelez-moi pour que l'on puisse valider ensemble.
Maintenant que vous avez un bucket S3, ajoutez les permissions pour permettre la lecture de tous les fichiers à l'intérieur par n'importe qui.
On doit pouvoir accéder à l'objet S3 via son URL.
Appelez-moi pour que l'on puisse valider ensemble.
Récupérez un projet que vous avez déjà réalisé et réalisez une image Docker pour chaque partie de ce projet.
Déployez les images Docker de votre projet en utilisant Terraform sur le compte AWS fournit pour cet atelier sur plusieurs instances EC2.
Vous pouvez utiliser l'IP publique généré pour chaque EC2 par AWS pour les faire communiquer.
Appelez-moi pour que l'on puisse valider ensemble.
Logiciel open-source pour automatiser le déploiement, la configuration et la gestion d’infrastructures.
Contrairement à d’autres outils, n’utilise pas d'agent mais SSH pour se connecter et exécuter les tâches.
Les tâches à exécuter sont décrites de manière déclarative dans des fichiers au format YAML.
Complémentarité entre provisionnement et configuration : Terraform est idéal pour créer l’infrastructure, tandis qu’Ansible excelle dans la configuration des machines (installation de paquets, déploiement d’applications).
Séparation des responsabilités : Utiliser Terraform pour gérer l’état de l’infrastructure et Ansible pour appliquer des configurations cela sépare "ce qui est" (l’infra) de "ce qu’elle fait" (les services qu’elle héberge).
Flexibilité post-provisionnement : Ansible peut être relancé facilement et indépendamment pour appliquer des mises à jour, corriger une configuration ou réagir à un changement, sans toucher à l’infrastructure sous-jacente.
L’inventaire (ou inventory) est un fichier ou une source dynamique qui liste tous les hôtes (machines) que Ansible peut gérer.
Il permet aussi de regrouper ces hôtes, de leur affecter des variables, et de cibler précisément les machines sur lesquelles exécuter des tâches.
Par défaut, l’inventaire est un fichier texte situé dans /etc/ansible/hosts ou défini via -i dans la ligne de commande.
[webservers]
web1.example.com ansible_host=192.168.1.100
web2.example.com ansible_host=192.168.1.101
[dbservers]
db1.example.com ansible_host=192.168.1.200 mysql_port=3306
db2.example.com ansible_host=192.168.1.201 mysql_port=3306
# Production Environment Group using another group
[production:children]
webservers
dbservers
# Specific Server Variables
[webservers:vars]
http_port=80
https_port=443
# Group with Connection Variables
[remote_servers]
remote1.example.com ansible_host=203.0.113.10 ansible_user=admin ansible_ssh_private_key_file=/path/to/private/key
# Global SSH Connection Defaults
[all:vars]
ansible_connection=ssh
ansible_user=ansible
ansible_become=yes
ansible_become_method=sudoUn Playbook est un fichier YAML qui décrit une ou plusieurs séquences de tâches à exécuter sur un ou plusieurs hôtes.
Il permet d’automatiser des configurations, des déploiements, ou de l’orchestration de services de manière déclarative.
On parle de scénario, contenant des tasks, exécutées sur des hosts.
---
- hosts: webservers # <-- Means the tasks will run on all servers in the webservers group
tasks:
- name: Ensure nginx is installed
apt: # <-- Use APT to install packages on Debian / Ubuntu
name: nginx
state: present
- name: Configure web server
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart Nginx # <-- Call handler Restart Nginx
handlers:
- name: Restart Nginx
service: # <-- Use Debian / Ubuntu's service system
name: nginx
state: restarted---
- hosts: webservers
become: yes # Use sudo for elevated privileges
vars:
# Centralized variables for easy management
web_package: nginx
web_port: 80
application_name: myapp
app_root_directory: "/var/www/{{ application_name }}"
# Pre-tasks run before roles and tasks
pre_tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600 # Only update if older than 1 hour
when: ansible_os_family == 'Debian'
# Roles allow for modular, reusable configuration
roles:
- role: security
tags:
- security
- role: webserver
tags:
- web
# Individual tasks for specific configurations
tasks:
- name: Ensure web server is installed
apt:
name: "{{ web_package }}"
state: present
tags:
- packages
- name: Create application directory
file:
path: "{{ app_root_directory }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
tags:
- app-setup
- name: Deploy application code
git:
repo: 'https://github.com/yourorg/yourapp.git'
dest: "{{ app_root_directory }}"
version: main # Specify branch/tag
notify:
- Restart Nginx
tags:
- deployment
- name: Configure Nginx virtual host
template:
src: templates/nginx-site.conf.j2
dest: "/etc/nginx/sites-available/{{ application_name }}"
notify:
- Validate Nginx Configuration
- Restart Nginx
tags:
- configuration
- name: Enable Nginx site
file:
src: "/etc/nginx/sites-available/{{ application_name }}"
dest: "/etc/nginx/sites-enabled/{{ application_name }}"
state: link
notify:
- Restart Nginx
tags:
- configuration
- name: Set up application environment
copy:
content: |
DB_HOST={{ database_host }}
DB_USER={{ database_user }}
SECRET_KEY={{ secret_key }}
dest: "{{ app_root_directory }}/.env"
owner: www-data
group: www-data
mode: '0600'
no_log: true # Prevents logging sensitive information
tags:
- secrets
# Handlers for service management
handlers:
- name: Validate Nginx Configuration
command: nginx -t
register: nginx_test
failed_when: nginx_test.rc != 0
changed_when: false
- name: Restart Nginx
service:
name: nginx
state: restarted
# Post-tasks run after roles and tasks
post_tasks:
- name: Verify application is responding
uri:
url: "http://localhost:{{ web_port }}"
status_code: 200
register: webapp_response
retries: 3
delay: 5
until: webapp_response.status == 200
tags:
- validation
# Example of a separate play for database servers
- hosts: dbservers
become: yes
roles:
- role: database
tags:
- database
# Conditional play for monitoring servers
- hosts: monitoring
become: yes
tasks:
- name: Install monitoring tools
apt:
name:
- prometheus
- grafana
state: present
when: monitoring_enabled | default(false)Installez Ansible avec la commande suivante :
pipx install --include-deps ansible
Puis, installez Multipass, qui nous permettra de simuler des serveurs.
Vérifiez que tout est bien installé :
multipass -v
ansible -v
Créez les serveurs nécessaires pour la suite du TPs :
Ensuite, générez la paire de clé SSH qui permettra à Ansible de se connecter à nos serveurs :
multipass launch -n web-server && multipass launch -n db-server# Generate SSH key if you don't have one
ssh-keygen -t rsa -b 4096 -f ./ansible_test_key
# Add SSH key to instances
multipass exec web-server -- mkdir -p /home/ubuntu/.ssh
multipass exec db-server -- mkdir -p /home/ubuntu/.ssh
# Copy public key to instances
multipass exec web-server -- sh -c "echo '$(cat ./ansible_test_key.pub)' >> /home/ubuntu/.ssh/authorized_keys"
multipass exec db-server -- sh -c "echo '$(cat ./ansible_test_key.pub)' >> /home/ubuntu/.ssh/authorized_keys"Créez ensuite le fichier inventory avec les informations des serveurs :
[webservers]
web-server ansible_host=<web-server IP> # <-- multipass info web-server | grep IPv4
[dbservers]
db-server ansible_host=<db-server IP> # <-- multipass info db-server | grep IPv4
[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=./ansible_test_key
ansible_ssh_common_args='-o StrictHostKeyChecking=no'Créez ensuite le fichier playbook.yml avec les tâches à réaliser pour Ansible :
---
- hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install basic packages
apt:
name:
- htop
- vim
- curl
state: present
- hosts: webservers
become: yes
tasks:
- name: Install nginx
apt:
name: nginx
state: present
- hosts: dbservers
become: yes
tasks:
- name: Install MySQL
apt:
name:
- mysql-server
- python3-pymysql
state: presentVérifiez que Nginx et Mysql ne sont pas déjà présent sur les serveurs :
Vous devriez avoir une erreur pour les deux commandes.
Maintenant, lancez Ansible pour configurer les serveurs :
Réessayez les commandes pour vérifier que Nginx et Mysql sont bien présents.
Appelez-moi pour que l'on puisse valider ensemble.
# Run the playbook
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i inventory playbook.yml# Connectez-vous à web-server pour lancer la commande dans son terminal
curl localhost
# Connectez-vous à db-server pour lancer la commande dans son terminal
mysql -vAjoutez dans le Playbook Ansible tout ce qui est nécessaire pour ajouter au web-server le service Docker.
Retirez Nginx et lancez l'image traefik/whoami via Ansible.
Vérifiez que votre web-server affiche quelque chose sur le port 80.
Appelez-moi pour que l'on puisse valider ensemble.
Déployez avec Terraform, 3 instances EC2 et créez automatiquement un inventory avec toutes les informations nécessaires pour que Ansible puisse configurer ces instances.
(IP, Clés SSH, etc)
Appliquez sur les 3 instances une configuration via un Playbook qui installe et lance sur toutes les instances Nginx.
Vérifiez sur vos instances EC2 que Nginx réagit au port 80.
Appelez-moi pour que l'on puisse valider ensemble.
Déployez avec Terraform une instance EC2 "webserver" et une instance EC2 "dbserver" et créez automatiquement un inventory avec toutes les informations nécessaires pour que Ansible puisse configurer ces instances.
(IP, Clés SSH, etc)
Appliquez sur l'instance "webserver" une configuration via un Playbook qui installe et lance l'image Docker Nginx et sur l'instance "dbserver" une base de donnée MySQL.
Vérifiez sur vos instances EC2 que Nginx et MySQL soient bien présents.
Appelez-moi pour que l'on puisse valider ensemble.
Ajoutez dans le Playbook Ansible tout ce qui est nécessaire pour déployer un cluster Docker Swarm sur vos instances.
Créer un manager et deux workers, il faut sauvegarder via Ansible les informations du manager pour permettre aux workers de rejoindre le cluster.
Utilisez l'image traefik/whoami pour le cluster via Ansible.
Vérifiez que votre cluster fonctionne correctement.
Appelez-moi pour que l'on puisse valider ensemble.
Déployez avec Terraform une infrastructure pour mettre en ligne une application que vous avez déjà réalisé précédemment.
Créez les images Docker de votre projet pour pouvoir ensuite utiliser Ansible pour configurer l'ajout et l'utilisation des images Docker et d'autres images nécessaires pour votre projet sur vos instances déployées par Terraform.
Appelez-moi pour que l'on puisse valider ensemble.
Projet
Approche consistant à intégrer la sécurité dès la conception d’un système, d’une application ou d’une architecture.
Au lieu d’ajouter des mécanismes de sécurité après coup, on réfléchit dès le départ à :
Quels sont les risques et menaces ?
Quelles mesures techniques et organisationnelles mettre en place ?
Cela réduit les failles structurelles, diminue les coûts de correction et améliore la robustesse globale.
Chiffrement des données prévu dès la phase de conception (et non ajouté après une fuite).
Modélisation des menaces (threat modeling) en phase de design.
Utilisation du principe du moindre privilège dans l’architecture.
Principe qui impose qu’un système soit sécurisé dès son installation et sa configuration initiale, sans action supplémentaire de l’utilisateur :
Les paramètres par défaut doivent privilégier la sécurité, quitte à limiter certaines fonctionnalités.
Les options moins sûres doivent être explicitement activées par l’utilisateur conscient du risque.
Cela protège les utilisateurs non experts et évite que des failles soient exploitables simplement parce que les réglages de base étaient trop permissifs.
Compte administrateur désactivé par défaut.
Communication chiffrée activée (HTTPS/TLS par défaut).
Mot de passe fort obligatoire à la première connexion.
By Design = sécurité pensée et intégrée dès la conception (amont).
By Default = sécurité appliquée dans la configuration initiale (aval, côté déploiement/utilisateur).
Les deux approches sont complémentaires : un système peut avoir une architecture sécurisée (by design), mais rester vulnérable si ses paramètres par défaut sont laxistes (by default).
La Twelve-Factor App est un ensemble de 12 bonnes pratiques proposées par des ingénieurs de Heroku (2011) pour concevoir des applications cloud-native, scalables, portables et faciles à maintenir.
Elle s’applique surtout aux applications SaaS et aux environnements de déploiement modernes (Docker, Kubernetes, PaaS).
1. Codebase : une seule base de code, déployée sur plusieurs environnements.
2. Dépendances : déclarer et isoler explicitement toutes les dépendances.
3. Config : séparer la configuration du code. (.env)
4. Backing services : traiter les services externes comme des ressources interchangeables.
5. Build, release, run : séparer ces étapes.
6. Stateless : l’application s’exécute comme un ou plusieurs processus stateless.
7. Port binding : l’app expose elle-même son service via un port, sans dépendre d’un serveur externe
8. Concurrency : mise à l’échelle par duplication de processus (horizontal scaling).
9. Disposability : Les processus doivent démarrer/arrêter rapidement.
10. Dev/prod parity : garder les environnements de dev, staging et prod similaires.
11. Logs : les logs sont des flux d’événements envoyés vers un agrégateur externe.
12. Admin processes : les tâches admin sont à faire dans l'environnement de l’app.
Portabilité : pas d’attache forte à une infra spécifique.
Scalabilité : facile à déployer sur le cloud, répartir la charge.
Résilience : redémarrage rapide, tolérance aux pannes.
Maintainabilité : séparation claire du code, de la config et des dépendances.
En résumé, la Twelve-Factor App est une philosophie de développement qui permet de construire des applications cloud-native robustes, adaptées aux microservices et aux déploiements modernes.
Le principe du moindre privilège (en anglais Least Privilege) consiste à donner à un utilisateur, un processus ou un système uniquement les droits strictement nécessaires pour accomplir sa tâche — ni plus, ni moins.
C’est un des fondements de la cybersécurité : plus les privilèges sont limités, plus on réduit la surface d’attaque et les conséquences d’une compromission.
Utilisateurs : un employé n’a accès qu’aux ressources nécessaires à son poste (ex. un comptable n’a pas accès aux serveurs de production).
Applications : un service web qui doit uniquement lire une base de données n’a pas de droit d’écriture.
Systèmes : les comptes administrateurs ne sont utilisés que pour les tâches critiques, pas pour le quotidien.
Réseau : pare-feu configuré pour n’ouvrir que les ports requis.
Réduction des dégâts en cas de compromission (l’attaquant est limité dans ses actions).
Limitation des erreurs humaines (moins de possibilités de fausses manipulations).
Conformité avec les standards (ISO 27001, NIST, RGPD, etc.).
Bien analyser les besoins réels pour attribuer les bons droits.
Éviter les exceptions trop larges ("accès admin temporaire") qui deviennent permanentes.
Maintenir la règle dans le temps (droits évolutifs selon les missions).
Le Secure Coding (ou développement sécurisé) désigne l’ensemble des méthodes et bonnes pratiques de programmation visant à prévenir les failles de sécurité dès la phase de développement.
Le but est d’écrire du code robuste, fiable et résistant aux attaques.
70 à 80 % des vulnérabilités viennent d’erreurs de développement (OWASP, NIST).
Corriger une faille pendant le développement coûte 10 à 100 fois moins cher qu’en production.
Répond aux exigences de conformité (ISO 27034, RGPD, PCI-DSS).
Par exemple :
Ne jamais faire confiance aux données fournies par l’utilisateur.
Filtrer, valider et échapper toutes les entrées (input validation).
Exemple : protéger contre l’injection SQL, XSS.
Par exemple :
bcrypt, Argon2).Utiliser l’authentification multifactorielle (MFA).
Générer des jetons de session aléatoires et limités dans le temps.
Par exemple :
Implémenter des vérifications côté serveur (pas seulement côté client).
Appliquer le principe du moindre privilège.
Par exemple :
Ne pas divulguer d’informations sensibles dans les messages d’erreur.
Centraliser et protéger les logs (pour détection et forensic).
Par exemple :
Chiffrer les données en transit (TLS 1.3) et au repos (AES-256).
Ne pas réinventer ses propres algorithmes : utiliser des bibliothèques éprouvées.
Par exemple :
Maintenir les bibliothèques et frameworks à jour.
Vérifier les dépendances contre des bases de vulnérabilités (ex. Snyk, Dependabot).
Par exemple :
Ne jamais stocker de secrets (mots de passe, clés API) en clair dans le code.
Utiliser des gestionnaires de secrets (Vault, AWS Secrets Manager, etc.).
Par exemple :
Revue de code (peer review).
Tests automatisés de sécurité (linting, SAST, DAST).
Tests de pénétration avant mise en production.
Processus collaboratif où des développeurs examinent le code écrit par leurs pairs avant son intégration (merge) afin d’améliorer sa qualité, lisibilité, maintenabilité et sécurité.
Le but :
Détecter les erreurs logiques ou de style.
Identifier des failles potentielles de sécurité.
Améliorer la cohérence et le partage de connaissances dans l’équipe.
Employer des checklists (qualité, sécurité, performance).
Favoriser des discussions constructives (pas du jugement personnel).
Compléter la review manuelle avec des outils automatisés (linters, SAST).
Ensemble des activités visant à vérifier le bon fonctionnement d’un logiciel selon les spécifications attendues :
Unitaires : testent des fonctions ou modules isolés.
Intégration : vérifient la coopération entre composants.
Système / end-to-end : testent l’application complète dans un contexte proche de la prod.
Régression : s’assurent qu’une modification n’a pas introduit de bug.
Performance / charge : évaluent robustesse et montée en charge.
Sous-domaine du testing qui vise à évaluer la robustesse du logiciel face aux menaces et à identifier des vulnérabilités exploitables.
Cela consiste à :
Intégrer le security testing dans le cycle DevSecOps (CI/CD).
Automatiser les tests simples et récurrents.
Réaliser régulièrement des pentests manuels pour compléter.
Se baser sur des standards comme l’OWASP Top 10 ou l’ASVS.
DAST (Dynamic Application Security Testing) : Analyse de l’application en cours d’exécution (simulation d’attaques, injections, comportement aux entrées malveillantes).
IAST (Interactive Application Security Testing) : Combinaison de SAST + DAST, instrumente l’application pendant les tests pour plus de précision.
Pentests (tests d’intrusion) : Attaques manuelles ou automatisées par des experts pour simuler un hacker réel.
Le hardening d’un OS est l’ensemble des techniques visant à réduire la surface d’attaque d’un système en supprimant, désactivant ou renforçant tous les éléments non nécessaires.
Rendre l’OS plus robuste face aux attaques en éliminant les faiblesses par défaut.
Réduction de la surface d’attaque
Désinstaller ou désactiver les services inutiles (FTP, Telnet, etc.).
Supprimer les comptes utilisateurs par défaut.
Gestion des accès et authentification
Appliquer le principe du moindre privilège (Least Privilege).
Forcer l’usage de mots de passe complexes ou d’authentification multifactorielle.
Limiter l’accès SSH (clé publique/privée, interdiction du login root direct).
Mises à jour et correctifs
Maintenir le système et les paquets à jour.
Automatiser l’application de correctifs de sécurité (patch management).
Renforcement des configurations système
Configurer correctement le pare-feu (iptables, ufw, Windows Firewall).
Restreindre les permissions de fichiers et répertoires sensibles.
Activer le chiffrement (ex. BitLocker, LUKS).
Surveillance et journalisation
Activer les logs système et les centraliser.
Mettre en place une détection d’intrusion (IDS/IPS).
Sécurisation des communications
Forcer l’usage de protocoles sécurisés (SSH, HTTPS, TLS 1.2/1.3).
Désactiver les versions obsolètes et vulnérables (SSLv3, TLS 1.0).
Un serveur web Linux (Ubuntu) fraîchement installé peut être renforcé en :
Désactivant SSH root (PermitRootLogin no).
Limitant SSH à quelques IP de confiance.
Supprimant Apache modules inutiles.
Configurant ufw pour n’autoriser que 22 (SSH), 80 (HTTP), 443 (HTTPS).
Forçant TLS 1.3 et désactivant les chiffrements faibles.
Le hardening OS est une étape indispensable pour passer d’un système “par défaut” (souvent trop permissif) à un système durci et résilient.
C’est une base de la défense en profondeur (defense in depth).
Il doit être appliqué systématiquement sur tout serveur ou poste sensible avant mise en production.
Le hardening des services consiste à sécuriser les applications et services réseau (serveur web, base de données, serveur mail, SSH, etc.) en réduisant leur surface d’attaque et en configurant uniquement ce qui est nécessaire.
C’est le prolongement logique du hardening de l’OS, mais appliqué au niveau applicatif.
Réduction de la surface d’attaque
Désactiver les fonctionnalités non utilisées (modules inutiles d’Apache/Nginx, extensions PHP, etc.).
Supprimer les comptes ou services par défaut.
Restreindre l’accès réseau (ex. base de données accessible uniquement en local).
Configuration sécurisée
Utiliser des versions sécurisées des protocoles (ex. IMAPS/SMTPS au lieu de IMAP/SMTP en clair).
Interdire les chiffrements obsolètes (SSLv2, SSLv3, TLS 1.0/1.1) et forcer l’utilisation de certificats valides.
Gestion des identités et accès : principe du Least Privilege appliqué aux comptes de service et authentification forte (MFA, clés SSH) avec rotation régulière des mots de passe et clés API.
Mises à jour et patching : mettre à jour régulièrement les services et frameworks (Apache, MySQL, Postfix…) et automatiser si possible (apt/yum, WSUS, Ansible)
Surveillance et journalisation : activer la journalisation fine (ex. logs d’accès Apache, logs de requêtes SQL) et détecter les anomalies (tentatives de brute-force, injections, scans).
SSH
Désactiver l’accès root (PermitRootLogin no).
Restreindre aux utilisateurs autorisés (AllowUsers).
Forcer l’authentification par clé SSH.
Limiter à certaines IP via firewall.
Serveur Web (Apache/Nginx)
Désactiver les modules non utilisés.
Forcer HTTPS (HSTS, TLS 1.3).
Masquer les bannières serveur (ServerTokens Prod).
Protéger contre XSS/CSRF via en-têtes HTTP (X-Frame-Options, Content-Security-Policy).
Base de données (MySQL/PostgreSQL)
Accès uniquement depuis le serveur applicatif.
Comptes utilisateurs avec droits minimaux.
Désactiver les fonctionnalités non nécessaires (ex. LOAD DATA LOCAL INFILE).
Chiffrement des connexions (ssl=ON).
Le service hardening sécurise chaque composant applicatif exposé.
Il complète l’OS hardening pour une défense en profondeur (defense in depth).
Chaque service a ses propres recommandations (guides CIS, NIST, OWASP).
Le pare-feu (firewall) est un dispositif (matériel ou logiciel) qui contrôle le trafic réseau entrant et sortant selon des règles prédéfinies.
C’est la première barrière entre un réseau interne et l’extérieur.
Types de firewalls
Filtrage statique (L3/L4) : basé sur adresses IP, ports, protocoles.
Pare-feu applicatif (L7 / WAF) : analyse du contenu applicatif (ex. HTTP, SQL).
Next-Generation Firewall (NGFW) : intègre IDS/IPS, analyse comportementale, inspection SSL.
Règles en mode deny by default (tout est bloqué, sauf ce qui est explicitement autorisé).
Journalisation et surveillance en temps réel.
Mise à jour régulière des signatures et règles.
Modèle de sécurité réseau basé sur le principe :
“Never trust, always verify” (ne jamais faire confiance, toujours vérifier).
Règles :
Pas de zone de confiance implicite (même à l’intérieur du réseau).
Authentification et autorisation continues à chaque requête.
Application stricte du least privilege.
Micro-segmentation des ressources.
Un employé doit accéder à une application interne :
Zone tampon du réseau, isolée, où sont placés les services exposés à Internet (serveurs web, mail, DNS).
Protéger le réseau interne en cas de compromission d’un service exposé.
Fonctionnement :
Les serveurs accessibles depuis Internet (public-facing) sont dans la DMZ.
Les échanges avec le réseau interne passent par des contrôles stricts (firewall, proxy).
Exemple classique : un site web hébergé en DMZ peut interroger une base de données dans le réseau interne, mais ne doit pas être directement exposé à celui-ci.
Diviser un réseau en sous-réseaux isolés pour limiter la propagation d’attaques et contrôler les flux soit :
Segmentation physique : réseaux séparés physiquement (switches/routeurs distincts).
Segmentation logique : VLAN, ACL, micro-segmentation via SDN.
Avantages :
Réduit l’impact d’une compromission (l’attaquant ne peut pas se déplacer latéralement).
Applique des politiques de sécurité différenciées selon les zones (ex. VLAN IoT vs VLAN prod).
Firewalling : barrière de contrôle du trafic.
Zero Trust : pas de confiance implicite, vérification continue.
DMZ : zone tampon pour protéger le réseau interne.
Segmentation : confinement et cloisonnement pour limiter les dégâts.
C’est l’ensemble des techniques et outils qui analysent les dépôts de code (history + tree + dépendances) pour détecter :
Un secret publié dans un repo, même supprimé, est souvent exploitable.
Les vulnérabilités dans les dépendances constituent la majorité des incidents.
Détection précoce = réponse rapide (révocation / rotation / patch) = réduction du blast radius.
Détection de secrets (static secrets scanning)
gitleaks, truffleHog, gitleaks-action (GitHub Action), git-secrets, gitleaks : recherche regex / heuristiques.
Scanning de vulnérabilités de dépendances (SCA - Software Composition Analysis)
Snyk, Dependabot (GitHub), OSS Index, npm audit, pip-audit, mvn dependency:check (OWASP Dependency-Check).
Code scanning / Static Analysis (SAST & CodeQL)
CodeQL (GitHub Advanced Security), Semgrep, SonarQube (rules sécurité).
Scanner en pré-commit et côté développeur
Pre-commit hooks (pre-commit, git-secrets) pour bloquer les fuites avant push.
Extensions IDE ou plugin qui avertissent lors d’insertion de clés.
Scanner à chaque push / PR (gated checks)
Job CI qui exécute : secrets scanning (gitleaks), SCA (Snyk/Dependabot), SAST (Semgrep/CodeQL).
Bloquer le merge si des secrets sont trouvés ou si une vuln critique est détectée (policy).
Scanner régulièrement l’historique Git
Recherche rétrospective (truffleHog / gitleaks --repo) pour trouver secrets committés puis supprimés.
Si un secret est découvert, rotation / révocation immédiate + purge de l’historique (git filter-repo / BFG) si nécessaire.
Automatiser la remédiation / ticketing
Créer automatiquement issues ou tickets pour vulnérabilités détectées.
Prioriser par score CVSS / criticité business.
Politique et gouvernance
Policy “deny-by-default” pour secrets en clair.
Exiger la rotation des clés et l’usage de vaults (Secrets Manager, HashiCorp Vault).
Mesures d’audit et preuve de conformité (logs, SBOM).
name: Repo Security Scan
on: [push, pull_request]
jobs:
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run gitleaks
run: |
curl -sLo gitleaks https://github.com/zricethezav/gitleaks/releases/latest/download/gitleaks-linux-amd64
chmod +x gitleaks
./gitleaks detect --source . --report-path gitleaks-report.json || true
- name: Upload gitleaks report
uses: actions/upload-artifact@v4
with:
name: gitleaks-report
path: gitleaks-report.json
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: |
npm install -g snyk
snyk test --json > snyk-report.json || true
- name: Upload snyk report
uses: actions/upload-artifact@v4
with:
name: snyk-report
path: snyk-report.json
Secrets déjà compromis : supprimer un commit ne suffit pas sans rotation / révocation.
Historique Git : les secrets peuvent rester dans les commits antérieurs ; il faut scrub + réécrire l’historique avec précaution.
Performance & bruit : scans très agressifs peuvent ralentir CI ; adapter granularité et fréquence.
Identifier & valider (investigation).
Si secret réel : révoquer / rotate immédiatement (cloud IAM, token, clé).
Purger l’historique si nécessaire (BFG / git-filter-repo) et forcer re-clone pour collaborateurs.
Corriger la vulnérabilité (update lib / patch code).
Documenter & créer ticket post-mortem si incident.
Le scan des repositories est une pratique indispensable dans une stratégie DevSecOps moderne : il combine détection de secrets, SCA et SAST, intégré en local (pre-commit) et dans la CI (PR checks).
L’importance réelle n’est pas seulement de détecter mais d’avoir un workflow clair de remédiation (révocation, patch, purge historique) et des politiques pour éviter la récurrence.
La gestion des identités et des accès (IAM) regroupe l’ensemble des méthodes, outils et processus qui garantissent que :
Authentification (AuthN) : vérifier qui est l’utilisateur ou le système.
Autorisation (AuthZ) : déterminer à quoi il a le droit d’accéder, et avec quels privilèges.
C’est un pilier fondamental de la sécurité des systèmes modernes.
AWS l'utilise actuellement.
Processus qui permet de prouver son identité.
Facteurs d’authentification :
Ce que l’on sait (mot de passe, PIN).
Ce que l’on a (token, carte à puce, smartphone).
Ce que l’on est (biométrie : empreinte, visage).
Bonnes pratiques :
MFA (Multi-Factor Authentication) = combinaison de plusieurs facteurs.
Gestion sécurisée des mots de passe (hash + sel avec bcrypt/Argon2).
Rotation et révocation rapide en cas de compromission.
Problème : difficiles à gérer, souvent exposés par erreur (dans le code ou les repos Git).
Jetons temporaires délivrés après authentification.
Exemples :
JWT (JSON Web Token) : très utilisé dans les API / microservices.
OAuth 2.0 : délégation d’accès (ex. connexion avec Google/Facebook).
OIDC (OpenID Connect) : extension d’OAuth pour l’authentification.
Avantages : durée de vie limitée, révocables, scopes précis.
Un vault est une solution dédiée à la gestion sécurisée des secrets (mots de passe, clés API, certificats). Il répond au besoin suivant : ne jamais stocker de secrets en clair dans le code ou les repos. Il existe de nombreux outils :
HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager.
Fonctionnalités
Stockage chiffré des secrets.
Accès contrôlé par IAM et audit logs.
Rotation automatique des clés et mots de passe.
Distribution sécurisée aux applications.
Authentification (AuthN) : prouver qui je suis.
Autorisation (AuthZ) : prouver ce que j’ai le droit de faire.
Credentials : identifiants classiques (souvent sensibles).
Tokens : jetons temporaires, adaptés aux environnements distribués (APIs, microservices).
Vault : coffre-fort sécurisé pour gérer et distribuer les secrets.
Ce paradigme met en lumière le rôle central de l’utilisateur dans la sécurité des systèmes d’information.
Un système peut être techniquement très sécurisé (pare-feu, chiffrement, IAM…), mais si l’utilisateur final adopte de mauvais comportements (mots de passe faibles, clic sur un lien de phishing, contournement des règles), la sécurité globale est compromise.
En d’autres termes : « L’humain est souvent le maillon faible de la cybersécurité ».
Utilisation de mots de passe faibles ou réutilisés.
Clic sur des liens malveillants (phishing, spear-phishing).
Contournement volontaire des politiques de sécurité jugées contraignantes (shadow IT).
Envoi d’un mail sensible au mauvais destinataire.
Mauvaise gestion des droits d’accès.
Stockage de données sensibles dans des env' non sécurisés (clé USB, cloud personnel).
Si les mesures de sécurité sont trop complexes : rejet / contournement par l’utilisateur.
L’équilibre sécurité vs. facilité d’usage est crucial.
Comprendre le pourquoi.
Sensibilisation et formation
Campagnes régulières de sensibilisation (phishing simulation, ateliers sécurité).
Formation adaptée au niveau de chaque profil (direction, technique, utilisateur lambda).
Conception centrée utilisateur (Security by Design)
Intégrer la sécurité sans nuire à l’expérience utilisateur.
Exemples : authentification SSO + MFA ergonomique, gestion simplifiée des mots de passe.
Politiques de sécurité réalistes
Règles compréhensibles et applicables (pas des mots de passe impossibles à mémoriser → privilégier un gestionnaire de mots de passe).
Clarifier les responsabilités de chaque acteur.
Contrôles techniques complémentaires
Protection renforcée même si l’utilisateur se trompe :
Filtres anti-phishing.
DLP (Data Loss Prevention).
Contrôles d’accès contextuels (Zero Trust).
Une entreprise impose un mot de passe complexe changé tous les 30 jours.
Résultat : les utilisateurs notent leurs mots de passe sur des post-it, perte de sécurité effective.
Solution : adoption de MFA + gestionnaire de mots de passe, sécurité renforcée ET meilleure ergonomie.
Le paradigme de « l’utilisateur et la sécurité » rappelle que la sécurité n’est pas qu’une question technique.
L’utilisateur doit être acteur de la sécurité à travers la sensibilisation, l’accompagnement et des outils adaptés.
L’enjeu est de réconcilier sécurité et ergonomie, pour réduire les risques liés aux erreurs humaines et aux comportements à risque.
Le 15 septembre 2022, Uber a annoncé qu’elle avait subi une intrusion majeure dans certains de ses systèmes internes : l’attaquant a publié des captures d’écran montrant un accès aux comptes Slack internes, aux environnements AWS, etc.
Mais comment s'infiltrer dans une grande entreprise tech qui possède de très bons process de sécurité ?
Selon les analyses, l’attaquant a ciblé un employé ou un sous-traitant via des techniques d’ingénierie sociale :
Il a utilisé ce qu’on appelle le MFA fatigue (ou push bombing) : envoyer de nombreuses demandes de validation de connexion MFA à la victime jusqu’à ce qu’elle accepte par exaspération.
Il se serait fait passer pour un membre de l’équipe IT pour persuader la victime de confirmer la requête d’authentification.
L'attaquant a pu naviguer dans le réseau interne et trouver des scripts PowerShell stockés sur un partage réseau, certains incluant des identifiants d’administration (PAM, etc.).
L’IaaS (Infrastructure as a Service) est un modèle de cloud computing dans lequel un fournisseur met à disposition, via Internet, des ressources informatiques virtualisées — serveurs, stockage, réseaux et systèmes d’exploitation — que l’entreprise peut configurer et gérer à la demande.
Responsabilités Fournisseur :
Virstualisation, Serveurs, Réseau, Stockage physique.
Responsabilités Client :
Applications, Données, Middlewares, OS
Flexible : ressources ajustables à la demande et paiement à l’usage, modèle pay-as-you-go.
Virtualisation : rapidité de déploiement et aucune gestion du matériel physique.
I18n : haute disponibilité et scalabilité mondiale.
Gestion technique encore nécessaire (OS, patchs, sécurité applicative)
Risque de dépendance fournisseur (vendor lock-in)
Facturation complexe si mauvaise gouvernance du cloud
Tous les Cloud Providers :
AWS, Google Cloud, Azure, OVH...
Le PaaS (Platform as a Service) est un modèle de cloud computing qui fournit un environnement complet de développement et de déploiement dans le cloud.
Le fournisseur gère l’infrastructure sous-jacente (serveurs, stockage, réseau, OS, middleware), tandis que le développeur se concentre sur le code et les applications.
Responsabilités Fournisseur :
Runtime, Middleware, OS, Infrastructure.
Responsabilités Client :
Applications, Données
Gain de temps : pas d’installation, d’administration système
Intégration facile avec des services tiers
Focus sur la logique métier plutôt que l’infrastructure
Moins de contrôle sur l’environnement système
Coût plus élevé à long terme pour de gros volumes
Risque de vendor lock-in (dépendance à la plateforme)
Des solutions "clé en main" :
Netlify, Vercel, Heroku...
Le CaaS (Container as a Service) est un modèle de cloud computing qui fournit une plateforme de gestion, de déploiement et d’orchestration de conteneurs.
Il se situe entre l’IaaS et le PaaS : le fournisseur gère l’infrastructure et les outils d’orchestration, tandis que le client gère ses conteneurs, images et applications.
Responsabilités Fournisseur :
Orchestrateur, Infrastructure, Réseau, Stockage
Responsabilités Client :
Applications, Conteneurs, Images
Le SaaS (Software as a Service) est un modèle de cloud computing dans lequel les applications sont hébergées et gérées par un fournisseur et accessibles à la demande via Internet.
L’utilisateur n’installe rien localement : il consomme le logiciel comme un service.
Responsabilités Fournisseur :
Tout
Responsabilités Client :
Utilisation de l'application
L’observabilité est la capacité à comprendre l’état interne d’un système à partir de ses sorties externes.
Elle repose sur trois piliers principaux :
Logs : traces des événements applicatifs et systèmes.
Metrics : mesures chiffrées de performance, de disponibilité, d’usage.
Traces : suivi d’une requête à travers plusieurs services (distributed tracing).
Le but est de détecter, comprendre et résoudre rapidement les incidents fonctionnels et sécuritaires.
Sentry est une plateforme open-source (et SaaS) de monitoring applicatif orientée erreurs, exceptions et performance.
Elle se situe à la jonction entre les pratiques DevOps (résilience, fiabilité) et SecOps (détection d’anomalies).
| Domaine | Fonctionnalités clés |
|---|---|
| Erreurs & exceptions | Collecte et analyse des erreurs applicatives (stacktrace, contexte utilisateur, version du code). |
| Performance monitoring | Suivi des temps de réponse, transactions lentes, requêtes SQL... |
| Release tracking | Corrélation des erreurs à des versions de déploiement (CI/CD). |
| Alerting & intégrations | Alertes Slack, Teams, email ou Webhook. GitHub, GitLab, Jira, etc. |
| Security observability | Détection de comportements anormaux (injections, auth suspectes). |
| Phase du cycle | Apport de Sentry | Bénéfice DevSecOps |
|---|---|---|
| Développement | Intégration SDK pour détecter les exceptions dès le dev (JavaScript, Python, Go, etc.) | Qualité de code, feedback rapide |
| CI/CD | Corrélation des erreurs avec les commits et releases | Traçabilité, responsabilité partagée |
| Production | Suivi des incidents et performance | Réduction du MTTR (Mean Time To Repair) |
| Sécurité | Identification d’erreurs révélant des vecteurs d’attaque (ex: injections, overflows) | Détection proactive de vulnérabilités |
npm install @sentry/node
// Exemple Node.js
const Sentry = require("@sentry/node");
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: "production",
tracesSampleRate: 1.0,
});
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.errorHandler());
# .gitlab-ci.yml
stages:
- build
- test
- deploy
- notify
deploy:
stage: deploy
script:
- npm run deploy
- sentry-cli releases new "$CI_COMMIT_SHA"
- sentry-cli releases finalize "$CI_COMMIT_SHA"
Voyons comment fonctionne Sentry sur une application en production.
Le lien suivant n'est accessible que par moi-même, n'hésitez pas à aller voir la Sandbox :
Sentry permet de “rendre visible l’invisible” :
Connecte le code aux comportements réels en production,
Renforce la qualité logicielle par la détection précoce des anomalies,
Participe à la boucle d’amélioration continue entre Dev, Sec et Ops.