1. Principles #
Reducing the attack surface.
Defense in depth #
- Minimalism: install only what is needed; every package is a potential vulnerability.
- Least privilege: one account per service, without a shell; limited sudo.
- Updates: automatic security fixes, scheduled reboots.
- Traceability: named accounts, logs kept off the server.
- Benchmarks: CIS Benchmarks, the ANSSI guide « Configuration recommendations of a GNU/Linux system ».
ss -tlnup # services exposés : chacun est-il nécessaire ?
systemctl list-unit-files --state=enabled
sudo apt purge telnetd rsh-server # retirer les services obsolètes2. SSH #
The front door.
sshd_config #
# /etc/ssh/sshd_config.d/10-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowGroups ssh-users
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2sudo sshd -t && sudo systemctl reload ssh # valider puis recharger
sudo grep 'Failed password\|Invalid user' /var/log/auth.log | tailCommon mistake: Keep an SSH session open while you test the new configuration in a second terminal: if something goes wrong, you can still fix it.
fail2ban #
fail2ban reads the logs and temporarily bans (via the firewall) addresses that accumulate failures.
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1hsudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd3. Mandatory access control #
SELinux and AppArmor.
Why #
With classic permissions (DAC), a compromised process can do everything its user can. SELinux (Red Hat family) and AppArmor (Debian, Ubuntu, SUSE) add a policy enforced by the kernel: nginx can only read files labeled for it, even if they are readable by everyone.
SELinux #
getenforce ; sestatus # Enforcing, Permissive ou Disabled
ls -Z /var/www/html ; ps -eZ | grep nginx # contextes
sudo ausearch -m avc -ts recent # refus récents
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/www(/.*)?'
sudo restorecon -Rv /srv/www # appliquer le bon contexte
sudo setsebool -P httpd_can_network_connect on
sudo semanage port -a -t http_port_t -p tcp 8081Common mistake: Disabling SELinux to « make an application work » removes a layer of protection. Diagnose the denial (ausearch,audit2why) and fix the context.
AppArmor #
sudo aa-status # profils chargés et mode
sudo aa-complain /usr/sbin/nginx # mode apprentissage (journalise sans bloquer)
sudo aa-enforce /usr/sbin/nginx
sudo journalctl -k | grep -i apparmor4. Kernel, audit and integrity #
Detecting and limiting.
sysctl #
# /etc/sysctl.d/90-hardening.conf
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
fs.protected_symlinks = 1
fs.suid_dumpable = 0Audit and integrity #
sudo sysctl --system # appliquer
sudo auditctl -w /etc/passwd -p wa -k comptes # surveiller les écritures
sudo ausearch -k comptes
sudo aide --init && sudo aide --check # base d'intégrité des fichiers
sudo lynis audit system # audit de durcissement avec scoreGood practice: Send logs (auth, audit, sudo) to a central platform: an attacker who gains root erases local traces first.
Secrets and encryption #
- Secret files in
600, owned by the service account. - Disk encryption (LUKS) for laptops and servers outside the data center.
- TLS certificates renewed automatically (certbot, ACME).
- No secrets in shell history, command arguments (visible in
ps) or Git.
