Hardening Linux : securiser son serveur de A a Z

Credit : Logo officiel

Hardening Linux : securiser son serveur de A a Z

Dylan D. — Agent Support Technique Serveur Securite 1882 mots 10 min de lecture

Pourquoi tout serveur expose doit etre durci des le jour 1

Un serveur Linux fraichement installe, expose sur Internet, recoit en moyenne sa premiere tentative de brute force SSH dans les 4 minutes apres l'ouverture du port 22. J'ai mesure ca sur un VPS Ionos commande pour un client en region parisienne le mois dernier : 4 minutes 12 secondes, premier Failed password dans auth.log. En 24 heures, c'etait 2800 tentatives depuis 60 IPs differentes, principalement Russie, Chine et Bresil.

Un serveur expose sans hardening, c'est un buffet a volonte pour les bots. Cet article regroupe la procedure complete que j'applique sur chaque nouvelle machine Debian 12 ou Ubuntu 22.04 LTS avant de la mettre en prod : SSH, pare-feu, fail2ban, CrowdSec, mises a jour, durcissement noyau, audit. C'est devenu mon checklist de mise en service, peaufine sur des dizaines de serveurs clients.

1. Securiser SSH : la premiere cible

SSH c'est la porte d'entree principale, donc la cible numero un des bots. Editer /etc/ssh/sshd_config :

# Changer le port (evite 90% des scans automatiques sur 22)
Port 2222

# Desactiver la connexion root
PermitRootLogin no

# Authentification par cle uniquement
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no

# Limiter les utilisateurs autorises
AllowUsers deploy admin

# Timeouts pour fermer les sessions oubliees
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30

# Protocole 2 uniquement
Protocol 2

# Desactiver les fonctionnalites inutiles sur un serveur
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no

# Cryptos modernes uniquement
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com

# Bannieres et logging
LogLevel VERBOSE

Valider la syntaxe avant de redemarrer :

sudo sshd -t
sudo systemctl restart sshd

IMPORTANT : ne fermez pas votre session avant de tester

Gardez votre session SSH actuelle ouverte. Ouvrez un nouveau terminal et testez la connexion sur le nouveau port avec votre cle. Si ca marche, vous pouvez fermer l'ancienne. Si ca echoue, votre session ouverte vous sauve la mise. J'ai deja vu un dev se verrouiller dehors un dimanche soir parce qu'il avait fait systemctl restart sshd puis exit sans tester. KVM console obligatoire pour reparer.

Details complets : securiser SSH avec sshd_config.

2. Pare-feu UFW : interdire par defaut

UFW est le frontend simplifie d'iptables sur Debian/Ubuntu. La logique : tout fermer par defaut, ouvrir uniquement ce qui est necessaire.

sudo apt install ufw

# Politique par defaut
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Autoriser SSH (sur le port custom)
sudo ufw allow 2222/tcp comment 'SSH'

# HTTP et HTTPS
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# Limiter les tentatives de connexion SSH
sudo ufw limit 2222/tcp

# Activer
sudo ufw enable
sudo ufw status verbose

Cas avance : whitelister par IP

# SSH uniquement depuis votre IP fixe
sudo ufw delete allow 2222/tcp
sudo ufw allow from 203.0.113.42 to any port 2222 proto tcp

# MySQL accessible uniquement depuis le serveur applicatif
sudo ufw allow from 10.0.0.5 to any port 3306 proto tcp

Pour des regles plus fines, voir comprendre et configurer iptables.

3. fail2ban : bannir les attaquants automatiquement

fail2ban surveille les logs et banni les IP apres plusieurs echecs. Indispensable :

sudo apt install fail2ban

Creer /etc/fail2ban/jail.local (ne JAMAIS modifier jail.conf directement) :

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw
ignoreip = 127.0.0.1/8 ::1 203.0.113.42

[sshd]
enabled = true
port = 2222
logpath = %(sshd_log)s
backend = systemd
maxretry = 3
bantime = 86400

