
🌐 Aussi en: English · Deutsch · Español
Un blog et deux serveurs Nextcloud pour des associations locales : rien sur ces machines ne vaut une attaque ciblée – et c’est justement pour cela qu’elles sont attaquées. Pas par quelqu’un qui veut mes données, mais par des scanners qui essaient chaque adresse IP d’Internet, toutes les heures, avec toujours la même poignée d’astuces. La plupart abandonnent à la première porte fermée. La question, c’est ce qui se passe avec ceux qui insistent.
La réponse porte un nom : Defense in Depth, la défense en profondeur. Aucune mesure n’a besoin d’être parfaite, parce que derrière chaque couche il y en a une autre. Cet article rassemble toutes les couches dont mes serveurs disposent aujourd’hui – puis fait quelque chose d’un peu inconfortable : j’ai demandé à mon co-admin IA (Claude) de lire tout ce que j’ai publié sur cette installation et de penser comme un attaquant. Par où commencerait-il ?
🧅 Pourquoi un seul mur ne suffit pas
Toute mesure de sécurité peut faillir. Une règle de pare-feu reçoit une faute de frappe. Un service censé bannir les attaquants s’arrête sans bruit – le mien l’a fait pendant deux jours, et personne ne l’a remarqué. Un plugin livre une faille un mardi et le correctif arrive le jeudi. Si l’une de ces choses est la seule barrière entre Internet et vos données, vous êtes à une mauvaise journée d’une intrusion.
La défense en profondeur renverse la perspective : partez du principe que chaque couche finira par céder, et faites en sorte que la suivante tienne quand même. Il y a un second avantage, moins évident – un attaquant qui franchit une couche doit faire du bruit pour franchir la suivante, et le bruit, cela se détecte.
🛡️ Les couches
1. La frontière réseau
Le pare-feu (nftables) rejette tout ce qui n’est pas explicitement autorisé : le trafic web sur 80/443 et SSH sur un port non standard. La supervision, les bases de données et les ports internes ne répondent que sur localhost ou à l’intérieur du cluster. SSH n’accepte en outre de nouvelles connexions que depuis les plages d’adresses de mon propre pays – cela n’arrête pas quelqu’un de déterminé (un serveur loué dans le bon pays coûte peu), mais cela supprime environ 98 % du bruit de fond, si bien que les tentatives restantes se remarquent vraiment.
2. SSH
Clés uniquement, pas de mots de passe – fixé dans un fragment de configuration classé avant tout ce qu’une image cloud ajoute, après avoir surpris l’image d’un hébergeur en train de réactiver discrètement les connexions par mot de passe. En plus, sshd tourne dans un bac à sable systemd dont hérite chaque session : pas de chargement de modules du noyau, pas de modification des paramètres du noyau. Root peut toujours le faire délibérément via systemd-run, c’est donc un obstacle et non un mur – mais la séquence classique « se connecter, charger un module rootkit » échoue, et le chargement de modules est de toute façon consigné dans le journal d’audit.
3. Le blocage automatique
fail2ban lit le journal SSH et le journal d’accès du serveur web, et bannit les adresses qui devinent des mots de passe, cherchent des fichiers bien connus ou martèlent les pages de connexion. Les récidivistes sont bannis bien plus longtemps. Les bannissements vont directement dans le pare-feu, et un chien de garde redémarre fail2ban si jamais il s’arrête de nouveau.
4. Le serveur web
TLS uniquement, avec des en-têtes de sécurité stricts. Les URL de connexion sont limitées en débit. Les chemins que les attaquants adorent – fichiers de configuration, .env, .git, le XML-RPC de WordPress – sont bloqués avant même d’atteindre PHP, et WordPress ne divulgue plus ses noms d’utilisateur via l’API REST.
5. Les conteneurs
Les applications tournent dans Kubernetes (K3s). Des NetworkPolicies décident quel pod peut parler à quel autre – un WordPress compromis ne peut pas simplement se connecter à tout ce qu’il veut. Une politique d’admission n’autorise que les images de conteneurs provenant de registres approuvés, les jetons de compte de service ne sont pas montés là où ils ne servent à rien, et SELinux est en mode « enforcing » : un conteneur ne peut écrire que dans les répertoires explicitement étiquetés pour lui.
6. Les applications elles-mêmes
WordPress met à jour le cœur, les plugins, les thèmes et les traductions chaque nuit – avec une sauvegarde de la base de données avant et une vérification après que le site répond toujours. Les plugins et thèmes inutilisés sont supprimés, pas seulement désactivés, car du code désactivé reste accessible. Nextcloud impose une politique de mots de passe et freine les tentatives de force brute ; les comptes administrateurs utilisent l’authentification à deux facteurs.
7. La détection
La prévention finit par échouer ; la détection, c’est ce qui vous permet de le savoir. AIDE vérifie chaque nuit si des fichiers système ont changé, rkhunter cherche des rootkits, ClamAV analyse les fichiers téléversés, auditd surveille les fichiers d’identité, sudo et les secrets du cluster, et un chien de garde (Monit) m’envoie un mail quand un service, le pare-feu, un certificat ou la sauvegarde n’est pas dans l’état attendu. Tant que tout va bien, ils restent tous silencieux – chaque mail signifie donc quelque chose.
8. La restauration
La dernière couche est celle dont on espère ne jamais avoir besoin. Les sauvegardes sont récupérées par une machine chez moi, pas envoyées par les serveurs – un serveur compromis n’a aucun identifiant pour les atteindre – et conservées avec 30 jours d’historique, si bien que même quelque chose resté inaperçu pendant une semaine peut être annulé.
9. Le processus
Tout ce qui précède est configuré par Ansible à partir d’un dépôt Git – ce qui fait du dépôt une partie de la surface d’attaque. Les secrets ne vivent que dans un coffre chiffré (vault) qui ne touche jamais Git. Chaque commit passe par un linter et un détecteur de secrets. Les versions sont épinglées, les mises à jour arrivent sous forme de pull requests relues, et chaque modification est d’abord simulée contre les vrais serveurs avant d’être exécutée pour de bon.
🕵️ Penser comme un attaquant
Voici la partie inconfortable. Mon code Ansible est public, tout comme plusieurs articles sur la façon dont ces serveurs sont construits. J’ai donc demandé à Claude : tu connais tout cela – par où commencerais-tu ?
La réponse n’était pas « le pare-feu » ni « SSH ». Elle était bien plus banale :
- Les applications. Un plugin ou une application avec une faille fraîche est de loin le chemin le plus probable. Les mises à jour nocturnes réduisent cette fenêtre ; elles ne peuvent pas la fermer.
- Les gens. L’un des serveurs Nextcloud compte plus d’une centaine de comptes. Un mot de passe réutilisé ou un mail d’hameçonnage convaincant bat toutes les couches techniques ci-dessus – sans le moindre exploit.
- La chaîne d’approvisionnement. Celui qui contrôle mon compte Git ou ma machine d’administration n’a pas besoin d’attaquer les serveurs : je déploierais son code moi-même.
- Les choses oubliées. Des comptes que plus personne n’utilise, des liens de partage sans date d’expiration, de vieux réglages qui dorment encore dans une base de données.
La leçon : une fois les bases techniques en place, les points faibles se déplacent là où se trouvent les personnes et les processus.
🔑 Conception publique, clés secrètes
Reste la question évidente : n’est-il pas imprudent de publier tout cela ? Les cryptographes y ont répondu en 1883. Le principe de Kerckhoffs dit qu’un système doit rester sûr même si tout à son sujet est public – sauf la clé. C’est ainsi que fonctionne tout le chiffrement que vous utilisez aujourd’hui : les algorithmes sont publiés, étudiés et attaqués par des experts du monde entier, et ils restent sûrs parce que la clé reste secrète.
Mes serveurs suivent la même idée. Savoir que SSH n’accepte que des clés, sur quel port, depuis quel pays, derrière quelles règles de pare-feu, ne rapproche personne d’un seul pas sans la clé privée. Savoir que la configuration se trouve dans un vault Ansible n’aide pas sans le mot de passe du vault. Savoir que les administrateurs utilisent l’authentification à deux facteurs n’aide pas sans le téléphone. La conception est publique ; les clés ne quittent jamais les endroits où elles doivent être.
L’inverse – une sécurité qui ne fonctionne que tant que personne ne sait comment elle fonctionne – est fragile : un document qui fuite, un initié curieux, et elle disparaît. Cacher des détails peut quand même coûter du temps à un attaquant, mais seulement comme couche supplémentaire, jamais comme fondation. La seule chose qui ne doit pas être publiée, c’est la liste des failles pas encore corrigées.
Et une dernière chose, pour ceux qui lisent ceci avec de mauvaises intentions : toutes les couches ne sont pas décrites dans cet article. Quelques protections et pièges de ces serveurs ont été délibérément laissés de côté – vous ne les découvrirez qu’en les déclenchant.
🔧 Ce que j’ai changé après cette conversation
- L’authentification à deux facteurs pour chaque compte administrateur sur les deux serveurs Nextcloud et sur le blog – avec des codes de secours imprimés, et la certitude que l’accès SSH permet toujours de la désactiver si un téléphone est perdu.
- Une politique de mots de passe sur les deux serveurs Nextcloud : au moins 12 caractères, pas de mots de passe très courants, et pas de mots de passe apparaissant dans des fuites de données connues. Cette dernière vérification utilise la k-anonymité : seuls les cinq premiers caractères de l’empreinte du mot de passe quittent le serveur.
- Comptes inactifs désactivés : tous ceux qui ne s’étaient pas connectés depuis plus d’un an, plus les comptes qui ne se sont jamais connectés – trente au total, dont un second administrateur inutilisé. Leurs données restent ; les comptes peuvent être réactivés en quelques secondes.
- Les liens publics de dépôt expirent au lieu de rester ouverts pour toujours.
- Trois endroits où un mot de passe aurait pu finir dans un journal – seulement avec un diff ou un message d’erreur, mais quand même – sont désormais masqués.
Et une erreur, honnêtement. Activer la politique de mots de passe sur le plus grand Nextcloud a réveillé un réglage hérité de l’ancien serveur : les mots de passe expirent après 300 jours. Pendant quelques minutes, chaque mot de passe plus ancien était considéré comme expiré – y compris le mien. Le réglage est désormais fixé explicitement, et j’ai appris à lire la configuration existante d’une application avant de l’activer.
🤝 La couche organisationnelle
Tout ne se règle pas avec un fichier de configuration :
- Informer les utilisateurs. Une courte note sur les gestionnaires de mots de passe, l’authentification à deux facteurs et l’hameçonnage (« Nextcloud ne vous demandera jamais votre mot de passe par e-mail ») protège davantage que n’importe quel réglage serveur.
- Prévoir sa propre absence. Qui peut prendre le relais si je ne peux pas ? Où sont gardés les codes de récupération et le mot de passe du vault – sur papier, dans une enveloppe scellée, pas seulement dans ma tête ?
- Regarder régulièrement. Une courte vérification mensuelle : nouveaux comptes administrateurs, liens de partage ouverts, tout ce qui paraît étrange dans les journaux d’audit et de bannissement.
🎯 À retenir
Aucune de ces couches n’est impressionnante à elle seule, et chacune peut être contournée. Ensemble, elles transforment « une erreur et c’est fini » en « plusieurs erreurs, chacune remarquée ». C’est toute l’idée de la défense en profondeur – et le regard de l’attaquant m’a montré que les prochaines couches ne sont pas de nouvelles règles de pare-feu, mais les comptes, les habitudes et les machines depuis lesquelles j’administre.





