2026-10-07 10:32:09 +02:00
|
|
|
---
|
|
|
|
|
- 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
|
|
|
|
|
|
2026-10-07 11:40:34 +02:00
|
|
|
- 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"
|
|
|
|
|
|
2026-10-07 10:32:09 +02:00
|
|
|
- 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
|
|
|
|
|
|
2026-10-07 15:50:54 +02:00
|
|
|
# Recharge même si nftables.conf n'a pas changé, pour effacer des tables
|
|
|
|
|
# ajoutées par un autre logiciel (ex. Docker) : -e durcissement_forcer_rechargement=true
|
|
|
|
|
- name: forcer le rechargement du pare-feu (sur demande)
|
|
|
|
|
ansible.builtin.command: /bin/true
|
|
|
|
|
changed_when: true
|
|
|
|
|
notify: recharger nftables
|
|
|
|
|
when: durcissement_forcer_rechargement | default(false) | bool
|
|
|
|
|
|
2026-10-07 10:32:09 +02:00
|
|
|
- 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
|