--- - name: installer les paquets de durcissement ansible.builtin.apt: name: - nftables - fail2ban - chrony - unattended-upgrades state: present update_cache: true cache_valid_time: 3600 - name: régler le fuseau horaire sur Europe/Paris community.general.timezone: name: Europe/Paris - name: vérifier la présence de systemd-timesyncd ansible.builtin.stat: path: /lib/systemd/system/systemd-timesyncd.service register: durcissement_timesyncd_unit - name: désactiver systemd-timesyncd (remplacé par chrony) ansible.builtin.systemd: name: systemd-timesyncd state: stopped enabled: false when: durcissement_timesyncd_unit.stat.exists - name: configurer chrony ansible.builtin.copy: content: | # Géré par Ansible (rôle durcissement) : configuration par défaut de Debian, # conservée volontairement (pools NTP standard). Pas de changement nécessaire # ici pour l'instant : la présence du paquet et le service actif suffisent. dest: /etc/chrony/conf.d/durcissement.conf mode: "0644" notify: redémarrer chrony - name: configurer les mises à jour automatiques (listes + sécurité) ansible.builtin.template: src: 20auto-upgrades.j2 dest: /etc/apt/apt.conf.d/20auto-upgrades mode: "0644" - name: interdire le redémarrage automatique par unattended-upgrades ansible.builtin.template: src: 51unattended-upgrades-local.conf.j2 dest: /etc/apt/apt.conf.d/51unattended-upgrades-local mode: "0644" - name: configurer fail2ban (jail sshd, backend nftables) ansible.builtin.template: src: jail.local.j2 dest: /etc/fail2ban/jail.local mode: "0644" notify: redémarrer fail2ban - name: créer le répertoire des règles nftables additionnelles ansible.builtin.file: path: /etc/nftables.d state: directory owner: root group: root mode: "0750" - name: déployer le script de retour à l'état d'avant durcissement ansible.builtin.template: src: durcissement-rollback.sh.j2 dest: /usr/local/sbin/durcissement-rollback.sh mode: "0700" owner: root group: root # --- À partir d'ici : modifications du pare-feu et de SSH. --- # Règle 4 (anti-coupure) : on arme un retour automatique avant de toucher à quoi # que ce soit, et on ne l'annule qu'après avoir vérifié l'accès depuis une # session SSH toute neuve (voir la vérification plus bas, delegate_to: localhost). - name: armer le filet de sécurité ({{ durcissement_delai_filet_secondes }} s) ansible.builtin.command: cmd: > systemd-run --unit=durcissement-rollback --on-active={{ durcissement_delai_filet_secondes }} /usr/local/sbin/durcissement-rollback.sh become: true changed_when: true - name: déployer la politique de pare-feu nftables ansible.builtin.template: src: nftables.conf.j2 dest: /etc/nftables.conf mode: "0640" owner: root group: root validate: "nft -c -f %s" notify: recharger nftables - name: appliquer le pare-feu immédiatement ansible.builtin.meta: flush_handlers - name: déployer la configuration SSH durcie ansible.builtin.template: src: sshd-durcissement.conf.j2 dest: /etc/ssh/sshd_config.d/99-durcissement.conf mode: "0644" owner: root group: root register: durcissement_sshd_conf notify: recharger ssh - name: valider la syntaxe sshd avant de recharger ansible.builtin.command: sshd -t become: true changed_when: false - name: appliquer la configuration SSH ansible.builtin.meta: flush_handlers - name: pause avant vérification (laisser les services redémarrer) ansible.builtin.pause: seconds: 3 - name: "vérification : nouvelle connexion SSH par clé (depuis le Mac)" ansible.builtin.command: cmd: > ssh -o IdentitiesOnly=yes -o IdentityFile=~/.ssh/id_ed25519_claude -o ControlMaster=no -o ControlPath=none -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new adam@163.172.4.195 echo CONNEXION_CLE_OK delegate_to: localhost become: false register: durcissement_verif_cle changed_when: false - name: "vérification : le mot de passe est refusé" # BatchMode empêche seulement l'invite interactive ; le serveur annonce quand # même au client les méthodes qu'il accepte. On vérifie donc le contenu du # message d'erreur ("password" ne doit plus y figurer), pas seulement le rc. ansible.builtin.command: cmd: > ssh -o IdentitiesOnly=yes -o PubkeyAuthentication=no -o PreferredAuthentications=password,keyboard-interactive -o BatchMode=yes -o ConnectTimeout=10 adam@163.172.4.195 echo NE_DOIT_PAS_S_AFFICHER delegate_to: localhost become: false register: durcissement_verif_mdp changed_when: false failed_when: > durcissement_verif_mdp.rc == 0 or 'password' in durcissement_verif_mdp.stderr - name: "vérification : root est refusé" ansible.builtin.command: cmd: > ssh -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new root@163.172.4.195 echo NE_DOIT_PAS_S_AFFICHER delegate_to: localhost become: false register: durcissement_verif_root changed_when: false failed_when: durcissement_verif_root.rc == 0 - name: "vérification : seuls 22, 80, 443 sont ouverts (nmap depuis le Mac)" # -p- (65535 ports) est beaucoup trop lent face à une politique "drop" : chaque # port fermé attend le timeout au lieu d'un rejet immédiat, et ça dépasse le # délai du filet de sécurité avant même d'avoir fini de scanner. Les 1000 ports # les plus courants (défaut de nmap) suffisent à vérifier qu'il n'y a rien # d'inattendu, et -T4 accélère le scan. ansible.builtin.command: cmd: nmap -Pn -T4 --open 163.172.4.195 delegate_to: localhost become: false register: durcissement_verif_nmap changed_when: false - name: afficher le résultat nmap ansible.builtin.debug: var: durcissement_verif_nmap.stdout_lines - name: désarmer le filet de sécurité (tout est vérifié) ansible.builtin.command: cmd: systemctl stop durcissement-rollback.timer become: true changed_when: true