[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log

[nginx-botsearch]
enabled = true
logpath = /var/log/nginx/access.log

[nginx-badbots]
enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2
sudo systemctl enable --now fail2ban

# Voir les bans actifs
sudo fail2ban-client status
sudo fail2ban-client status sshd

# Debannir une IP (urgence)
sudo fail2ban-client set sshd unbanip 203.0.113.99

Guide complet : configurer fail2ban contre les brute force.

4. CrowdSec : la threat intelligence collaborative

CrowdSec est l'alternative moderne a fail2ban, avec une base collaborative de menaces. Si une IP attaque un serveur en France, tous les serveurs CrowdSec dans le monde en profitent.

curl -s https://install.crowdsec.net | sudo sh
sudo apt install crowdsec crowdsec-firewall-bouncer-iptables

# Verifier le statut
sudo systemctl status crowdsec
sudo cscli metrics

# Lister les decisions actives (bans)
sudo cscli decisions list
sudo cscli alerts list

# Installer les collections utiles
sudo cscli collections install crowdsecurity/nginx
sudo cscli collections install crowdsecurity/linux
sudo cscli collections install crowdsecurity/iptables
sudo cscli collections install crowdsecurity/wordpress  # si WP

Sur mes serveurs, CrowdSec banni en moyenne 200 IPs par jour, dont 60% via la blocklist communautaire avant meme que l'attaque ne touche le serveur. Setup complet : configurer CrowdSec sur Linux.

fail2ban + CrowdSec ne font pas double emploi : le premier reagit aux logs locaux en temps reel, le second pre-bloque sur la base de l'intelligence collective.

5. Mises a jour automatiques

Un serveur non patche, c'est une CVE qui attend d'etre exploitee. Sur Debian/Ubuntu :

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

Config /etc/apt/apt.conf.d/50unattended-upgrades :

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
};

Unattended-Upgrade::Package-Blacklist {
    "mariadb-server";
    "mysql-server";
};

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Unattended-Upgrade::Mail "admin@monsite.fr";
Unattended-Upgrade::MailReport "on-change";

Les packages critiques (base de donnees) sont blackliste pour eviter qu'une mise a jour mineure ne casse une replication. Je les patche manuellement avec maintenance planifiee.

Tester sans appliquer :

sudo unattended-upgrade --dry-run --debug

6. Durcir le noyau via sysctl

Creer /etc/sysctl.d/99-hardening.conf :

# Anti-spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignorer les broadcasts ICMP
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Pas de redirections ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Bloquer le source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Protection SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2

# Logger les paquets suspects (martians)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Desactiver IPv6 si non utilise
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

# Limiter les coredumps
fs.suid_dumpable = 0

# Protection ASLR
kernel.randomize_va_space = 2

Appliquer :

sudo sysctl --system
# Verifier
sudo sysctl net.ipv4.tcp_syncookies

7. Auditer le systeme

Lynis : audit systematique

sudo apt install lynis
sudo lynis audit system

Lynis donne un score de hardening (Lynis index). Viser au-dessus de 75. La premiere fois que j'ai lance Lynis sur un serveur "en prod depuis 3 ans" recupere d'un client, le score etait a 42. J'ai pas dormi cette nuit-la, j'ai patche pendant le week-end.

Les warnings principaux a corriger :

Rootkits et integrite

sudo apt install rkhunter chkrootkit aide
sudo rkhunter --update
sudo rkhunter --propupd
sudo rkhunter --check --skip-keypress

sudo chkrootkit

# AIDE pour la detection de modifications
sudo aideinit
sudo aide --check

Inventaire des services et ports

# Ports ouverts en ecoute
sudo ss -tlnp

# Services systemd actifs
sudo systemctl list-units --type=service --state=running

# Fichiers SUID potentiellement dangereux
find / -type f -perm -4000 -exec ls -la {} \; 2>/dev/null

# Comptes avec UID 0 (devrait etre uniquement root)
awk -F: '($3 == 0) {print}' /etc/passwd

# Comptes sans mot de passe
sudo awk -F: '($2 == "") {print}' /etc/shadow

8. Permissions sensibles

