Paillasse/docs/journal.md
Adam Belkacemi f5a5e8d8a9 durcit le serveur : pare-feu nftables, SSH par clé, fail2ban, chrony, mises à jour de sécurité
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-07 10:32:09 +02:00

7 KiB

Journal de bord — Syllabus (ex-Paillasse)

2026-10-07 — Étape 1 : reconnaissance du serveur

Fait

  • Déblocage de l'accès SSH : la clé dédiée ~/.ssh/id_ed25519_claude avait une passphrase sans invite interactive disponible dans Claude Code. Adam a retiré la passphrase lui-même (ssh-keygen -p -f ~/.ssh/id_ed25519_claude, nouvelle passphrase vide).
  • ⚠️ Incident mineur : au premier essai, Adam a collé l'ancienne passphrase directement dans la conversation avec Claude Code au lieu de la taper dans le prompt du terminal. Elle n'a pas été utilisée ni répétée, et elle est devenue sans objet dès que la passphrase de la clé a été retirée. Point d'attention pour la suite : ne jamais coller de secret dans le chat, toujours dans le terminal.
  • Alias paillasse créé dans ~/.ssh/config (163.172.4.195, utilisateur adam, IdentityFile ~/.ssh/id_ed25519_claude, IdentitiesOnly yes).
  • Reconnaissance en lecture seule via SSH : OS, noyau, CPU, virtualisation, RAM, disques/RAID, réseau, état actuel de SSH et du pare-feu, paquets de durcissement déjà présents ou non.
  • Vérification dans la documentation officielle OpenStack (support matrix + page des séries) de la version de Kolla-Ansible à utiliser : 2025.2 (Flamingo), seule série récente qui supporte encore Debian 12 bookworm et qui est encore maintenue.
  • Écriture de docs/inventaire-serveur.md.

Commandes clés

ssh -i ~/.ssh/id_ed25519_claude -o IdentitiesOnly=yes adam@163.172.4.195 ...
ssh paillasse "lscpu; ls -la /dev/kvm; cat /proc/mdstat; ip -br a; sudo nft list ruleset; sudo sshd -T"

Problèmes rencontrés et solution

  • Connexion SSH refusée (Permission denied (publickey,password)) : la clé privée avait une passphrase, et l'environnement Claude Code n'a pas de terminal interactif pour la saisir (ssh_askpass absent). Solution : Adam a retiré la passphrase lui-même avec ssh-keygen -p.

Comprendre

