Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
| eadl:bloc4:fm4:td4 [2026/06/25 02:15] – jcheron | eadl:bloc4:fm4:td4 [2026/06/25 13:14] (Version actuelle) – [8. Pourquoi systemd plutôt que nohup] jcheron | ||
|---|---|---|---|
| Ligne 33: | Ligne 33: | ||
| * Infrastructure TD2 et TD3 opérationnelle | * Infrastructure TD2 et TD3 opérationnelle | ||
| - | * Instance EC2 accessible via SSH | + | * Instance EC2 accessible via SSH ou Session Manager |
| * Dépôt GitHub disponible avec les droits d' | * Dépôt GitHub disponible avec les droits d' | ||
| * Java 17 et Maven installés sur le poste de travail | * Java 17 et Maven installés sur le poste de travail | ||
| - | <WRAP round help> | ||
| Rappel sur les environnements d' | Rappel sur les environnements d' | ||
| - | * Le poste de travail et le runner CI/CD ont besoin de Java et Maven pour **compiler** l' | + | * Java et Maven sont nécessaires sur le **poste de travail** pour compiler |
| - | * L'instance | + | * Java est nécessaire sur **l' |
| * Maven n'a pas sa place sur l'EC2 : on y dépose uniquement le jar déjà compilé | * Maven n'a pas sa place sur l'EC2 : on y dépose uniquement le jar déjà compilé | ||
| - | </ | ||
| ===== 1. Compréhension de l' | ===== 1. Compréhension de l' | ||
| Ligne 61: | Ligne 59: | ||
| </ | </ | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Questions de compréhension : | + | Ce fichier sera commité dans Git avec le reste du code source. |
| - | * Pourquoi le mot de passe en clair dans ce fichier | + | * Quelles sont les conséquences concrètes si un dépôt contenant |
| - | * Que se passe-t-il si ce fichier est commité dans Git ? | + | * Un attaquant qui récupère ce fichier a-t-il accès à la base de données directement ? Quels autres éléments lui manquent-il |
| - | * Quel service AWS permet de corriger cette situation | + | * Pourquoi externaliser ce secret dans Secrets Manager ne suffit pas si le code qui le récupère est lui-même mal sécurisé |
| </ | </ | ||
| ===== 2. Build de l' | ===== 2. Build de l' | ||
| - | Le build se fait sur le poste de travail. L'EC2 ne reçoit que le jar final. | + | Le fichier Maven minimal pour construire |
| Fichier : '' | Fichier : '' | ||
| Ligne 120: | Ligne 118: | ||
| <WRAP round todo> | <WRAP round todo> | ||
| - | Compiler l' | + | Compiler l' |
| <sxh bash> | <sxh bash> | ||
| Ligne 127: | Ligne 125: | ||
| </ | </ | ||
| - | Vérifier que le fichier '' | + | Vérifier que le fichier '' |
| - | + | ||
| - | <sxh bash> | + | |
| - | ls -lh app/ | + | |
| - | </ | + | |
| </ | </ | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Questions de compréhension : | + | Dans un pipeline CI/CD en production, ignorer les tests avec '' |
| - | * Pourquoi utilise-t-on '' | + | * Dans quelle situation précise serait-il acceptable de l'utiliser malgré tout ? |
| - | * Dans quel cas ne faudrait-il pas ignorer | + | * Quels types de tests seraient |
| - | * Où se trouve le jar produit par Maven ? Pourquoi ce répertoire est-il généralement dans '' | + | |
| </ | </ | ||
| ===== 3. Déploiement manuel ===== | ===== 3. Déploiement manuel ===== | ||
| - | Avant d' | + | Avant d' |
| - | + | ||
| - | Cette section introduit volontairement un problème que vous devrez identifier. | + | |
| - | + | ||
| - | <WRAP round todo> | + | |
| - | Étape 1 : Vérifier que Java est disponible sur l' | + | |
| - | + | ||
| - | Se connecter à l' | + | |
| - | + | ||
| - | <sxh bash> | + | |
| - | ssh -i ~/ | + | |
| - | </ | + | |
| - | + | ||
| - | Depuis l' | + | |
| - | + | ||
| - | <sxh bash> | + | |
| - | java -version | + | |
| - | </ | + | |
| - | + | ||
| - | Si Java n'est pas installé, l' | + | |
| - | + | ||
| - | <sxh bash> | + | |
| - | sudo yum install -y java-17-amazon-corretto | + | |
| - | + | ||
| - | # Vérifier l' | + | |
| - | java -version | + | |
| - | </ | + | |
| - | + | ||
| - | Quitter la session SSH : | + | |
| - | + | ||
| - | <sxh bash> | + | |
| - | exit | + | |
| - | </ | + | |
| - | </ | + | |
| <WRAP round todo> | <WRAP round todo> | ||
| - | Étape 2 : Copier le jar sur l' | + | Copier le jar sur l' |
| <sxh bash> | <sxh bash> | ||
| Ligne 188: | Ligne 148: | ||
| </ | </ | ||
| - | Étape 3 : Se connecter à l' | + | Se connecter à l' |
| <sxh bash> | <sxh bash> | ||
| Ligne 201: | Ligne 161: | ||
| </ | </ | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Questions d'analyse : | + | Sur un système Linux, les arguments passés à un processus sont visibles via ''ps aux'' |
| - | * Quels sont les problèmes concrets | + | * Quelle est la conséquence concrète |
| - | * Que se passe-t-il si l' | + | * Cette méthode |
| - | * Pourquoi | + | |
| - | * Quelle commande Linux permet | + | |
| </ | </ | ||
| Ligne 218: | Ligne 176: | ||
| </ | </ | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Analysez l' | + | Avant de chercher |
| - | * Pourquoi l'application ne peut-elle pas se connecter à '' | + | * L'erreur indique |
| - | * Quelle valeur devrait remplacer | + | * Listez les couches réseau à vérifier |
| - | * Comment | + | |
| Commande utile pour tester la connectivité réseau depuis l' | Commande utile pour tester la connectivité réseau depuis l' | ||
| Ligne 230: | Ligne 187: | ||
| nc -zv RDS_HOST 5432 | nc -zv RDS_HOST 5432 | ||
| </ | </ | ||
| - | |||
| - | * Si cette commande échoue, quel composant AWS est probablement en cause ? | ||
| - | * Quel Security Group faut-il vérifier en priorité ? | ||
| Ne cherchez pas la solution immédiatement. Identifiez d' | Ne cherchez pas la solution immédiatement. Identifiez d' | ||
| Ligne 240: | Ligne 194: | ||
| On automatise maintenant le déploiement pour qu'il soit reproductible. | On automatise maintenant le déploiement pour qu'il soit reproductible. | ||
| - | |||
| - | Ansible se connecte à l'EC2 via SSH depuis le poste de travail. Il installe Java si nécessaire, | ||
| Fichier : '' | Fichier : '' | ||
| - | <sxh ini> | + | <sxh ini; |
| [web] | [web] | ||
| EC2_IP ansible_user=ec2-user ansible_ssh_private_key_file=~/ | EC2_IP ansible_user=ec2-user ansible_ssh_private_key_file=~/ | ||
| Ligne 250: | Ligne 202: | ||
| Fichier : '' | Fichier : '' | ||
| - | <sxh ini> | + | <sxh ini; |
| [defaults] | [defaults] | ||
| host_key_checking = False | host_key_checking = False | ||
| stdout_callback = yaml | stdout_callback = yaml | ||
| </ | </ | ||
| - | |||
| - | <WRAP round help> | ||
| - | Pourquoi '' | ||
| - | |||
| - | Serait-ce acceptable dans un environnement de production ? Pourquoi ? | ||
| - | </ | ||
| Fichier : '' | Fichier : '' | ||
| Ligne 302: | Ligne 248: | ||
| <WRAP round todo> | <WRAP round todo> | ||
| - | Lancer le playbook | + | Lancer le playbook : |
| - | <sxh bash> | + | <sxh bash; |
| ansible-playbook -i ansible/ | ansible-playbook -i ansible/ | ||
| </ | </ | ||
| Ligne 310: | Ligne 256: | ||
| Vérifier que le jar est bien présent sur l' | Vérifier que le jar est bien présent sur l' | ||
| - | <sxh bash> | + | <sxh bash; |
| ssh -i ~/ | ssh -i ~/ | ||
| </ | </ | ||
| - | </ | ||
| - | |||
| - | <WRAP round help> | ||
| - | Questions de compréhension : | ||
| - | |||
| - | * Pourquoi crée-t-on un utilisateur dédié '' | ||
| - | * Pourquoi Ansible installe-t-il Java sur l'EC2 alors qu'on l'a peut-être déjà installé manuellement à la section 3 ? | ||
| - | * Qu' | ||
| </ | </ | ||
| ===== 6. Problème volontaire – L' | ===== 6. Problème volontaire – L' | ||
| - | Le jar est déployé | + | Le jar est déployé mais l' |
| - | <WRAP round help> | + | <WRAP round question> |
| Avant de regarder la section suivante : | Avant de regarder la section suivante : | ||
| - | * Quel élément manque dans le playbook actuel | + | * Le playbook copie le jar mais ne fournit aucune configuration à l' |
| - | * Comment | + | * Ansible peut exécuter des commandes AWS CLI sur la machine cible. Quelles permissions IAM l' |
| - | * Pourquoi ne doit-on pas mettre | + | * Quelle différence y a-t-il entre stocker |
| - | * Pourquoi ne pas le mettre non plus dans un fichier de variables Ansible | + | |
| </ | </ | ||
| - | ===== 7. Correction – Récupération du secret | + | ===== 7. Correction – Récupération du secret |
| - | On complète le playbook avec la récupération du secret, la génération du fichier de configuration, | + | On ajoute |
| Fichier : '' | Fichier : '' | ||
| Ligne 433: | Ligne 370: | ||
| </ | </ | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Questions de compréhension : | + | * '' |
| - | + | * Le service systemd démarre | |
| - | * Pourquoi utilise-t-on | + | * Si Secrets Manager retourne |
| - | * Pourquoi | + | |
| - | * Quel rôle IAM doit avoir l'instance EC2 pour que la commande | + | |
| - | * Pourquoi ne jamais stocker ce secret dans le dépôt Git, même dans un fichier | + | |
| </ | </ | ||
| ===== 8. Pourquoi systemd plutôt que nohup ===== | ===== 8. Pourquoi systemd plutôt que nohup ===== | ||
| - | <WRAP round help> | + | <WRAP round question> |
| - | Comparez les deux approches : | + | Comparez les deux approches |
| - | <sxh bash> | + | <sxh bash; |
| - | # Approche nohup – ne pas utiliser en production | + | # Approche nohup – à ne pas utiliser en production |
| nohup java -jar demo.jar & | nohup java -jar demo.jar & | ||
| </ | </ | ||
| - | * Que se passe-t-il avec '' | + | * Un processus lancé avec '' |
| - | * Que se passe-t-il avec '' | + | * systemd expose des métriques sur les redémarrages successifs d'un service. En quoi cette information est-elle utile pour distinguer un bug applicatif d'un problème d' |
| - | * Comment | + | </ |
| + | |||
| + | ===== 9. Mise en place du pipeline CI/CD ===== | ||
| + | |||
| + | On automatise maintenant le build et le déploiement via GitHub Actions. | ||
| + | |||
| + | Fichier : '' | ||
| + | <sxh yaml> | ||
| + | name: Build and Deploy | ||
| + | |||
| + | on: | ||
| + | push: | ||
| + | branches: [ " | ||
| + | |||
| + | jobs: | ||
| + | build-and-deploy: | ||
| + | runs-on: ubuntu-latest | ||
| + | |||
| + | steps: | ||
| + | - name: Récupérer le code | ||
| + | uses: actions/ | ||
| + | |||
| + | - name: Configurer Java 17 | ||
| + | uses: actions/ | ||
| + | with: | ||
| + | distribution: | ||
| + | java-version: | ||
| + | |||
| + | - name: Compiler l' | ||
| + | run: | | ||
| + | cd app | ||
| + | mvn clean package -DskipTests | ||
| + | |||
| + | - name: Configurer les credentials AWS | ||
| + | uses: aws-actions/ | ||
| + | with: | ||
| + | aws-access-key-id: | ||
| + | aws-secret-access-key: | ||
| + | aws-region: eu-west-1 | ||
| + | |||
| + | - name: Préparer la clé SSH | ||
| + | run: | | ||
| + | mkdir -p ~/.ssh | ||
| + | echo "${{ secrets.EC2_SSH_KEY }}" > ~/ | ||
| + | chmod 600 ~/ | ||
| + | |||
| + | - name: Installer Ansible | ||
| + | run: | | ||
| + | sudo apt-get update -q | ||
| + | sudo apt-get install -y ansible | ||
| + | |||
| + | - name: Déployer avec Ansible | ||
| + | run: | | ||
| + | ansible-playbook \ | ||
| + | -i ansible/ | ||
| + | ansible/ | ||
| + | -e " | ||
| + | </ | ||
| + | |||
| + | ===== 10. Problème volontaire – Le pipeline échoue ===== | ||
| + | |||
| + | En l' | ||
| + | |||
| + | <WRAP round question> | ||
| + | Identifiez les problèmes avant de passer à la section suivante : | ||
| + | |||
| + | * Le runner GitHub Actions est une machine éphémère hébergée chez GitHub. Quelles contraintes réseau cela implique-t-il pour joindre une instance EC2 dans un sous-réseau public ? | ||
| + | * L' | ||
| + | * Si la vérification de la clé SSH hôte est active, le pipeline se bloque en attente d'une confirmation interactive. Pourquoi ce comportement est-il particulièrement problématique dans un contexte CI/CD ? | ||
| + | </ | ||
| + | |||
| + | ===== 11. Correction – Configuration des secrets GitHub ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Dans le dépôt GitHub, aller dans Settings > Secrets and variables > Actions. | ||
| + | |||
| + | Créer les secrets suivants : | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Mettre à jour l' | ||
| + | </ | ||
| + | |||
| + | Fichier : '' | ||
| + | <sxh ini> | ||
| + | [web] | ||
| + | EC2_IP_REELLE ansible_user=ec2-user ansible_ssh_private_key_file=~/ | ||
| + | </ | ||
| + | |||
| + | Fichier : '' | ||
| + | <sxh ini> | ||
| + | [defaults] | ||
| + | host_key_checking = False | ||
| + | stdout_callback = yaml | ||
| + | remote_user = ec2-user | ||
| + | </ | ||
| + | |||
| + | <WRAP round question> | ||
| + | * Les secrets GitHub sont chiffrés au repos et masqués dans les logs. Malgré cela, un secret GitHub n' | ||
| + | * Ce pipeline utilise une clé d' | ||
| + | </ | ||
| + | |||
| + | ===== 12. Vérification du déploiement ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Vérifier que l' | ||
| + | |||
| + | <sxh bash> | ||
| + | ssh -i ~/ | ||
| + | |||
| + | # Vérifier le statut du service | ||
| + | sudo systemctl status demo | ||
| + | |||
| + | # Consulter les logs de l' | ||
| + | sudo journalctl -u demo -n 50 --no-pager | ||
| + | </ | ||
| + | |||
| + | Vérifier que l' | ||
| + | |||
| + | <sxh bash> | ||
| + | curl http:// | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP round question> | ||
| + | * L' | ||
| + | * Dans une architecture avec plusieurs instances EC2 derrière l'ALB, pourquoi le fait de vérifier uniquement une instance ne suffit-il pas à valider le déploiement | ||
| + | </ | ||
| + | |||
| + | ===== 13. Amélioration sécurité – Remplacer SSH par Session Manager ===== | ||
| + | |||
| + | Objectif de cette section : | ||
| + | |||
| + | * supprimer le port 22 du Security Group | ||
| + | * éviter la gestion des clés SSH | ||
| + | * améliorer la traçabilité des connexions | ||
| + | |||
| + | ===== 13.1 Configuration IAM pour Session Manager ===== | ||
| + | |||
| + | Fichier : '' | ||
| + | <sxh js> | ||
| + | resource " | ||
| + | name = " | ||
| + | |||
| + | assume_role_policy = jsonencode({ | ||
| + | Version = " | ||
| + | Statement = [{ | ||
| + | Effect = " | ||
| + | Principal = { | ||
| + | Service = " | ||
| + | } | ||
| + | Action = " | ||
| + | }] | ||
| + | }) | ||
| + | } | ||
| + | |||
| + | resource " | ||
| + | role = aws_iam_role.ec2_ssm_role.name | ||
| + | policy_arn = " | ||
| + | } | ||
| + | |||
| + | resource " | ||
| + | name = " | ||
| + | role = aws_iam_role.ec2_ssm_role.name | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Appliquer la configuration Terraform : | ||
| + | |||
| + | <sxh bash> | ||
| + | terraform apply | ||
| + | </ | ||
| + | |||
| + | Associer le profil IAM à l' | ||
| + | EC2 > Instance > Actions > Security > Modify IAM role | ||
| + | </ | ||
| + | |||
| + | ===== 13.2 Test de connexion via Session Manager ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Tester la connexion sans clé SSH : | ||
| + | |||
| + | <sxh bash; | ||
| + | aws ssm start-session --target INSTANCE_ID | ||
| + | </ | ||
| + | |||
| + | Vérifier que la session s' | ||
| + | </ | ||
| + | |||
| + | <WRAP round question> | ||
| + | * SSH ouvre un port entrant sur l' | ||
| + | * Un administrateur | ||
| + | * SSM améliore la traçabilité, | ||
| + | </ | ||
| + | |||
| + | ===== 13.3 Suppression du port SSH ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Modifier le Security Group de l'instance EC2 pour supprimer la règle entrante sur le port 22. | ||
| + | |||
| + | Depuis la console AWS : | ||
| + | EC2 > Security Groups > Sélectionner le SG de l'instance > Inbound rules > Supprimer la règle port 22 | ||
| + | |||
| + | Vérifier qu'une connexion SSH directe est bien refusée : | ||
| + | |||
| + | <sxh bash; | ||
| + | ssh -i ~/ | ||
| + | # Attendu : Connection refused ou timeout | ||
| + | </ | ||
| + | |||
| + | Vérifier que Session Manager fonctionne toujours : | ||
| + | |||
| + | <sxh bash; | ||
| + | aws ssm start-session --target INSTANCE_ID | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ===== 13.4 Limite actuelle – Ansible et SSM ===== | ||
| + | |||
| + | <WRAP round question> | ||
| + | * Le playbook Ansible utilise encore SSH pour se connecter à l'instance alors que le port 22 vient d' | ||
| + | * Dans une architecture sans SSH, deux alternatives à Ansible sont envisageables : le plugin de connexion SSM d' | ||
| + | * Plus largement, le modèle push d' | ||
| + | </ | ||
| + | |||
| + | ===== Challenge final ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | L' | ||
| + | |||
| + | Point 1 : Rotation automatique du secret | ||
| + | |||
| + | Configurer Secrets Manager pour effectuer une rotation automatique du mot de passe RDS tous les 30 jours. | ||
| + | |||
| + | Point 2 : Inventaire Ansible dynamique | ||
| + | |||
| + | Remplacer le fichier '' | ||
| + | |||
| + | Point 3 : Notifications de déploiement | ||
| + | |||
| + | Ajouter une étape dans le pipeline GitHub Actions pour envoyer une notification (Slack ou email) en cas de succès ou d' | ||
| + | </ | ||
| + | |||
| + | <WRAP round question> | ||
| + | Questions de synthèse : | ||
| + | |||
| + | * La rotation automatique du secret en point 1 résout un problème de sécurité, mais crée un risque opérationnel. Lequel, et comment le playbook Ansible doit-il être adapté pour y faire face ? | ||
| + | * Si l' | ||
| + | * Ce pipeline déploie en continu sur la branche '' | ||
| + | </ | ||
| + | |||
| + | ===== Bonus – Déploiement Blue/Green simplifié ===== | ||
| + | |||
| + | <WRAP round todo> | ||
| + | Mettre en place un déploiement sans interruption de service. | ||
| + | |||
| + | Modifier le playbook Ansible pour : | ||
| + | |||
| + | * déployer le nouveau jar dans un répertoire horodaté | ||
| + | * basculer un lien symbolique vers la nouvelle version | ||
| + | * redémarrer le service uniquement si le jar a changé | ||
| + | |||
| + | Fichier : '' | ||
| + | </ | ||
| + | |||
| + | <sxh yaml> | ||
| + | --- | ||
| + | - hosts: web | ||
| + | become: true | ||
| + | |||
| + | vars: | ||
| + | app_dir: /opt/demo | ||
| + | releases_dir: | ||
| + | app_jar: demo.jar | ||
| + | app_user: appuser | ||
| + | timestamp: "{{ ansible_date_time.epoch }}" | ||
| + | |||
| + | tasks: | ||
| + | - name: Créer le répertoire de la release | ||
| + | file: | ||
| + | path: "{{ releases_dir }}/{{ timestamp }}" | ||
| + | state: directory | ||
| + | owner: "{{ app_user }}" | ||
| + | mode: ' | ||
| + | |||
| + | - name: Copier le jar dans le répertoire de la release | ||
| + | copy: | ||
| + | src: ../ | ||
| + | dest: "{{ releases_dir }}/{{ timestamp }}/{{ app_jar }}" | ||
| + | owner: "{{ app_user }}" | ||
| + | mode: ' | ||
| + | |||
| + | - name: Basculer le lien symbolique vers la nouvelle release | ||
| + | file: | ||
| + | src: "{{ releases_dir }}/{{ timestamp }}/{{ app_jar }}" | ||
| + | dest: "{{ app_dir }}/ | ||
| + | state: link | ||
| + | owner: "{{ app_user }}" | ||
| + | |||
| + | - name: Redémarrer le service | ||
| + | | ||
| + | name: demo | ||
| + | state: restarted | ||
| + | </ | ||
| + | |||
| + | <WRAP round question> | ||
| + | * Ce déploiement réduit l' | ||
| + | * Le lien symbolique est basculé avant le redémarrage du service. Si le redémarrage échoue, dans quel état se trouve l' | ||
| + | * Sans politique de nettoyage, les répertoires de releases s' | ||
| + | </ | ||