Configuration des outils de base de Debian
Dans cette partie nous configurerons les outils de bases du système : gestion des mise à jour, réglage de l'heure, ssh, le pare-feu, etc.
On commence par se connecter au serveur fraîchement installé par SSH avec l'utilisateur root
et le mot de passe défini à l'étape 11 de la partie précédente.
ssh-keygen -f "/home/alice/.ssh/known_hosts" -R "10.11.12.13"
ssh root@10.11.12.13
Étape 1 (fac) : Durcissement du noyau
Le durcissement du noyau Linux consiste à accroître les mécanismes de protection du noyau. Cela permet à la fois d'apporter des protections ou des contre-mesures à des vulnérabilités logicielles ou matérielles potentielles de la plateforme et réduire dans le même temps la surface d’attaque du noyau, initialement très grande.
On se basera essentiellement sur les recommendations de l'ANSSI (voir [ANSSI R7-14]) aussi détaillées plus simplement ici et là. D'autres références sont disponibles : en anglais et en français.
Pour modifier les paramètres du noyau, on utilisera l'outil sysctl
. Pour que les changements apportés au noyau soit appliqués au démarrage du système il suffit de créer un fichier de configuration (avec l’extension .conf
) dans le répertoire /etc/sysctl.d
. Dans ces fichiers de configuration il suffira d'indiquer la clef du paramètre à changer suivie de sa valeur. Pour avoir une liste assez complète des paramètres du noyau vous pouvez aller sur ce site et pour déterminer les paramètre actuel du noyau de votre système on peut utiliser la commande sysctl -a
.
On commence par les paramètres du noyau.
nano /etc/sysctl.d/10-kernel.conf
# Désactive les combinaisons de touches magiques (Magic System Request Key)
kernel.sysrq = 0
# Default : kernel.sysrq = 438
# Active l'ASLR
kernel.randomize_va_space = 2
# Default : kernel.randomize_va_space = 2
# Cache les adresses noyau dans /proc et les différentes autres interfaces,
# y compris aux utilisateurs privilégiés
kernel.kptr_restrict = 2
# Default : kernel.kptr_restrict = 0
# Restreint l'accès au buffer dmesg
kernel.dmesg_restrict = 1
# Default : kernel.dmesg_restrict = 1
# Interdit l'accès non privilégié à l'appel système perf_event_open (). Avec une
# valeur plus grande que 2, on impose la possession de CAP_SYS_ADMIN , pour pouvoir
# recueillir les évènements perf.
kernel.perf_event_paranoid = 3
# Default : kernel.perf_event_paranoid = 3
# Restreint l'utilisation du sous -système perf
kernel.perf_cpu_time_max_percent = 5
# Default : kernel.perf_cpu_time_max_percent = 25
# Restreint l'usage du BPF noyau aux utilisateurs privilégiés
kernel.unprivileged_bpf_disabled = 1
# Default : kernel.unprivileged_bpf_disabled = 2
# ptrace protections
kernel.yama.ptrace_scope = 1
# Default : kernel.yama.ptrace_scope = 0
# Désactive kexec
kernel.kexec_load_disabled = 1
# Default : kernel.kexec_load_disabled = 0
# Arrête complètement le système en cas de comportement inattendu du noyau Linux
kernel.panic_on_oops = 1
# Default : kernel.panic_on_oops = 0
# Interdit le chargement des modules noyau (sauf ceux déjà chargés à ce point)
kernel.modules_disabled = 1
# Default : kernel.modules_disabled = 0
On configure ensuite le réseau.
nano /etc/sysctl.d/20-network.conf
# Pas de routage entre les interfaces. Cette option est spéciale et peut
# entrainer des modifications d'autres options. En plaçant cette option au plus
# tôt , on s'assure que la configuration des options suivantes ne change pas.
net.ipv4.ip_forward = 0
# Default : net.ipv4.ip_forward = 0
# Vérifie que l'adresse source des paquets reçus sur une interface donnée aurait
# bien été contactée via cette même interface. À défaut, le paquet est ignoré.
# Selon l'usage, la valeur 1 peut permettre d'accroître la vérification à
# l'ensemble des interfaces, lorsque l'équipement est un routeur dont le calcul de
# routes est dynamique. Le lecteur intéressé est renvoyé à la RFC3704 pour tout
# complément concernant cette fonctionnalité.
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
# Default : net.ipv4.conf.all.rp_filter = 0
# Refuse la réception de paquet ICMP redirect. Le paramétrage suggéré de cette
# option est à considérer fortement dans le cas de routeurs qui ne doivent pas
# dépendre d'un élément extérieur pour déterminer le calcul d'une route. Même
# pour le cas de machines non-routeurs, ce paramétrage prémunit contre les
# détournements de trafic avec des paquets de type ICMP redirect.
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
# Default : net.ipv6.conf.all.accept_redirects = 1
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# Default : net.ipv4.conf.all.secure_redirects = 1
net.ipv4.conf.all.shared_media = 0
net.ipv4.conf.default.shared_media = 0
# Default : net.ipv4.conf.all.shared_media = 1
# Cette option ne doit être mise à 1 que dans le cas d'un routeur, car pour ces
# équipements l'envoi de ICMP redirect est un comportement normal. Un équipement
# terminal n'a pas de raison de recevoir un flux dont il n'est pas destinataire et
# donc d'émettre un paquet ICMP redirect.
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Default : net.ipv4.conf.all.send_redirects = 1
# Refuse les informations d'en-têtes de source routing fournies par le paquet
# pour déterminer sa route.
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Default : net.ipv6.conf.all.accept_source_route = 0
# Loguer les paquets ayant des IPs anormales
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# Default : net.ipv4.conf.all.log_martians = 0
# RFC 1337
net.ipv4.tcp_rfc1337 = 1
# Default : net.ipv4.tcp_rfc1337 = 0
# Ignorer les réponses non conformes à la RFC 1122
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Default : net.ipv4.icmp_ignore_bogus_error_responses = 1
# Augmenter la plage pour les ports éphémères
net.ipv4.ip_local_port_range = 32768 65535
# Default : net.ipv4.ip_local_port_range = 32768 60999
# Utilise les SYN cookies. Cette option permet la prévention d'attaque de
# type SYN flood.
net.ipv4.tcp_syncookies = 1
# Default : net.ipv4.tcp_syncookies = 1
# Désactivation de l'IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# Default : net.ipv6.conf.all.disable_ipv6 = 0
# Refuse le routage de paquet dont l'adresse source ou destination est celle de la
# boucle locale. Cela interdit l'émission de paquet ayant comme source 127/8.
net.ipv4.conf.all.route_localnet = 0
# Default : net.ipv4.conf.all.route_localnet = 0
# Ignore les "ICMP broadcasts" pour éviter de participer aux attaques Smurf
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Default : net.ipv4.icmp_echo_ignore_broadcasts = 1
# Atténuation de l'effet de dispersion du JIT noyau au coût d'un compromis sur
# les performances associées.
net.core.bpf_jit_harden = 2
# Default : net.core.bpf_jit_harden = 0
On configure ensuite la mémoire virtuelle. Il ne s'agit pas ici d'augmenter la sécurité mais d'optimiser les performances de la mémoire SWAP en fonction de l'utilisation du serveur. Pour plus d'information voir ce document.
nano /etc/sysctl.d/30-memory.conf
vm.swappiness = 15
# Default : vm.swappiness = 60
vm.dirty_ratio = 20
# Default : vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
# Default : vm.dirty_background_ratio = 10
On continue par les propriétés des systèmes de fichiers.
nano /etc/sysctl.d/40-filesystem.conf
# Désactive la création de coredump pour les exécutables setuid
fs.suid_dumpable = 0
# Default : fs.suid_dumpable = 0
# Disponible à partir de la version 4.19 du noyau Linux , permet d'interdire
# l'ouverture des FIFOS et des fichiers "réguliers" qui ne sont pas la propriété
# de l'utilisateur dans les dossiers sticky en écriture pour tout le monde.
fs.protected_fifos = 2
# Default : fs.protected_fifos = 1
fs.protected_regular = 2
# Default : fs.protected_regular = 2
# Restreint la création de liens symboliques à des fichiers dont l'utilisateur
# est propriétaire. Cette option fait partie des mécanismes de prévention contre
# les vulnérabilités de la famille Time of Check - Time of Use (Time of Check -
# Time of Use)
fs.protected_symlinks = 1
# Default : fs.protected_symlinks = 1
# Restreint la création de liens durs à des fichiers dont l'utilisateur est
# propriétaire. Ce sysctl fait partie des mécanismes de prévention contre les
# vulnérabilités Time of Check - Time of Use , mais aussi contre la possibilité de
# conserver des accès à des fichiers obsolètes
# fs.protected_hardinks = 1
# Default : n'existe pas
On termine par diverses propriétés.
nano /etc/sysctl.d/50-other.conf
# userfaultfd() est un appel système qui peut être abusé également,
# ce paramètre le restreint à la capacité CAP_SYS_PTRACE
vm.unprivileged_userfaultfd = 0
# Default : vm.unprivileged_userfaultfd = 0
# Cela limite le chargement des "TTY line disciplines" à la capacité CAP_SYS_MODULE
# pour empêcher les attaquants non privilégiés de charger des "line disciplines"
# vulnérables avec l'ioctl TIOCSETD
dev.tty.ldisc_autoload = 0
# Default : dev.tty.ldisc_autoload = 1
On peut finalement configurer les paramètres du noyau lors du démarrage en éditant le fichier de configuration /etc/default/grub
de GRUB et en modifiant la ligne GRUB_CMDLINE_LINUX_DEFAULT
. Cela fonction uniquement si GRUB a été installé comme chargeur d'amorçage. Pour EFISTUB
il faudra modifier le fichier /boot/efi/startup.nsh
.
nano /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet slab_nomerge=yes init_on_free=1 mce=0 spec_store_bypass_disable=seccomp spectre_v2=on pti=on"
GRUB_CMDLINE_LINUX=""
slab_nomerge=yes
(CONFIG_SLAB_MERGE_DEFAULT) : désactive la fusion de caches slabs (allocations mémoire dynamiques) de taille identique. Cette fonctionnalité permet de différentier les allocations entre les différents caches slabs, et complique fortement les méthodologies de pétrissage du tas (heap massaging) en cas de heap overflow ;init_on_free=1
(INIT_ON_FREE_DEFAULT_ON) : cela permet la remise à zéro de la mémoire à la libération, ce qui peut aider à atténuer les vulnérabilités d'utilisation après libération et à effacer les informations sensibles en mémoire.mce=0
: Cela provoque une panique du noyau sur les erreurs non corrigibles dans la mémoire ECC qui pourraient être exploitées. Ceci n'est pas nécessaire pour les systèmes sans mémoire ECC.spec_store_bypass_disable=seccomp
: force le système à utiliser la contre-mesure par défaut pour la vulnérabilité Spectre v4 (Speculative Store Bypass) ;spectre_v2=on
: force le système à utiliser une contre-mesure pour la vulnérabilité Spectre v2 (Branch Target Injection) ;pti=on
: force l’utilisation de Page Table Isolation (PTI) y compris sur les processeurs se prétendant non impactés par la vulnérabilité Meltdown ;page_poison=on
(CONFIG_PAGE_POISONING) : déjà activé par défaut dans Debian 12 ;init_on_alloc=1
(CONFIG_INIT_ON_ALLOC_DEFAULT_ON) : déjà activé par défaut dans Debian 12 ;page_alloc.shuffle=1
(CONFIG_SHUFFLE_PAGE_ALLOCATOR) : déjà activé par défaut dans Debian 12 ;randomize_kstack_offset=on
(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT) : déjà activé par défaut dans Debian 12 ;vsyscall=none
(CONFIG_LEGACY_VSYSCALL_NONE) : déjà activé par défaut dans Debian 12.
On finit en montant la partition /boot
et en mettant à jour Grub.
mount /boot
update-grub
reboot
Étape 2 : Configuration de mises à jour
Dans la partie précédente, on a fait le choix de monter les partitions /tmp
et /var
en nosuid, nodev, noexec
. Or le gestionnaire de paquets apt
a besoin par défaut que les fichiers écrits dans /tmp
et /var/lib/dpkg
soient exécutables.
Nous allons donc d'abord configurer apt
pour qu'il monte une partition temporaire dans /mnt/aptmp
avant d’installer ou de mettre à jour un paquet et qu'il démonte cette partition après l'installation du paquet. On fait de même avec la partition /boot
au cas où il y a une mise à jour du noyau.
mkdir /mnt/aptmp
nano /etc/apt/apt.conf.d/70debconf
DPkg::Pre-Install-Pkgs {
"/usr/sbin/dpkg-preconfigure --apt || true";
"mount -t tmpfs -o size=500m tmpfs /mnt/aptmp";
"mount /boot";
};
DPkg::Post-Invoke {
"umount /mnt/aptmp";
"umount /boot";
};
Maintenant on change les répertoires qu'utilisent apt
et dpkg
.
mkdir /root/varlibdpkg
cp -rp /var/lib/dpkg/* /root/varlibdpkg/
nano /etc/apt/apt.conf.d/50directories
APT::ExtractTemplates::TempDir "/mnt/aptmp";
Dir::State::status "/root/varlibdpkg/status";
Et on finit en rajoutant admindir=/root/varlibdpkg
au fichier /etc/dpkg/dpkg.cfg
.
nano /etc/dpkg/dpkg.cfg
no-debsig
log /var/log/dpkg.log
admindir=/root/varlibdpkg
Il est important d'avoir un serveur toujours à jour notamment pour les mise à jour de sécurité. Pour cela on peut utiliser l'outil unattended-upgrades
dont l'utilisation est décrite ici. On fait le choix ici d'utiliser une solution plus minimaliste en créant un petit script qui mettra à jour le système.
nano /root/apt_upgrade_daily.sh
#!/bin/bash
# On met à jour la liste des paquets
apt-get update
# On log le nombre de mises à jour
echo "APT UPGRADE : `apt-get -s upgrade | grep upgraded,`" | systemd-cat -p info
# On effectue les mises à jour
apt-get -y upgrade
# On indique au journal la nécessité de redémarrer le serveur
if [ -f /var/run/reboot-required ]; then
echo "APT UPGRADE : reboot required" | systemd-cat -p warning
fi
Il faut ensuite rendre ce script exécutable puis créer un timer systemd pour le lancer à intervalle régulier. Pour plus d'information sur les timers systemd voir ici.
chmod +x /root/apt_upgrade_daily.sh
nano /root/apt_upgrade_daily.service
[Unit]
Description=Daily apt upgrade
After=network.target
[Service]
Type=oneshot
ExecStart=/root/apt_upgrade_daily.sh
[Install]
WantedBy=multi-user.target
nano /root/apt_upgrade_daily.timer
[Unit]
Description=Daily apt upgrade
[Timer]
OnCalendar=*-*-* 3:00:00
RandomizedDelaySec=3h
Persistent=true
[Install]
WantedBy=timers.target
Il faut enfin activer le timer. On vérifie ensuite que tout fonctionne.
systemctl enable /root/apt_upgrade_daily.service
systemctl enable /root/apt_upgrade_daily.timer
systemctl start apt_upgrade_daily.timer
systemctl status apt_upgrade_daily.timer
systemctl list-timers --all
Étape 3 : Synchronisation de l'heure
Avoir un serveur toujours à l'heure est important pour la sécurité. En particulier cela est essentiel pour les certificats TLS, la connexion par TOTP ou encore l’horodatage d’évènements enregistrés dans les journaux système.
On va s'assurer que le serveur est toujours à la bonne heure en le synchronisant avec un serveur NTP (lui même relier à une horloge atomique). Pour cela on va utiliser l'outil timedatectl
fourni par systemd. Pour plus d'information voir cette documentation.
On commence par installer le paquet systemd-timesyncd
.
apt install systemd-timesyncd
Les NOUVEAUX paquets suivants seront installés :
systemd-timesyncd
On définit ensuite les serveurs NTP à utiliser.
nano /etc/systemd/timesyncd.conf
[Time]
NTP=0.fr.pool.ntp.org 1.fr.pool.ntp.org 2.fr.pool.ntp.org 3.fr.pool.ntp.org
FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
On définit ensuite la zone géographique sur laquelle on se base pour l'heure de notre serveur (c'est notamment utile pour les changements d'heure) et on active la synchronisation.
timedatectl set-timezone Europe/Paris
timedatectl set-ntp true
On redémarre alors le service systemd-timesyncd
pour prendre en compte les modifications et on peut vérifie que tout est bon.
systemctl restart systemd-timesyncd
systemctl status systemd-timesyncd
timedatectl status
timedatectl timesync-status
La commande systemctl status systemd-timesyncd
permet de vérifier que le service est bien lancé, la commande timedatectl status
permet de vérifier que la synchronisation est bien active et qu'on est bien sur la bone zone géographique et timedatectl timesync-status
permet notamment de voir à quel serveur NTP on est connecté.
Étape 4 : Gestion de l'utilisateur administrateur et de sudo
Gérer son serveur directement avec le compte root
est déconseillé en terme de sécurité (voir [ANSSI R33]). Pour cela on va créer un utilisateur administrateur aliceadmin
qui pourra lancer des commandes nécessitant les privilèges administrateur via sudo
. Cela a deux avantages : devoir entrer un mot de passe pour lancer des commandes nécessitant les privilèges de root
et toutes les commandes lancées via sudo
sont journalisées.
On commence par créer le nouvel utilisateur aliceadmin
. On peut, sans trop de soucis, choisir un mot de passe assez facile à retenir. En effet on n'utilisera pas ce mot de passe pour se connecter au compte aliceadmin
car on utilisera une clef ssh. On peut laisser vide les champs d'information (Name, Phone, ...).
adduser aliceadmin
Adding user `aliceadmin' ...
Adding new group `aliceadmin' (1000) ...
Adding new user `aliceadmin' (1000) with group `aliceadmin (1000)' ...
Creating home directory `/home/aliceadmin' ...
Copying files from `/etc/skel' ...
Nouveau mot de passe :
Retapez le nouveau mot de passe :
passwd : mot de passe mis à jour avec succès
Modifier les informations associées à un utilisateur pour aliceadmin
Entrer la nouvelle valeur, ou appuyer sur ENTER pour la valeur par défaut
NOM []:
Numéro de chambre []:
Téléphone professionnel []:
Téléphone personnel []:
Autre []:
Is the information correct? [Y/n] Y
Adding new user `aliceadmin' to supplemental / extra groups `users' ...
Adding user `aliceadmin' to group `users' ...
On installe ensuite sudo
que l'on configure avec la commande visudo
. Il faut rajouter dans le fichier la ligne aliceadmin ALL=(ALL) ALL
pour autoriser l'utilisateur aliceadmin
à acceder à toutes les commandes root. Pour plus d'informations voir ici.
apt install sudo
visudo
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults use_pty
# User privilege specification
root ALL=(ALL:ALL) ALL
aliceadmin ALL=(ALL:ALL) ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
@includedir /etc/sudoers.d
On passe sur le compte de aliceadmin
et on verrouiller le mot de passe du compte root afin qu'on ne puisse plus s'y connecter directement.
su aliceadmin
sudo usermod -L -e 1 root
sudo usermod -s /bin/false root
Étape 5 : Gestion des clefs SSH
Le but de cette partie est de mettre en place l'authentification SSH par clef. Cela a pour avantage de diminuer drastiquement le risque de piratage par force brute car la longueur des clefs est par défaut très longue.
On commence par supprimer toutes les clefs du serveur, générées lors de l'installation de openssh-server
, pour régénérer une clef RSA 4096 et une clef ED25519 avec l'outil ssh-keygen
. Voir le manuel.
sudo rm /etc/ssh/ssh_host_*
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
Et on en profite pour supprimer les trop petits nombres premiers, de taille inférieur à 2048 bits, du fichier /etc/ssh/moduli
.
awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.safe > /dev/null
sudo mv /etc/ssh/moduli.safe /etc/ssh/moduli
On passa ensuite sur la machine locale avec laquelle on se connectera au serveur. On fait le choix ici d'utiliser une clef pour l'algorithme ECDSA sur la courbe elliptique Curve25519.
mkdir ~/.ssh/webalice/
ssh-keygen -a 128 -t ed25519 -f ~/.ssh/webalice/aliceadmin-ed25519
ssh-keygen -f "/home/alice/.ssh/known_hosts" -R "10.11.12.13"
ssh-copy-id -i ~/.ssh/webalice/aliceadmin-ed25519.pub aliceadmin@10.11.12.13
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alice/.ssh/webalice/aliceadmin-ed25519.pub"
The authenticity of host '10.11.12.13 (10.11.12.13)' can't be established.
ED25519 key fingerprint is SHA256:uR+W9GKXuV/5g+1f8W6aiwW5IKuYA6tnbK/mCoId3i0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
aliceadmin@10.11.12.13's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'aliceadmin@10.11.12.13'"
and check to make sure that only the key(s) you wanted were added.
La deuxième commande permet de générer un couple de clefs (une clef publique et une clef privée) ECDSA
sur la courbe elliptique Curve25519
. Le paramètre -a 128
signifie qu'on décide de chiffrer la clef privée (avec 128 tours de passe KDF) avec un mot de passe de sorte que sans ce mot de passe il soit impossible de se connecter au serveur. Cela a pour but d’empêcher quelqu'un qui déroberait le fichier de la clé privée sur notre disque puisse acceder au serveur sans le mot de passe. C'est une option facultative que l'on peut enlever.
Après l'execution de la deuxième commande, deux fichiers webaliceadmin-ed25519
et webaliceadmin-ed25519.pub
ont été créés dans le répertoire ~/.ssh/vps/
: il s'agit de la clef privée (chiffrée) et de la clef publique. On envoie alors la clef publique au serveur avec la troisième commande pour qu'on puisse se connecter au compte aliceadmin
avec la clef privée. Pour cela il faudra entrer le mot de passe de aliceadmin
choisi lors de l'étape précédente.
On se connecte maintenant au serveur en utilisant la clef avec la commande suivant et en utilisant le mot de passe de la clef si on a décidé de chiffré la clef privée :
ssh -i ~/.ssh/webalice/aliceadmin-ed25519 aliceadmin@10.11.12.13
Étape 6 : Configuration et sécurisation de la connection SSH
On cherche dans cette partie et la suivante à configurer et sécuriser la connection SSH. Pour cela on va suivre les recommandations pour un usage sécurisé d’(Open)SSH de l'ANSSI et le guide de Mozilla.
On édite le fichier de configuration du serveur SSH.
sudo nano /etc/ssh/sshd_config
Port 32
# ANSSI R26 | Default : Port 22
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
PermitRootLogin no
# ANSSI R21 | Default : PermitRootLogin prohibit-password
StrictModes yes
# ANSSI | Default : StrictModes yes
PubkeyAuthentication yes
# Default : PubkeyAuthentication yes
PasswordAuthentication no
# Default : PasswordAuthentication yes
KbdInteractiveAuthentication yes
# Default : KbdInteractiveAuthentication yes
UsePAM yes
AllowAgentForwarding no
# Default : AllowAgentForwarding yes
AllowTcpForwarding no
# ANSSI R27 | Default : AllowTcpForwarding yes
AllowStreamLocalForwarding no
# Default : AllowStreamLocalForwarding yes
X11Forwarding no
# ANSSI R28 | Default : X11Forwarding no
PrintMotd no
# Default : PrintMotd yes
PrintLastLog yes
# ANSSI R21 | Default : PrintLastLog yes
PermitUserEnvironment no
# ANSSI R26 | Default : PermitUserEnvironment no
AcceptEnv LANG LC_*
Subsystem sftp internal-sftp
# Default : Subsystem sftp /usr/lib/openssh/sftp-server
KexAlgorithms curve25519-sha256@libssh.org,curve25519-sha256,diffie-hellman-group-exchange-sha256
# Default : KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# Default : HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# Default : Ciphers chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
# Default : MACs umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
AllowUsers aliceadmin
# ANSSI R22
Pour valider les changement, on relance le service SSH. Pour vérifier que la nouvelle configuration fonctionne bien, on peut quitter la connection actuelle et essayer de se reconnecter.
sudo systemctl reload sshd
exit
On n'oublie pas d'indiquer qu'on se connecte maintenant au port 32
.
ssh -i ~/.ssh/webalice/aliceadmin-ed25519 -p 32 aliceadmin@10.11.12.13
Étape 7 (fac) : Connection SSH par double authentification
On peut améliorer la sécurité de la connection SSH au compte aliceadmin
en ajoutant une double authentification comme cela est fait sur certain site. Il sera alors nécessaire d'avoir une application sur un deuxième appareil (souvent un smartphone) qui générera un code temporaire toutes les 30 secondes. Il faudra donner ce code en plus de la clef privée pour se connecter au serveur. Sur smartphone on pourra utiliser l'application Aegis.
On installe pour cela le module PAM libpam-google-authenticator
qui contient le module PAM Google Authenticator. Contrairement à ce qu'on pourrait croire ce logiciel n'utilise aucun "service Google" et n'envoie aucune donnée à Google. Il s'agit d'un logiciel totalement libre qui permet la double authentification par la génération d'un mot de passe à usage unique basé sur le temps (TOTP).
sudo apt install libpam-google-authenticator
Les NOUVEAUX paquets suivants seront installés :
libpam-google-authenticator libqrencode4
On commence par créer la clef secrète permettant d'initialiser le TOPT en lançant google-authenticator
.
google-authenticator
Do you want authentication tokens to be time-based (y/n) y
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
Your new secret key is: 3PWWW6ZKB7JL7S4IJD5FEZNSGQ
Enter code from app (-1 to skip): 381176
Code confirmed
Your emergency scratch codes are:
41715015
47330205
15559260
82868672
86538443
Do you want me to update your "/home/aliceadmin/.google_authenticator" file? (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) n
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) y
On répond oui
à la première question. Le système va alors générer une clef secrète qui vous permettra de configurer votre application OTP. Il suffit pour cela de scanner le QR code via l'application OPT. Il faut penser à stocker dans un endroit sûr les 5 codes de secours, sous peine d'être enfermé dehors si le générateur d'OTP devait faire défaut.
On répond ensuite oui
, oui
, non
et oui
aux questions. Pour plus d'info voir le github.
Il faut ensuite configurer PAM pour prendre en compte la double authentification lors de la connexion SSH.
sudo nano /etc/pam.d/sshd
Il faut commenter la ligne contenant @include common-auth
et la remplacer par auth required pam_google_authenticator.so nullok
de sorte à avoir un début de fichier ressemblant à :
# PAM configuration for the Secure Shell service
# Standard Un*x authentication.
#@include common-auth
auth required pam_google_authenticator.so nullok
# Disallow non-root logins when /etc/nologin exists.
account required pam_nologin.so
[...]
Il faut alors modifier le fichier de configuration de ssh
pour qu'il prenne en compte la double authentification.
sudo nano /etc/ssh/sshd_config
Il faut rajouter à la toute fin du fichier les lignes suivantes :
[...]
Match User aliceadmin
AuthenticationMethods publickey,keyboard-interactive:pam
La double authentification est maintenant configurée. Il n'y a plus qu'à recharger le service sshd
pour que les changements soient pris en compte. On peut alors se déconnecter avec exit
et tenter de se reconnecter. Cette fois-ci il faudra donner le code OPT pour pouvoir acceder au serveur.
sudo systemctl reload sshd
exit
ssh -i ~/.ssh/webalice/aliceadmin-ed25519 -p 32 aliceadmin@10.11.12.13
ssh -i ~/.ssh/webalice/aliceadmin-ed25519 -p 32 aliceadmin@10.11.12.13
Enter passphrase for key '/home/alice/.ssh/vps/serveradmin-ed25519':
Verification code:
Étape 8 : Configuration du pare-feu
Debian 10 a introduit nftables
un nouvel outil pour configurer le pare-feu qui remplace iptables
. Il permet une gestion plus fine des règles de filtrage. Il permet notamment de créer nativement des "Blacklist" (pouvant remplacer fail2ban) et faire du "port-knocking" sans avoir à installer de logiciel tiers.
Voici quelques références expliquant le fonctionnement de nftables
: le wiki officiel, le Bulletin d'actualité du CERT-FR et le wiki de Archlinux.
On commence par installer le paquet nftables
.
sudo apt install nftables
Paquets suggérés :
firewalld
Paquets recommandés :
netbase
Les NOUVEAUX paquets suivants seront installés :
libjansson4 libnftables1 libnftnl11 nftables
Pour fonctionner nftables
a besoin de charger des modules du noyau. Or à l'étape 1 on empêche le chargement de tels modules. Il faut donc ajouter les modules à charger dans /etc/modules
.
sudo nano /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.
nf_tables
nft_ct
nft_limit
nft_log
nf_log_syslog
Il faut alors redémarrer le serveur pour que nftables soit opérationnel.
sudo reboot
On édite alors les règles de filtrage du pare-feu dans le fichier /etc/nftables.conf
. Ici on propose un exemple simple de configuration :
- On refuse par défaut tout traffic entrant et on accepte au cas par cas quelques exceptions.
- On accepte les connections déjà établies.
- On bannit pour 6 heures toutes les ip qui envoie plus de 1000 paquets TCP en moins d'une heure sur un port autre que 80 et 443 (http et https).
- On bannit pour 30 minutes toutes les ip qui ouvrent plus de 100 connections invalides en moins d'une heure.
- On bannit pour 15 minutes toutes les ip qui envoie un paquet non
SYN
lors de l'ouverture de la connection TCP. - On bannit pour 6 heures toutes les ip qui envoie plus de 1000 paquets UDP en moins d'une heure.
- On limite à 10 paquets "ping" par seconde
- On bannit pour 30 minutes toutes les ip utilisant un autre protocole que TCP UDP et ICMP.
- On autorise les nouvelle connections sur les ports 80 et 443 (http et https).
- On décide de mettre en place un "port-knocking" pour cacher le port de ssh (c'est une sécurité supplémentaire pour la connexion SSH). Le principe est simple : on ferme de base le port de ssh et on ne l'ouvre que pour une ip qui aura envoyée des paquets sur 4 ports qu'on aura choisi en amont (et arbitrairement). Pour filer la métaphore si une IP ne fait pas le bon "toc toc toc toc" alors le port de SSH ne s'ouvrira pas. Et a priori, à part nous, personne ne connaît les bon port sur lesquels "taper" car ils sont tous fermés par le pare-feu. A noter quand même que cette mesure n'est pas si forte que ça contre un adversaire pouvant écouter le réseau. En effet si l'adversaire peut écouter à l'entré du serveur il déterminera facilement, quand on se connectera, quelle est la séquence d'ouverture du port ssh. Cependant c'est une technique très efficace contre les bots qui testent tous les ports. Pour plus d'information voir ici et pour avoir des exemples avec
nftables
voir là.
sudo nano /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
# Port-Knocking : 1111:tcp,2222:udp,3333:tcp,4444:udp
define port1 = 1111
define port2 = 2222
define port3 = 3333
define port4 = 4444
# SSH Port
define sshport = 32
chain input {
type filter hook input priority 0; policy drop;
# Allow established/related connections
ct state {established, related} accept
# Allow from loopback
iifname lo accept
# BlackList IP
ip saddr @blackhole drop
# FLOODING simple blacklist
tcp dport != @tcpaccepted meter flood { ip saddr timeout 1h limit rate over 1000/hour } add @blackhole { ip saddr timeout 6h } log prefix "NFT_LOG : FLOOD : " drop
# Drop invalid connections
ct state invalid tcp dport @tcpaccepted drop
ct state invalid meter invalid { ip saddr timeout 1h limit rate over 100/hour } add @blackhole { ip saddr timeout 30m } log prefix "NFT_LOG : INVALID CONNECTION : " drop
# If the connection is NEW and flag is not SYN then drop
tcp flags != syn meter suspicious { ip saddr timeout 1h limit rate over 50/hour } add @blackhole { ip saddr timeout 15m } log prefix "NFT_LOG : NOTSYN : " drop
# UDP
ip protocol udp meter udpflood { ip saddr timeout 1h limit rate over 1000/hour } add @blackhole { ip saddr timeout 6h } log prefix "NFT_LOG : UDP : " drop
# ICPM with ping limitation
ip protocol icmp icmp type echo-request limit rate 10/second accept
# Other protocol
ip protocol != { tcp, udp, icmp } meter proto { ip saddr timeout 1h limit rate over 30/hour } add @blackhole { ip saddr timeout 30m } log prefix "NFT_LOG : OTHER PROTO : " drop
# Allow accepted tcp port
tcp dport @tcpaccepted tcp flags syn ct state new accept
# Port-Knocking to ssh
jump PortKnock
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
# Blacklist of ip
set blackhole {
type ipv4_addr;
flags timeout;
}
# tcp and udp accepted port
set tcpaccepted {
type inet_service;
elements = { 80, 443 }
}
# Port knocking
set Knocked_1 {
type ipv4_addr
flags timeout
timeout 10s
}
set Knocked_2 {
type ipv4_addr
flags timeout
timeout 10s
}
set Knocked_3 {
type ipv4_addr
flags timeout
timeout 10s
}
set Knocked_accept {
type ipv4_addr
flags timeout
timeout 5m
}
chain Lock {
add @blackhole { ip saddr timeout 10s }
}
chain Knock_1 {
add @Knocked_1 { ip saddr }
}
chain Knock_2 {
add @Knocked_2 { ip saddr }
}
chain Knock_3 {
add @Knocked_3 { ip saddr }
}
chain Knock_a {
add @Knocked_accept { ip saddr } log prefix "NFT_LOG : Port-Knock accepted : "
}
chain PortKnock {
# Allow accepted connection by portknocking
ip saddr @Knocked_accept tcp dport $sshport accept
udp dport $port4 ct state new ip saddr @Knocked_3 goto Knock_a
tcp dport $port3 ct state new ip saddr @Knocked_3 return
ip saddr @Knocked_3 ct state new goto Lock
tcp dport $port3 ct state new ip saddr @Knocked_2 goto Knock_3
udp dport $port2 ct state new ip saddr @Knocked_2 return
ip saddr @Knocked_2 ct state new goto Lock
udp dport $port2 ct state new ip saddr @Knocked_1 goto Knock_2
tcp dport $port1 ct state new ip saddr @Knocked_1 return
ip saddr @Knocked_1 ct state new goto Lock
tcp dport $port1 ct state new goto Knock_1
}
}
Il faut maintenant démarrer le pare-feu et vérifier qu'il fonctionne.
sudo systemctl start nftables
sudo systemctl status nftables
sudo nft list table inet filter
A ce stade là, si vous avez fait des modifications et que vous n'êtes pas sûrs de vos règles, je recommande d'ouvrir un nouveau terminal et de tenter de vous connecter au serveur. [...]
Maintenant pour se connecter à ssh il faut faire la bonne séquence de "port-knocking". On utilise alors le petit logiciel knock
qu'il faut installer sur la machine locale utiliser comme suit :
sudo apt install knockd
knock -d 100 10.11.12.13 1111:tcp 2222:udp 3333:tcp 4444:udp && ssh -i ~/.ssh/webalice/aliceadmin-ed25519 -p 32 aliceadmin@10.11.12.13
A noter que maintenant sans faire knock -d 100 10.11.12.13 1111:tcp 2222:udp 3333:tcp 4444:udp
vous ne pouvez plus acceder au serveur via SSH car le port est fermé. Le fait de faire knock -d 100 10.11.12.13 1111:tcp 2222:udp 3333:tcp 4444:udp
permet d'ouvrir le port SSH pour une durée de 5 min pour l'IP qui fait la requête.
Maintenant que tout bon on peut activer par défaut le pare-feu à chaque démarrage du serveur.
sudo systemctl enable nftables
En cas d'erreur de configuration du pare-feu il est possible que le serveur devienne inaccessible (même après redémarrage. Il faudra alors démarrer en mode rescue, modifier le fichier /etc/nftables.conf
et redémarrer le serveur.
Dans la configuration proposée de nftables on journalise un certain nombre d'opération, par exemple les bannissements d'IP. Pour voir les logs de nftables on utilise
sudo journalctl | grep "NFT"
et on peut voir la liste des ip dans la blacklist avec la commande
sudo nft list table inet filter
Étape 9 : Chiffrement de la partition de stockage
Commençons rappeler l'organisation du disque du serveur.
sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1
├─sda2 ext4 1.0 67ffeaa3-6a24-4973-9492-d84b3ed33e98
├─sda3 ext4 1.0 4d1f2b87-fdde-4dd0-b1e2-b79ea2b5d6e7 2,7G 0% /
├─sda4 ext4 1.0 eaa44e06-26ea-4ced-a0b8-0e7ed13dfaa8 2,4G 9% /var
├─sda5 ext4 1.0 0f76eb85-394f-47c2-a8db-515eba6859cd 9,2G 1% /var/log
├─sda6 ext4 1.0 d675f6af-6b1b-46f3-b200-9cb8be4fc2ac 3,7G 14% /usr
├─sda7 ext4 1.0 6dcb5bb2-af3e-417a-9bbf-bcf6dfd4eea0 1,9G 0% /opt
├─sda8 ext4 1.0 1a77e46b-5838-499d-a4f5-7c95a357d594 9,6G 0% /home
├─sda9 swap 1 4464a211-350f-460d-889f-0466468a66b6 [SWAP]
└─sda10
L'objectif de cette partie est de chiffrer la partition /dev/sda10
. Pour cela on va utiliser le logiciel cryptsetup
pour créer une partition LUKS
. Pour plus d'informations voir ici. On commence par installer le logiciel.
sudo apt install cryptsetup
Paquets suggérés :
cryptsetup-initramfs dosfstools keyutils liblocale-gettext-perl
Les NOUVEAUX paquets suivants seront installés :
cryptsetup cryptsetup-bin libpopt0
Il faut également autoriser des modules noyau pour le bon fonctionnement de cryptsetup
. On rajoute à la suite de /etc/modules
.
sudo nano /etc/modules
[...]
algif_skcipher
aesni_intel
xts
dm_crypt
Il faut alors redémarrer le serveur pour que nftables soit opérationnel.
sudo reboot
On décide ici de partir sur un bon compromis sécurité/performance en choisissant de chiffrer en aes-xts 256
ce qui équivaut en fait à un niveau de sécurité de AES en 128 bits. Pour la fonction de dérivation de clé on choisit l'algorithme Argon2id. Attention suivant la valeur du paramètre --pbkdf-force-iterations
et la puissance du serveur cela peut prendre beaucoup de temps.
sudo cryptsetup --type luks2 --cipher aes-xts-plain64 --key-size 256 --hash sha512 --pbkdf argon2id --pbkdf-force-iterations 5 --pbkdf-memory 1048576 --pbkdf-parallel 4 luksFormat /dev/sda10
Il faut taper YES
puis choisir un bon mot de passe.
On peut vérifier les métadonnées de la partition LUKS
et sauvegarder ces métadonnées avec les commandes
sudo cryptsetup luksDump /dev/sda10
sudo cryptsetup luksHeaderBackup /dev/sda10 --header-backup-file luks-header-server.img
On récupérera plus tard le fichier luks-header-server.img
qu'on sauvegardera localement.
On déchiffre la partition /dev/sda10
puis on la formate en ext4
.
sudo cryptsetup luksOpen /dev/sda10 hdcrypt
sudo mkfs.ext4 -m 1 /dev/mapper/hdcrypt
On monte alors cette partition sur /home/crypt
.
sudo mkdir /home/crypt
sudo mount -o rw,nosuid,nodev,noexec /dev/mapper/hdcrypt /home/crypt
On peut créer le script suivant permettant d'automatiser le déchiffrement puis le montage de la partition chiffrée. Il faudra l'exécuter à chaque démarrage du serveur pour pouvoir acceder au données chiffrée. Puisqu'il faudra le mot de passe pour le déchiffrement il est inutile de lancer automatiquement ce script.
sudo nano /root/decrypt.sh
#!/bin/bash
cryptsetup luksOpen /dev/sda10 hdcrypt
mount -o rw,nosuid,nodev,noexec /dev/mapper/hdcrypt /home/crypt
sudo chmod +x /root/decrypt.sh
Étape 10 : Configuration SshFS
On va dans cette partie configurer SSH afin de pouvoir monter un espace de stockage à l'aide de sshfs
. Pour plus de détails voir ici et là.
On souhaite créer des utilisateurs qui pourront acceder au serveur de stockage. Pour cela, puisqu'on a fait expirer le compte root
on doit modifier le fichier /etc/pam.d/chfn
pour autoriser la création du nom complet et des informations associées à l'utilisateur. Il faut ajouter la ligne account sufficient pam_rootok.so
.
sudo nano /etc/pam.d/chfn
#
# The PAM configuration file for the Shadow `chfn' service
#
# This allows root to change user infomation without being
# prompted for a password
auth sufficient pam_rootok.so
account sufficient pam_rootok.so
[...]
On crée ensuite les utilisateurs qui pourront acceder au serveur de stockage. Disons qu'on a deux utilisateurs : bob-data
et carol-data
. On rajoute l'utilisatrice aliceweb
qui gérera l'espace pour les sites web. On peut choisir un mot de passe temporaire fort qui ne sera pas utilisé pour l'accès à l'espace de stockage. Ensuite on empêche l'accès à ces compte par mot de passe.
sudo adduser bob-data
sudo adduser carol-data
sudo adduser aliceweb
sudo usermod -L -s /usr/sbin/nologin bob-data
sudo usermod -L -s /usr/sbin/nologin carol-data
sudo usermod -L -s /usr/sbin/nologin aliceweb
On créer un dossier pour chaque utilisateur sur la partition chiffrée et on restreint l'accès à ces dossier.
sudo mkdir -p /home/crypt/bob/data
sudo chown bob-data:bob-data /home/crypt/bob/data
sudo chmod 755 /home/crypt/bob/data
sudo mkdir -p /home/crypt/carol/data
sudo chown carol-data:carol-data /home/crypt/carol/data
sudo chmod 755 /home/crypt/carol/data
On créer aussi un dossier dans lequel on mettra les sites web. On gérera cet espace dans une prochaine partie mais on ne souhaite pas que ces données soient sur la partition chiffrée. En effet en cas de redémarrage du serveur on veut que les sites web soient accessibles sans avoir à déchiffrer la partition chiffrée.
sudo mkdir /home/www
On souhaite que les utilisateurs bob-data
, carol-data
et aliceweb
se connectent à SSH avec une clef mais uniquement pour acceder au documents de leur dossier respectif. On les empêche aussi d'acceder à un terminal car ils n'ont pas à lancer de commande. Pour cela on édite le fichier /etc/ssh/sshd_config
en modifiant la ligne AllowUsers aliceadmin
et en ajoutant à la fin du fichier les lignes suivantes de sorte à avoir
sudo nano /etc/ssh/sshd_config
[...]
#AllowUsers aliceadmin
AllowUsers aliceadmin aliceweb bob-data carol-data
# ANSSI R22
Match User aliceadmin
AuthenticationMethods publickey,keyboard-interactive:pam
Match User aliceweb
AuthenticationMethods publickey
ForceCommand internal-sftp
ChrootDirectory /home/www
PermitTTY no
Match User bob-data
AuthenticationMethods publickey
ForceCommand internal-sftp
ChrootDirectory /home/crypt/bob
PermitTTY no
Match User carol-data
AuthenticationMethods publickey
ForceCommand internal-sftp
ChrootDirectory /home/crypt/carol
PermitTTY no
On créer maintenant à partir de la machine locale une clef SSH pour chaque utilisateur. On pourra entrer un mot de passe vide.
ssh-keygen -o -t ed25519 -f ~/.ssh/webalice/aliceweb-ed25519
ssh-keygen -o -t ed25519 -f ~/.ssh/webalice/bob-ed25519
ssh-keygen -o -t ed25519 -f ~/.ssh/webalice/carol-ed25519
On décide ici d'installer à la main les clefs SSH sur le serveur plutôt que d'utiliser ssh-copy-id
. Pour cela on créer dans chaque dossier personnel un dossier .ssh
et un fichier authorized_keys
dans lequel on mettra la clef publique précédemment générée. Par exemple pour aliceweb
: on récupère d'abord la clef publique sur la machine locale
cat ~/.ssh/webalice/aliceweb-ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICR4KHdnxyc8VL8Yz9j15Vl9A8yp2Nyj1o9BzoAqLku7 alice@home
Ensuite sur le serveur on fait
sudo mkdir /home/aliceweb/.ssh
sudo nano /home/aliceweb/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICR4KHdnxyc8VL8Yz9j15Vl9A8yp2Nyj1o9BzoAqLku7 alice@home
sudo chown -R aliceweb:aliceweb /home/aliceweb/.ssh
sudo chmod 700 /home/aliceweb/.ssh
sudo chmod 400 /home/aliceweb/.ssh/authorized_keys
Il faut ensuite faire de même pour les autres utilisateurs c'est-à-dire ici pour bob-data
et carol-data
.
On peut alors relancer le service sshd
sudo systemctl reload sshd
On peut désormais se connecter à l'espace de stockage du serveur, par exemple de Bob, avec la commande
knock -d 100 10.11.12.13 1111:tcp 2222:udp 3333:tcp 4444:udp && sshfs bob-data@10.11.12.13:/data /home/alice/pointDeMontage -p 32 -o IdentityFile=~/.ssh/webalice/bob-ed25519
Étape 11 (fac) : Quotas de disques
Afin d'éviter qu'un des utilisateur utilise à lui seul tout l'espace de la partition chiffrée on va mettre en place un système de quota. Pour plus de détails voiri ici. On commence par installer les paquets quota
et quotatool
.
sudo apt install quota quotatool
Paquets suggérés :
libnet-ldap-perl rpcbind default-mta | mail-transport-agent
Paquets recommandés :
libldap-common libsasl2-modules
Les NOUVEAUX paquets suivants seront installés :
libldap-2.5-0 libnl-3-200 libnl-genl-3-200 libsasl2-2 libsasl2-modules-db quota quotatool
Il est nécessaire d'activer le module noyau quota_v2
. Il faut donc l'ajouter au fichier /etc/modules
.
sudo nano /etc/modules
[...]
quota_v2
Puis on redémarre le serveur.
sudo reboot
Il faut ensuite démonter la partition chiffrée pour avec les options de montage permettant la mise en place des quotas. Pour plus d'informations voir ici et le manuel de ext4.
sudo tune2fs -O quota /dev/mapper/hdcrypt
sudo tune2fs -Q usrquota /dev/mapper/hdcrypt
On peut également modifier le script de montage de la partition chiffrée
sudo nano /root/decrypt.sh
#!/bin/bash
cryptsetup luksOpen /dev/sda10 hdcrypt
mount -o rw,nosuid,nodev,noexec,usrquota /dev/mapper/hdcrypt /home/crypt
On créer le fichier de configuration des quota sur la partition chiffré et on active les quotas.
sudo /root/./decrypt.sh
On configure maintenant les quotas par utilisateurs. Pour bob
on lui accorde jusqu'à 10 Gio
(stricte) avec un avertissement à 9 Gio
(souple) et pour carol
on lui accorde jusqu'à 20 Gio
(stricte) avec un avertissement à 15 Gio
(souple).
sudo edquota bob-data
Quotas disque pour user bob-data (uid 1001) :
Système de fichiers blocs souple stricte inodes souple stricte
/dev/mapper/hdcrypt 20 9G 10G 7 0 0
sudo edquota carol-data
Quotas disque pour user carol-data (uid 1002) :
Système de fichiers blocs souple stricte inodes souple stricte
/dev/mapper/hdcrypt 4 15G 20G 1 0 0
On peut aussi configurer le temps qu'on autorise au utilisateur de dépasser les limites souples. Ici j'augmente cette limite à 30 jours.
sudo edquota -t
Sursis avant l'application des limites souples pour users :
Unités de temps peuvent être : days (jours), hours (heures), minutes, ou seconds
Système de fichiers période de sursis bloc période de sursis inode
/dev/mapper/hdcrypt 30days 30days
Pour vérifier les quotas des utilisateurs on peut faire :
sudo repquota -u /home/crypt
*** Rapport pour les quotas user sur le périphérique /dev/mapper/hdcrypt
Période de sursis bloc : 30days ; période de sursis inode : 30days
Block limits File limits
Utilisateur utilisé souple stricte sursis utilisé souple stricte sursis
----------------------------------------------------------------------
root -- 36 0 0 6 0 0
bob-data -- 20 9437184 10485760 7 0 0
carol-data -- 8 15728640 20971520 2 0 0
Étape 12 (fac) : Apparmor
On installe maintenant apparmor
un logiciel de sécurité qui permet d'isoler et de restreindre le pouvoir d'action des applications du système. Plus précisément c'est un modèle d’accès MAC où une autorité décide des accès d’une application sans que celle-ci puisse les altérer. Voir [ANSSI R45] et le cahier de l'administrateur Debian.
sudo apt install apparmor apparmor-utils apparmor-profiles
Paquets suggérés :
apparmor-profiles-extra
Les NOUVEAUX paquets suivants seront installés :
apparmor apparmor-utils apparmor-profiles
Par défaut un certain nombre de profils sont déjà présents dans le répertoire /etc/apparmor.d
. Si on souhaite tous les activer on peut utiliser la commande aa-enforce /etc/apparmor.d/*
. On peut voir les profils actifs avec la commande aa-status
.
sudo aa-enforce /etc/apparmor.d/*
sudo aa-status
Étape 13 (fac) : Résolution DNS
On peut terminer la configuration du réseau en ajoutant un serveur DNS qui permettra de résoudre les noms de domaine Internet en des adresse IP. Cependant un serveur web n'ayant pas usuellement l'utilité de résoudre des noms de domaine (à part peut-être si des scripts utilisent des nom de domaine plutôt que des adresses IP) cette partie est facultative.
On peut choisir le serveur DNS de l’hébergeur ou pour des questions de vie privée on peut choisir des serveurs DNS supposés plus respectueux comme FDN, Quad9 ou CloudFlare.
Pour cela on va installer et configurer systemd-resolved
. Plus d'info ici.
sudo apt install systemd-resolved
sudo nano /etc/systemd/resolved.conf
[Resolve]
# FDN
DNS=80.67.169.12 80.67.169.40
# Quad9
FallbackDNS=9.9.9.9 149.112.112.112
Domains=~
DNSSEC=yes
On termine en relançant le service de systemd-resolved
et en vérifiant que la configuration est bien prise en compte.
sudo systemctl restart systemd-resolved
sudo resolvectl status
Étape 14 (fac) : Sauvegarde de données
Maintenant qu'on accès au serveur de stockage on peut en profiter pour sauvegarde certaines données de la configuration du serveur. Par exemple on peut récupérer les métadonnées de la partition LUKS
précédemment sauvegarder avec la commande cryptsetup luksHeaderBackup
.
sudo mv /home/aliceadmin/luks-header-server.img /home/crypt/bob/data/luks-header-server.img
sudo chown bob-data:bob-data /home/crypt/bob/data/luks-header-server.img