Avant de changer quoi que ce soit, il fallait savoir précisément sur quoi on allait travailler : est-ce que la virtualisation matérielle marche vraiment (sans ça, pas d'OpenStack utilisable), le RAID est-il sain, combien de RAM reste disponible, et surtout quelle version de Kolla-Ansible est compatible avec Debian 12. C'est important car OpenStack évolue vite : la version la plus récente (2026.1) a justement arrêté de supporter Debian 12, donc l'installer aveuglément aurait bloqué tout le projet dès l'étape 5. On a aussi remarqué que le pare-feu est aujourd'hui totalement ouvert et que root peut encore se connecter par clé : ce sont exactement les deux points que l'étape 2 (durcissement) va corriger. Rien n'a été modifié sur le serveur à cette étape, uniquement des commandes de lecture.

Suite

Étape 2 : durcissement SSH + pare-feu nftables + fail2ban/chrony/unattended-upgrades, via un rôle Ansible depuis le Mac. C'est une étape qui touche SSH et le réseau : je vais détailler la commande avant de l'exécuter, prévoir un retour arrière automatique (anti-coupure), et ne redémarrer/couper rien sans l'accord explicite d'Adam pour les points couverts par la règle 3 du prompt de déploiement.

2026-10-07 — Étape 2 : durcissement du serveur

Fait

  • Rôle Ansible durcissement (ansible/roles/durcissement/) + playbook ansible/durcissement.yml, appliqués après accord explicite d'Adam.
  • Pare-feu nftables : tout refusé en entrée sauf loopback, trafic établi, ICMP, et les ports 22/80/443.
  • SSH : PermitRootLogin no, PasswordAuthentication no (connexion par clé uniquement), via un drop-in /etc/ssh/sshd_config.d/99-durcissement.conf.
  • fail2ban (jail sshd, backend nftables car pas d'iptables sur l'image), chrony (remplace systemd-timesyncd), unattended-upgrades (sécurité auto, redémarrage automatique explicitement désactivé — un reboot reste une décision d'Adam).
  • Filet de sécurité anti-coupure : timer systemd-run de 5 minutes armé avant toute modification du pare-feu/SSH, script de retour à l'état précédent (/usr/local/sbin/durcissement-rollback.sh), désarmé seulement après vérification réussie depuis une connexion SSH toute neuve + nmap.
  • Vérifié deux fois l'idempotence (rejouer le playbook ne change rien d'inattendu).

Commandes clés

cd ansible && script -q /dev/null ansible-playbook durcissement.yml -i inventory.ini
ssh paillasse "sudo systemctl list-timers | grep durcissement"   # filet de sécurité
nmap -Pn -T4 --open 163.172.4.195

Problèmes rencontrés et solution

  1. Bug dans le rôle : le notify pour recharger sshd manquait sur la tâche de dépôt de la config SSH → sshd jamais rechargé au 1er essai → le filet de sécurité s'est déclenché (normal, rien de cassé) → corrigé en ajoutant le notify.
  2. Le test de vérification nmap -p- (65535 ports) était beaucoup trop lent face à une politique drop (chaque port fermé attend un timeout) → dépassait les 5 minutes du filet de sécurité → 2ᵉ déclenchement automatique du rollback (normal, rien de cassé) → corrigé en limitant le scan aux ports par défaut + -T4 (4,5 s au lieu de plusieurs minutes).
  3. Incident réel : auto-bannissement par fail2ban. Les tentatives volontairement ratées (mot de passe, root) de nos propres tests de vérification, répétées sur plusieurs runs rapprochés, ont dépassé le seuil maxretry = 5 de fail2ban : l'IP du Mac d'Adam s'est fait bannir par son propre pare-feu. Résolu via la console web Scaleway (hors bande) avec fail2ban-client set sshd unbanip. Post-mortem complet : docs/postmortems/2026-10-07-fail2ban-auto-ban.md. Correctif : maxretry relevé à 10.

Critère vérifié

  • Connexion par clé : OK. Mot de passe : refusé (Permission denied (publickey), sans mention de password dans les méthodes offertes). Root : refusé. nmap -Pn -T4 --open 163.172.4.195 depuis le Mac : seul le port 22 est ouvert (80/443 autorisés par le pare-feu mais rien n'écoute encore dessus — normal, le portail arrive à l'étape 8).

Comprendre

Durcir un serveur, c'est fondamentalement risqué pour l'accès qu'on a déjà : chaque changement de pare-feu ou de SSH peut potentiellement nous enfermer dehors. D'où le filet de sécurité (un minuteur qui annule tout automatiquement si on ne confirme pas que ça marche dans les 5 minutes) : il s'est déclenché deux fois pendant la mise au point, et les deux fois c'était le bon comportement — un bug ailleurs, pas un défaut du filet. L'incident fail2ban est différent et plus subtil : ce n'est pas le pare-feu qui nous a bloqués, c'est un service de protection qu'on vient d'installer qui a réagi à nos propres tests comme à une attaque. C'est un vrai piège classique en administration système, qui vaut la peine d'être raconté en entretien : on protège un système contre tout le monde, y compris soi-même si on ne fait pas attention au volume de ses propres tentatives.

Suite

Étape 3 : sauvegardes vers Dedibackup (archives tar.zst chiffrées age, rotation 7 quotidiennes + 4 hebdomadaires, timer systemd).