# Fichiers systeme
sudo chmod 1777 /tmp
sudo chmod 600 /etc/shadow
sudo chmod 600 /etc/gshadow
sudo chmod 644 /etc/passwd
sudo chmod 644 /etc/group
sudo chmod 600 /etc/ssh/sshd_config

# Restreindre cron aux users autorises
echo "deploy" | sudo tee /etc/cron.allow
echo "root" | sudo tee -a /etc/cron.allow

# Idem pour at
sudo touch /etc/at.allow
sudo chmod 600 /etc/at.allow

Rappel sur les permissions Linux : chmod, chown, ACL.

9. Monitoring et alerting

Un serveur durci sans monitoring, c'est un coffre-fort sans alarme : les attaques echouent, mais vous ne saurez jamais qu'il y en a eu. Mettre en place :

Erreurs courantes et leur fix

1. Locked out apres restart SSH

Vous avez modifie sshd_config et fait systemctl restart sshd sans tester. Solution : passer par la console KVM/VNC du fournisseur (Ionos, OVH, Scaleway proposent ca). Reverter la config via la console.

2. UFW casse Docker

Docker manipule iptables directement et bypasse UFW par defaut. Fix : editer /etc/default/ufw :

DEFAULT_FORWARD_POLICY="ACCEPT"

Et dans /etc/ufw/after.rules, ajouter les regles Docker. Ou utiliser iptables directement si setup complexe.

3. Mises a jour automatiques cassent une appli

Un paquet a une nouvelle version qui casse votre stack (ex : majeur PHP). Fix : ajouter le paquet a la blacklist :

Unattended-Upgrade::Package-Blacklist {
    "php8.2";
    "php8.2-fpm";
};

4. fail2ban ne banni rien

Log mal lu. Verifier :

sudo fail2ban-client -d  # mode debug
sudo tail -f /var/log/fail2ban.log

Souvent le logpath ne pointe pas sur le bon fichier (ex : auth.log vs journal systemd).

5. Lynis pleure sur AppArmor

Sur Debian, AppArmor est present mais peu profile. Activer les profiles :

sudo apt install apparmor-profiles apparmor-utils
sudo systemctl enable --now apparmor
sudo aa-enforce /etc/apparmor.d/*

Checklist finale du hardening

[ ] SSH sur port non standard, cles uniquement, root desactive
[ ] Utilisateur deploy cree, sudo configure
[ ] UFW actif avec deny incoming par defaut
[ ] fail2ban en place avec jail SSH/Nginx
[ ] CrowdSec installe avec collections nginx + linux
[ ] Mises a jour automatiques activees
[ ] sysctl durci applique
[ ] AppArmor en mode enforce
[ ] Audit Lynis > 75 points
[ ] Sauvegardes automatisees ET testees
[ ] Monitoring (Netdata) avec alertes mail
[ ] Logs centralises (journalctl persistant)

Pour aller plus loin

Documenter et formaliser le hardening

Une erreur classique : appliquer ces commandes une fois sur un serveur, ne rien noter, et 6 mois plus tard ne plus savoir ce qui a ete fait. Ma methode : un playbook Ansible qui regroupe l'ensemble du hardening de cet article, versionne sur Git. A chaque nouveau serveur, ansible-playbook hardening.yml -i nouveau.host et tout est applique en 4 minutes, identique partout.

Details dans Ansible pour debutants : automatiser la config serveur. Le ROI est immediat des le 3eme serveur a configurer.

La securite, ce processus jamais termine

La securisation c'est pas un truc qu'on fait une fois et qu'on oublie. C'est un processus continu : nouveaux CVE chaque semaine, nouveaux vecteurs d'attaque, nouveaux outils defensifs. Planifiez un audit complet (Lynis + revue des logs + test de restauration backup) tous les 3 mois. Et surtout, gardez les logs : journalctl -p err une fois par semaine, auth.log apres chaque incident. Un serveur attaque sans logs, c'est une enquete impossible. Avec des logs, c'est souvent quelques minutes pour comprendre et patcher.

# Articles similaires

Sur les memes sujets et plus loin