lid's Wiki

EPSI I1: Sécurisation de l'infrastructure

il y a toujours un XKCD sur chaque sujet

Obligations juridiques

En tant que DSI, responsables d'infrastructure, RSSI, administrateur ou technicien systèmes et réseaux, nous sommes tenus de respecter un ensemble d'obligations juridiques telles que:

Notre responsabilité est encadrée par les textes de loi suivants:

S'il est bien connu que l'accès et le maintien frauduleux dans un système d'information fait encourir des peines importantes, il faut aussi rappeler qu'en tant qu'administrateurs systèmes et réseaux nous encourons aussi des peines en cas de défaut de sécurisation des infrastructures sous notre responsabilité: nous sommes tenus d'implémenter toutes les mesures de sécurité possibles dans les limites de nos capacités (techniques, financières, etc).

Cela implique aussi de communiquer rapidement en cas de fuite de données ou de compromission de ces infrastructures, voire, de se mettre en relation avec les services de l'État compétents (ANSSI notamment) en cas de compromission.

De même, il est important de former les utilisateurs du SI aux bonnes pratiques concernant la sécurité des données de l'entreprise, et de ne pas hésiter à effectuer quelques piqûres de rappel à intervalle régulier 😃

Afin d'assurer de bonnes pratiques de sécurité de nos systèmes d'information, il existe tout un ensemble de normes de sécurités et de guides dont l'implémentation permet d'assurer la sécurité du système d'information, telles que:

Que nous détaillerons un peu plus loin dans ce module.

Dès lors, en tant que Responsables d'un Système d'Information, Administrateurs ou Techniciens de ce SI, nous sommes tenus de respecter ces lois, et d'implémenter dans les limitations techniques et financières de nos environnements les systèmes et logiciels permettant le respect de ces lois. Pour cela, il existe plusieurs normes et méthodes permettant de déterminer et d'implémenter les objectifs de sécurité nécessaires.

Afin de pouvoir manipuler un peu (quand même!), nous verrons aussi comment:

Les différents types d'attaques

Nous l'avons déjà vu les années précédentes, donc je ne vais pas vous faire une répétition de ce que nous avions vu les années précédentes, mais pour rappel, il existe tout un ensemble d'attaques du système d'information qui peuvent être de différents types:

Les attaques matérielles

Il faut bien évidemment s'assurer que le matériel sensible soit stocké et utilisé de manière sécurisée (cf sécurité en Datacenter). Idéalement, la chaîne d'approvisionnement en matériel doit être sûre et vérifiable (Traçabilité du matériel).

En effet, vous pouvez avoir construit la meilleure forteresse "logique" (logicielle), si le matériel est accessible derrière une porte en carton, ou si un des fabriquants est compromis (firmwares "vérolés", backdoors étatiques ou interface de management à distance (pour le "support") dissimulées et exploitables, composants électroniques faisant "un peu plus" que ce qu'ils sont censés faire sur le papier, systèmes embarqués "téléphonant à la maison", "puces de sécurité" (TPM anyone?) présentant des failles de sécurité, etc), vos données sont en danger 😃.

Il peut être plus simple d'aller cambrioler une salle informatique mal sécurisée et repartir avec les disques durs non chiffrés que d'essayer d'exploiter une faille logicielle ou une mauvaise configuration réseau. (donc: chiffrez dans la mesure du possible!)

Virus, trojans, intrusions, phishing, ransomwares, etc

Les menaces liées aux appareils mobiles

BYOD, ou BYOV?

Bring Your Own Device, ou Bring Your Own Vulnerabilities?

Plus sérieusement, le matériel appartenant aux utilisateurs du SI et n'étant pas la propriété de l'entreprise doit être isolé du réseau de l'entreprise afin de limiter les risques de compromission. Idéalement ce matériel, s'il est autorisé à se connecter à Internet via le réseau de l'entreprise, doit être isolé sur des réseaux sans fils dédiés, eux mêmes isolés dans des VLANs dédiés. Des logiciels comme PacketFence ou autre NAC (logiciel de contrôle d'accès réseau) permettent de reconnaître et isoler le matériel ne faisant pas partie de l'entreprise dans des réseaux spécifiques séparés du/des réseau(x) vitaux de l'entreprise. Ils peuvent aussi détecter des appareils au comportement anormal et les isoler dans des VLANs spécifiques, et fournir par exemple un réseau wifi invité aux utilisateurs externes à l'entreprise.

MDM

Pour la gestion de la flotte mobile, il peut être intéressant d'implémenter une solution de MDM (Mobile Device Management), afin d'éviter que nos chers utilisateurs installent n'importe quelle application (et potentiellement des applications malveillantes) sur les appareils de la flotte mobile de l'entreprise.

IoT

De la même manière, les équipements de type Internet of Things doivent être isolés du réseau de l'entreprise, voire, ne pas avoir accès à Internet tout court pour éviter de potentielles fuites de données, ces équipements ayant une fâcheuse tendance à "téléphoner à la maison", c'est à dire contacter à intervalle régulier le site du constructeur. On peut notamment citer les caméras IP qui ont souvent des comportements anormaux ou des configurations "en dur" (serveurs DNS notamment), dont le micrologiciel peut rapidement devenir obsolète (pas de mise à jour, pas de support, etc) et sont parfois originaires de pays peu regardants sur les problématiques de vie privée, d'espionnage, de démocratie et des droits de l'Homme, et donc constituent un risque potentiel dès leur entrée en fonction. Il est donc nécessaire de les isoler des réseaux vitaux de l'entreprise afin d'éviter toute compromission ou fuite de données.

Méthodologie

Normes ISO 27000

L'ensemble des normes ISO 27000 définit les normes et les bonnes pratiques de la sécurité des systèmes d'information. Elles sont souvent mises à jour, il faut donc bien effectuer sa veille technologique concernant cet ensemble de normes. On peut citer, notamment:

MEHARI

La MÉthode Harmonisée d'Analyse des RIsques a été développée à la fois en France et au Canada. C'est une méthode de gestion des risques répondant à la norme ISO 27002 et 27005, et qui fournit une base de connaissances et de bonnes pratiques permettant l'évaluation et la gestion des risques en fonction de la taille de l'organisme ciblé:

EBIOS

La méthode EBIOS (Expression des Besoins et Identification des Objectifs de Sécurité) est principalement utilisée dans le secteur public, mais aussi dans le secteur privé. Elle propose une démarche relativement simple, dans le but de construire une politique de sécurité en fonction de l'analyse des risques. Elle se base sur trois activités:

À cela viennent s'ajouter quatre étapes supplémentaires, une fois le contexte correctement déterminé:

Cette méthode, si elle a l'avantage d'être claire, exhaustive et universelle, a le défaut de ne pas fournir de recommandation ni de solution. Elle doit donc être complétée par d'autres méthodes afin d'atteindre les objectifs de sécurité fixés.

Identification des utilisateurs

Méthodes d'authentification

IdP: Identity Providers

Un fournisseur d'identité, Identity Provider, permet de centraliser l'authentification de nos utilisateurs, en fournissant en général des options d'authentification plus fortes que celles fournies par les systèmes d'authentification internes de nos différents applicatifs. Pour les utilisateurs du SI, un IdP apporte aussi un confort d'utilisation non négligeable grâce au SSO (Single Sign-On). La plupart de ces fournisseurs d'identité permettent:

Il existe plusieurs systèmes d'authentification des utilisateurs: OIDC, SAML, LDAP/AD, OAuth (pour utiliser un fournisseur d'identité externe tel que Google, Microsoft, Github, etc). Comme vous avez un module en Janvier avec M. Sébastien Baule sur le sujet (il vous fera découvrir Keycloak notamment) je ne vais pas trop m'étendre sur le sujet 😃

OAuth 2

Oauth est un protocole de délégation d'autorisation, qui permet à un site, une application, etc, d'interroger un site tiers pour valider l'identité d'un utilisateur.

Le protocole a été défini par Blaine Cook et Chris Messina (de Twitter) en 2006 et finalisé en 2007. Sa version 2, Oauth 2.0, est sortie en octobre 2012 (RFC 6749 et 6750).

Il est notamment utilisé par OpenID Connect, dont nous allons parler juste après 😃

OAuth fonctionne sur un principe de 4 échanges:

OAuth2 part du principe que la machine du client est peu sûre, et donc, ne transmet pas d'informations sur les ressources de l'utilisateur, il récupère juste un token d'identification idéalement temporaire. De plus, les tokens peuvent être signés par le serveur d'autorisation.

OIDC

OIDC, pour Open ID Connect, se base sur OAuth 2.0 pour fournir un mécanisme d'authentification de nos utilisateurs. OIDC est géré par la fondation OpenID, et propose une API RESTful utilisant JSON pour fournir les informations d'authentification requises.

Bien que le standard ne spécifie pas la gestion des groupes, différentes implémentations ajoutent ce support (Authentik par exemple). OpenID Connect est utilisé par Google, Microsoft, FranceConnect, Salesforce par exemple.

Les clients (applicatifs Webs, etc) peuvent interroger le serveur OIDC pour vérifier les informations d'authentification fournies par l'utilisateur, et pour obtenir des informations notamment sur l'état de sa session.

Dans le monde du logiciel libre, on peut citer:

Et côté services propriétaires:

En général, un Client OpenID (une application utilisant OIDC pour identifier ses utilisateurs) est défini par un ClientID unique ainsi qu'un ClientSecret lui permettant de s'authentifier auprès du serveur OIDC, là où un utilisateur est authentifié auprès du serveur OIDC par son login, mot de passe, et 2FA, le serveur OpenID lui délivrant un token, et lui indiquant une redirection vers la ressource désirée.

SAML

Security Assertion Markup Language, contrairement à OAuth/OIDC, utilise XML pour fournir les informations d'authentification, là où OIDC utilise JSON. Plus ancien qu'Oauth2 et OIDC, SAML a été développé par OASIS et sa première version est sortie en 2002. La seconde version est elle sortie en 2005, ce qui ne nous rajeunit pas 😃

Son fonctionnement est un peu plus complexe que OAuth2 et OIDC, et se décompose en 8 phases:

Le standard SAML recommande le chiffrement TLS 1.0+ pour le transport des informations mais aussi XML Signature et XML Encryption pour la sécurité des messages. Il répond au besoin DIC (Disponibilité, Intégrité et Confidentialité).

Bien qu'il soit plus ancien qu'OIDC, et que votre serviteur préfère OIDC du fait de son allergie au XML, SAML est encore largement utilisé.

LDAP/AD

Enfin, on ne le présente plus, Lightweight Directory Access Protocol, dont Active Directory se sert, est un protocole d'annuaire permettant d'authentifier des utilisateurs. L'authentification est effectuée par l'opération Bind, mais un utilisateur authentifié et ayant les droits correspondants peut aussi parcourir l'arbre LDAP (dans les limites de ses permissions) et accéder à des informations de type groupes, Unités Organisationnelles, clefs SSH, numéro de téléphone, etc.

Il en existe un grand nombre d'implémentations, libres, ou pas:

(Attention, libre ne veut pas dire gratuit)

Authentification forte

L'authentification forte désigne toute procédure d'identification nécessitant au moins deux facteurs d'authentification différents, et reposant idéalement sur des principes cryptographiques jugés forts. L'ANNSI fait ainsi la distinction entre l'authentification multifacteur seule et l'authentification forte ne nécessitant pas, dans son interprétation, forcément la présence de deux facteurs d'authentification.

En combinant plusieurs facteurs d'authentification différents, on peut ainsi s'assurer plus sûrement de l'identité de l'utilisateur qui désire accéder à nos ressources. Ces facteurs sont généralement classifiés de cette manière:

TOTP

Time based One Time Password est un algorithme de génération de mots de passe à usage unique (typiquement, une suite de six chiffres changeant à intervalle régulier générés à partir d'une "seed" unique par utilisateur) que l'on utilise souvent comme mécanisme de double authentification.

Bien que relativement pratique et efficace, TOTP a quelques inconvénients:

Cependant, c'est une solution relativement fiable et facile à mettre en place.

Implémentations de TOTP:

Clefs physiques (Yubikey, etc)

Il existe aussi plusieurs fabricants de clefs physiques d'authentification, notamment Yubico et ses Yubikeys, qui utilisent en général l'authentification par clef publique et le protocle Universal Second Factor (U2F) développé par l'alliance FIDO (FIDO U2F).

Concernant Yubikey, bien que certains de ses produits soient open source, ce n'est pas le cas pour tous leurs produits, et dès lors il peut être compliqué de s'assurer de la réelle sécurité du produit. De même, en 2017, une faille dans l'implémentation de l'algorithme RSA pouvait conduire à la compromission de secrets contenus dans la clef. Cependant, ce type d'outil reste une des méthodes de double authentification les plus sûres.

Biométrie (sigh)

Les facteurs biométriques peuvent aussi être utilisés pour authentifier un utilisateur, par exemple via une empreinte digitale ou rétinienne, en complément d'un facteur mémoriel par exemple. Cependant, un doigt, ça se coupe… :]

Réseaux sans fils

La protection des réseaux sans fil d'une entreprise ne peut en général pas se contenter d'une simple PSK connue de tous les employés. Il faut donc utiliser des méthodes d'authentification qui, si elles doivent rester relativement transparentes pour les utilisateurs du système d'information, doivent assurer à la fois confidentialité et authentification des utilisateurs lors de leur connexion à ce réseau sans fil.

Norme 802.1X et WPA entreprise

Le protocole 802.1X fournit une couche de sécurité sur les réseaux câblés et sans fil. Il s'appuie sur un serveur d'authentification (RADIUS, TACACS, CAS, etc) et permet de basculer l'état (en général le VLAN) d'un port (physique ou sans fil) réseau afin d'autoriser l'accès au réseau à un utilisateur s'étant correctement authentifié. Ce protocole s'appuie sur le protocole EAP (Extensible Authentication Protocol, 1998) qui n'utilise pas le protocole IP.

Il y a plusieurs implémentations, libres ou pas, du protocole:

Le réseau du campus est un exemple de réseau sans-fil 802.1X (utilisation d'un certificat notamment, et authentification RADIUS).

Chiffrement

Bon, là encore, ce sont des sujets que nous avons déjà abordés les années précédentes, aussi je me contenterai d'un rappel succinct.

Concepts clés

Le but est de s'assurer de:

Chiffrement symétrique

Le chiffrement symétrique signifie que les deux parties disposent d'un secret de chiffrement commun (PreShared Key, PSK, par exemple), qui sera utilisé comme graine de l'algorithme de chiffrement utilisé. Par exemple, un chiffrement OpenSSL AES-256-CBC avec une passphrase est un type de chiffrement symétrique.

Chiffrement asymétrique

Le chiffrement asymétrique, lui, repose sur un système à double clefs: une clef privée (qui doit rester privée), et une clef publique librement partageable.

Imaginons qu'Alice veuille envoyer un message chiffré à Bob, Alice chiffrera alors le message avec la clef publique de Bob, et Bob pourra alors déchiffrer le message grâce à sa clef privée. Inversement, si Bob veut envoyer un message à Alice, il chiffrera le message avec la clef publique d'Alice, qui pourra le déchiffrer grâce à sa clef privée.

Inversement, on peut aussi utiliser le chiffrement asymétrique pour signer un message: on le chiffre alors avec sa clef privée (ou, par exemple dans le cas de DKIM, uniquement les en-têtes du message), dont on est le seul à avoir connaissance, et le récepteur du message le déchiffrera grâce à la clef publique de l'émetteur. Dans ce cas, le message en tant que tel est facile à déchiffrer, cependant on s'assure bien que le message est bien envoyé par la bonne personne.

On peut tout à fait imaginer un mécanisme où nous chiffrons une partie du message (les entêtes par exemple) avec notre clef privée, et le contenu du message avec la clef publique du récepteur, et dès lors on peut envoyer un message dont on s'assure bien que l'expéditeur est bien celui qu'il prétend, tout en conservant la confidentialité du message.

Hashage

Le hachage (hashing), permet, lui, de s'assurer de l'intégrité d'un message (ou fichier). En effet, le hash d'un message, d'un mot de passe ou d'un fichier est théoriquement unique, c'est à dire que deux messages différents ou deux fichiers différents ne peuvent mathématiquement pas produire le même hash. Inversement, le même message ou fichier produira toujours le même hash.

Cependant, suivant l'algorithme de hashage utilisé, des collisions peuvent apparaître, c'est à dire que deux messages, fichiers ou mots de passe peuvent produire le même hash. Dès lors, l'algorithme utilisé est déprécié. On peut citer MD5 et SHA-1 comme exemples d'algorithmes de hashage permettant des attaques par collision.

On utilise généralement SHA-256 et supérieurs comme algorithmes de hashage sans clef. Il existe aussi des algorithmes de hashages cryptographiques avec clef comme MD5, HMAC, etc.

Degré de difficulté des algorithmes de chiffrement

En cryptographie, la difficulté signifie "au-delà de la portée de tout adversaire, aussi longtemps que la sécurité des informations chiffrées est jugée importante".

Dès lors, si l'on désire chiffrer des données sur des durées étendues, il est important de bien choisir les algorithmes de chiffrement utilisés 😃

Chiffrement des disques via LUKS

Si, sous Windows, on utilise Bitlocker pour chiffrer nos disques, un système similaire existe sous GNU/Linux: LUKS (Linux Unified Key Setup). Sous la majorité des distributions GNU/Linux grand public (Debian, Ubuntu, Fedora, PopOS, etc) l'installeur propose directement le chiffrement de la partition root. Il est important par contre de mentionner que la partition /boot ne sera, elle, pas chiffrée. Elle contient l'initramfs (qui contient un ensemble minimaliste d'utilitaires et de drivers permettant au noyau d'initialiser les disques - et donc, ici, de les déchiffrer - et d'amorcer le système), le kernel, etc.

Bien évidemment, si notre machine est un serveur (ou, dans notre cas, une VM), elle sera probablement inaccessible physiquement, et on aura pas forcément toujours accès à une console d'administration (iDRAC, IPMI, ILO, etc). Il faut donc un mécanisme d'accès afin de pouvoir entrer la passphrase de déchiffrement des disques au démarrage. Nous verrons comment ajouter à notre initramfs et comment utiliser dropbear, un serveur SSH minimaliste, pour obtenir une console sécurisée au chargement de l'initramfs nous permettant de déchiffrer nos disques lors du démarrage de la machine.

Attention, cela implique que la HostKey SSH de notre machine sera différente lors du boot que celle utilisée ensuite par OpenSSH une fois la machine démarrée, sauf si l'on prend le temps de les ajouter à l'initramfs.

Installation de Debian avec chiffrement des disques

Lors de l'installation de Debian, nous allons sélectionner l'option "LVM chiffré" à l'étape de paritionnement des disques. Idéalement, on configurera en amont le réseau avec une adresse IP statique mais comme vous travaillez probablement sous Virtualbox ou VMWare, ne vous en souciez pas outre mesure. Lorsque nous configurerons dropbear-initramfs, nous utiliserons comme IP statique l'IP attribuée par le DHCP de votre solution de virtualisation (ou par le DHCP du campus si nous sommes en mode bridgé).

Idéalement, on veut aussi utiliser une passphrase de déchiffrement solide, mais pour notre machine de test, utilisez un mot de passe déchiffrement simple à retenir.

Installation de dropbear dans l'initramfs pour le déchiffrement des disques à distance

Tout d'abord, nous allons installer le paquet dropbear-initramfs sur notre debian fraîchement installée:

sudo apt update && sudo apt dist-upgrade
sudo apt install dropbear-initramfs

Attention, les chemins des fichiers de configuration de dropbear-initramfs ont changé entre Debian Bullseye (11) et Bookworm (12), et suivantes (Debian 13, Trixie, et la future Debian Forky (14)), et de la même façon pour Ubuntu, Pop_OS! et autres dérivés Debian. Consultez la documentation de votre distribution à ce sujet.

Pour Bookworm et Trixie, les fichiers qui vont nous intéresser sont dans:

/etc/dropbear/initramfs

Et pour Bullseye et versions antérieures (mais rassurez-moi, vous n'utilisez pas de versions antérieures à Bullseye, si?):

/etc/dropbear-initramfs/

On va donc se placer dans le répertoire correspondant pour configurer dropbear, et éditer le fichier dropbear.conf (Bookworm, Trixie et ultérieures) ou config (Bullseye) afin de configurer les options de lancement du serveur dropbear SSH:

DROPBEAR_OPTIONS="-I 120 -j -k -p 2222 -s -c cryptroot-unlock"

Les options définies sont:

On va ensuite configurer l'IP statique de notre initramfs, en modifiant le fichier /etc/initramfs-tools/initramfs.conf:

IP=192.168.1.151::192.168.1.254:255.255.255.0:deb-crypt

Ici, on configure donc une IP statique (192.168.1.151 dans mon cas), une passerelle (192.168.1.254), un masque de sous-réseau (/24) et enfin un hostname pour notre session initramfs. Notez les deux "::" entre l'IP et la passerelle, car nous omettons un paramètre intermédiaire (server-ip pour du PXE). On pourrait aussi renseigner un périphérique spécifique (si on a plusieurs interfaces réseau), un serveur DNS, et un serveur NTP en fin de ligne, mais notre but n'est pas d'avoir un Linux minimaliste en RAM, juste de déchiffrer notre disque de démarrage 😃

Il ne nous reste plus qu'à configurer le fichier authorized_keys de notre dropbear en y copiant notre clef publique SSH:

Bookworm et Trixie:

cp /home/user/.ssh/authorized_keys /etc/dropbear/initramfs/authorized_keys

Bullseye:

cp /home/user/.ssh/authorized_keys /etc/dropbear-initramfs/authorized_keys

Et mettre à jour notre initramfs:

sudo update-initramfs -u
# pour plus de verbosité:
sudo update-initramfs -u -v

Reboot, et tester!

Ajout de disque et chiffrement du disque

Bien évidemment, si on ajoute de nouveaux disques à notre machine, on va aussi vouloir les chiffrer! On ajoute un nouveau disque à notre VM (disons, 4Go), et on va le partitionner (via cfdisk, fdisk, etc). Une fois le nouveau disque ajouté:

lsblk
# bien noter l'identifiant du disque, probablement /dev/sdb
sudo cfdisk /dev/sdb
lsblk
# on devrait obtenir une partition /dev/sdb1

On va ensuite chiffrer notre partition:

sudo cryptsetup luksFormat /dev/sdb1

Là aussi, on veut choisir une passphrase de qualité, mais pour notre exemple, utilisez une passphrase simple.

Il ne nous reste plus qu'à créer le système de fichiers:

sudo cryptsetup open /dev/sdb1 mondisque
sudo mkfs.ext4 /dev/mapper/mondisque

Il ne nous reste plus qu'à créer un point de montage pour notre disque, et le monter:

mkdir /mnt/mondisque
mount /dev/mapper/mondisque /mnt/mondisque
# on teste, on démonte et on ferme :)
df -h 
umount /mnt/mondisque
cryptsetup close mondisque

Maintenant, pour monter automatiquement le disque au démarrage, il va falloir que nous modifiions les fichiers /etc/fstab et /etc/crypttab, mais nous voulons aussi éviter de déchiffrer ce nouveau disque au démarrage. Comme notre disque système est déjà chiffré, nous allons créer un fichier contenant la clef de déchiffrement de notre nouveau disque. Ce fichier devra être protégé correctement (permissions, etc).

Créons d'abord un répertoire pour notre fichier clef, et un fichier qui contiendra la clef de notre disque:

sudo mkdir /etc/lukskeys
sudo dd if=/dev/urandom of=/etc/lukskeys/mondisque-key bs=512 count=8 iflag=fullblock
chown root:root /etc/lukskeys/mondisque-key
sudo chmod 400 /etc/lukskeys/mondisque-key

On va ensuite créer notre fichier clef à proprement parler (notre passphrase nous sera demandée, chiffrée, puis placée dans le fichier "mondisque-key" dans notre exemple):

sudo cryptsetup -v luksAddKey /dev/sdb1 /etc/lukskeys/mondisque-key

Enfin, on va pouvoir ajouter notre disque à /etc/crypttab. Pour celà, on va tout d'abord récupérer l'UUID de notre disque chiffré:

sudo cryptsetup luksDump /dev/sdb1 | grep UUID
UUID:           bb57e714-6b09-456c-9e6a-dab7e12c66b2

On va récupérer cette UUID, et ajouter la ligne suivante à /etc/cryptab:

echo "sdb1_crypt UUID=bb57e714-6b09-456c-9e6a-dab7e12c66b2 /etc/lukskeys/mondisque-key luks" | sudo tee -a /etc/crypttab

On vérifie que tout est OK:

sudo cryptdisks_start sdb1_crypt

Il ne nous reste plus qu'à ajouter notre partition chiffrée à fstab, avec un point de montage existant (bien vérifier que le répertoire existe!):

sudo vim /etc/fstab
/dev/mapper/sdb1_crypt /mnt/mondisque ext4 defaults 0 2

On reboote, on déverrouille notre disque système via dropbear, et normalement, TADAAAM 😃

Notez qu'on peut aussi créer un fichier image disque, et le chiffrer de cette manière puis le monter automatiquement (tout est fichier!).

Chiffrement symétrique des données sensibles via OpenSSL

On peut utiliser openssl pour chiffrer symétriquement un fichier, en utilisant une passphrase connue d'Alice et Bob (donc, un secret prépartagé).

Exemple:

openssl aes-256-cbc -a -salt -pbkdf2 -in fichier.txt -out secrets.txt.enc
openssl aes-256-cbc -d -a -pbkdf2 -in secrets.txt.enc -out fichier.txt.dec

Cependant, attention avec ce système:

Chiffrement asymétrique des données sensibles via SSH

On peut utiliser la clef publique de quelqu'un pour chiffrer un message (fichier, etc).

Pour notre test, sur notre VM LUKS, créons un fichier quelconque avec un message dedans, et une clef SSH au format RSA (ça ne fonctionnera pas avec une clef ED25519):

echo "coucou" > monsecret
ssh-keygen -t rsa -b 4096 -f ~/.ssh/clefbob
# On convertit la clef publique au format PEM:
ssh-keygen -f ~/.ssh/clefbob.pub -e -m pem > clefbob.pub.pem
# Chez lui, "Bob" convertit sa clef privée au format RSA:
cp ~/.ssh/clefbob ./clefbobrsa
ssh-keygen -p -m PEM -f ./clefbobrsa

Bien évidemment, on part du principe que Bob n'est pas sur la même machine 😉

On chiffre notre fichier en utilisant la clef publique au format PEM de Bob:

cat monsecret | openssl pkeyutl -encrypt -pubin -inkey ./clefbob.pub.pem > encrypted

Pour le déchiffrer, Bob utilisera la commande suivante:

cat encrypted | openssl pkeyutl -decrypt -inkey clefbobrsa > decrypted

Et voilà 😃

Chiffrement asymétrique des données sensibles via GPG

GPG, Gnu Privacy Guard est l'implémentation par le projet GNU du standard OpenPGP (RFC 4880).

Il permet de garantir:

Sa première version stable est publiée en 1999. Le projet a été créé par Werner Koch.

GPG est principalement utilisé dans la signature et le chiffrement de mails, mais il est capable de chiffrer et signer tout type de fichiers.

Installation de gnupg

Très simple si ce n'est pas déjà installé:

sudo apt install gnupg

Génération de notre couple de clefs

Pour générer notre couple de clefs GPG, au format RSA, nous allons utiliser la commande suivante:

gpg --full-generate-key

Qui va nous produire quelque chose comme ça:

gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: directory '/home/lidstah/.gnupg' created
gpg: keybox '/home/lidstah/.gnupg/pubring.kbx' created
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

Il vous sera ensuite demandé votre identité (réelle ou pseudonymique, hein), adresse mail, etc.

On va utiliser ici des informations "fausses" pour ne pas se retrouver bloqué si on veut, un jour, mettre en place GPG réellement sur un vrai serveur de clefs.

Une passphrase vous sera demandé pour protéger votre clef. Dans la vraie vie, on utilise une passphrase raisonnablement complexe, mais pour notre exemple, utilisons une passphrase simple (mais qui doit contenir au moins un chiffre, et un caractère spécial).

La génération de la clef peut être longue, c'est peut être l'occasion de verrouiller notre session et d'aller se faire un café 😃

On va vérifier les informations de notre clef:

gpg --list-secret-keys --keyid-format=long
# dans mon cas
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/lidstah/.gnupg/pubring.kbx
--------------------------------
sec   rsa4096/B54517686F3AB70D 2024-10-27 [SC]
      83BCB0018D4107C32282BE05B54517686F3AB70D
uid                 [ultimate] lidstah (test key) <lidstah@gmail.com>
ssb   rsa4096/A700BD56C8E83DB5 2024-10-27 [E]

On va ensuite exporter notre clef publique, en récupérant son ID:

gpg --armor --export B54517686F3AB70D
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGceJlABEADGMrlfatt22CEPXgsqDs88FwJbasLfGEnpudXtrLP9UG/oUKm+
i/25WehvIiJkfbRP8eNYHkhjic5ZCsVXld0MQBhiJZjiuYmdn7R1yrAMVKzdotSP
yVedvPLjQWEeKN/bovFiG9sWhCfL12rxN8KcGNp6jgq5NxOfVwv60o5ZY8VXvV/E
scC4fgFp7Ay6t4t6xxPdVJoFEiwspEiaR8j/RWOET9CU3UKyaHr0Pa+DoalF+ypT
Mac0ZpM+ZS7Ba4mYzJ22QjjxLAF44P7I3sAZA8wqEGV7AJWIC7Ax+wugPf0+wOx7
j4asJz64jjKfXKY1LTsG6KSRnlRpZGn/jQlCoo1OnTvSrRgTw7RaQUeGYcAzlpTV
VCLno6yrdvX1km0z/IQfrBCOD4CTrArS/mVWFesYZ+AY2uT1XA6USLKM6Dh2hNrV
[SNIP, c'est long!]
2p/5OKn2SMbfya/UnA5rzMubHx+9NaUztCu//ICl3bAdzG6+G2++jWtzx+f1cwbp
buxwNpERPdBpmmQvUU4rHTM28s+Lo6YJc9m3v3+uwo6c4gh0hOLifG2gNJNY5bGn
ic+T39ZPLB1wLtzmUBOCLminat0q87Xyxhp12+t+XEgselIbuKKPUnVKfjt6bubP
gwm7/vROfeTcAH1NxcDjP4FGc05S0fGN9gQZS2iQXKLGRc9/IWTp7hM4CQbx7GmH
hNhDt+IVi3s3a4JPvYuYC/5XtJcpF4jgSyUEyQtslK1azcAQujZMHRebf/pnbakj
1RiFVyhHjg+mEeGeY9Aj6nNm6YWvhQ7htqL8OIgiW3vN4jKJwzjlP1JGz/eHjpco
hLQ=
=lDZG
-----END PGP PUBLIC KEY BLOCK-----

On va vouloir la copier dans un fichier:

gpg --armor --export B54517686F3AB70D > maclefpublique

On va voir maintenant comment chiffrer un fichier avec GPG. Pour cela, dans la vraie vie, vous ajouterez les clefs publiques des personnes avec qui vous voulez communiquer de façon chiffrée et sécurisée - dans le temps, on organisait des signing parties pour s'échanger nos clef publiques de façon sécurisée, mais de nos jours on utilisera plutôt un serveur de clefs.

N'hésitez donc pas à échanger vos clefs publiques avec vos collègues, mais sinon on va se créer un second utilisateur de notre VM, et lui générer lui aussi un couple de clefs (même procédure que ci-dessus, donc, mais pour notre autre utilisateur, attention, su user ne fonctionnera pas (sauf si on modifie le propriétaire de la tty), donc, configurez le fichier authorized_keys pour votre nouvel utilisateur, ouvrez un nouveau terminal et connectez vous en ssh à votre nouvel utilisateur).

Pour importer la clef publique d'une personne dans votre trousseau:

gpg --import alice.gpg
gpg --list-keys

Mais ce n'est pas tout, on va vouloir signer cette clef pour bien indiquer à GPG que l'on fait confiance à cette clef:

gpg --edit-key alice@alice.com
# fingerprint de la clef, à vérifier avec le propriétaire de la clef
fpr
# on signe la clef:
sign
quit

On effectue cette opération pour nos deux comptes.

chiffrement de fichier permettant le déchiffrement par plusieurs utilisateurs

Maintenant, admettons que j'ai un message à transmettre à mon second utilisateur (alice@alice.com), je vais vouloir le chiffrer via GPG:

echo "coucou" >message.txt
gpg --output message.txt.gpg --encrypt --recipient alice@alice.com message.txt

Alice de son côté pourra déchiffrer mon fichier avec la commande:

gpg --output message.txt --decrypt message.txt.gpg
cat message.txt

Signature d'un fichier via GPG

On peut aussi signer notre fichier chiffré, pour qu'Alice puisse bien vérifier que nous sommes bien la bonne personne:

gpg --output message.txt.gpg.sig --sign message.txt.gpg

Et nous transmettrons cette signature à Alice, qui pourra la vérifier:

gpg --output message.txt.gpg --decrypt message.txt.gpg.sig

Et Alice n'a plus qu'à déchiffrer le message comme décrit précedemment. On a ainsi:

Bien évidemment, on peut chiffrer un message pour plusieurs utilisateurs, et le signer:

gpg --output message.gpg --encrypt --recipient alice@alice.com --recipient bob@bob.com message
gpg --output message.gpg.sig --sign message.gpg

Et hop!

NOTE: il est important de sauvegarder son trousseau (répertoire ~/.gnupg) régulièrement. En effet, si vous perdez ce répertoire, vous perdez vos clefs, votre trousseau, et donc il faudra tout recommencer! Et bien évidemment, il faut chiffrer le backup!

Serveurs de clés, partage de clefs publiques

Bien évidemment, si on devait aller rencontrer physiquement, au hasard, les mainteneurs des paquets Debian que nous utilisons pour vérifier leur clef GPG qu'ils et elles utilisent pour signer les paquets de notre distribution, ce serait assez rapidement pénible (et probablement assez coûteux en frais d'avion/train/etc), et pour nous, et pour eux!

Pour celà, on peut "uploader" nos clefs publiques sur un serveur de clef, par exemple keys.openpgp.org. On peut aussi auto-héberger notre propre serveur de clefs, utiliser github (qui permet d'utiliser sa clef GPG pour signer ses commits), etc.

Réseaux

Monitoring

Bien évidemment, il est important de pouvoir détecter tout comportement anormal, tant en entrée, sortie ou sur nos réseaux internes (et publics si nous disposons d'un bloc d'adresses publiques). Pour cela, nous avons vu les années précédentes différents outils:

Firewalls

De la même manière, chaque machine de notre système d'information doit être configurée pour n'accepter les connexions qu'aux services qu'elle doit exposer, et de même, on voudra restreindre ses communications vers l'extérieur au strict minimum. Les mêmes règles s'appliquent sur le poste de travail, ainsi que notre équipement réseau. Tout ce qui n'est pas explicitement autorisé doit être implicitement interdit.

Concernant le poste de travail, on voudra probablement protéger l'entreprise en mettant en place:

VPN

Bien évidemment, on voudra aussi ne pas exposer inutilement des services de l'entreprise sur le réseau public tout en permettant aux utilisateurs en télétravail ou mobiles (ex: pour le personnel navigant, commerciaux, etc). Il existe pléthore de solutions, hébergeables par l'entreprise directement, ou utilisant un prestataire (ex: tailscale) permettant d'authentifier et donner accès au réseau via VPN (Virtual Private Network) aux utilisateurs de l'entreprise, mais permettant aussi d'interconnecter à moindre coût (MPLS ça coûte cher :p) les différents sites de l'entreprise.

IPSec

IPSec (Internet Protocol Security) est un protocole ouvert de l'IETF (encore eux 😃), conçu pour assurer des communications privées et chiffrées sur des réseaux IP.

IPSec opère sur la couche 3 du modèle OSI (IP), et fut au début conçu pour fonctionner sur IPv6 uniquement avant d'être adapté à IPv4. Il permet l'authentification et le chiffrement des données à travers le tunnel VPN. La RFC 4301 détaille le protocole. Il est souvent utilisé pour des liaisons inter-site du fait de ses bonnes performances et de son niveau de sécurité. L'authentification s'effectue via le protocole IKE (Internet Key Exchange) via des clés partagées (PSK), mais permet aussi l'utilisation de certificats en lieu et place de la PSK.

Il peut fonctionner directement d'hôte à hôte, ou via un tunnel (encapsulation). La méthode hôte à hôte ne permet pas le NAT directement, il faut recourir à NAT-T, c'est pour cela qu'on l'utilise principalement en mode tunnel pouru du site à site ou du client à site.

Il supporte plusieurs algorithmes de chiffrement, parmi lesquels:

OpenVPN

OpenVPN a été développé dès 2001 par James Yonan. C'est un logiciel libre, qui permet aux utilisateurs de s'authentifier soit:

Il fonctionne sur à peu près tous les systèmes d'exploitation existants, peut fonctionner en UDP ou TCP (attention au TCP meltdown), et peut utiliser un grand nombre d'algorithmes de chiffrement.

C'est en général la solution implémentée dans les soft-routers/pare-feu tels que pfSense ou OPNSense, mais aussi dans les routeurs grands publics. S'il offre un très bon niveau de sécurité, ses performances sont moins bonnes qu'IPSec ou que son "concurrent" Open Source principal, Wireguard. Cependant elles sont largement suffisantes pour un accès sécurisé à un réseau d'entreprise ou personnel.

Wireguard

Wireguard est un logiciel libre, mais aussi un protocole de communication, permettant de créer facilement un VPN. Sa première version est sortie en 2015, et il a été intégré au kernel Linux en 2020 avec la version 5.6 du noyau.

Il propose des clients pour à peu près tous les systèmes d'exploitation existants, et dispose aussi de plusieurs implémentations en espace utilisateur (moins performantes mais pouvant mieux convenir à certaines contraintes de sécurité, notamment, containers dans un cluster Kubernetes).

Il fonctionne uniquement en UDP (à cause des problèmes liés au TCP over TCP, mais il est possible de l'encapsuler dans STUN si le TCP est obligatoire), et peut utiliser un mode de pré-partage de clefs symétriques, dans le but d'atténuer les risques liés à l'informatique quantique.

Il ne prend en charge que la couche 3 du modèle OSI, et fonctionne en IPv4 et en IPv6. Il est aussi capable d'effectuer des translations 4 to 6, et 6 to 4.

Il existe de nombreuses interfaces permettant de simplifier son utilisation, notamment concernant la gestion des clefs, ou implémentant une couche supplémentaire d'identification de l'utilisateur (LDAP, OIDC, etc).

Chaque utilisateur connaît la clef publique du serveur, et le serveur connaît la clef publique de chaque utilisateur (sur le même principe qu'OpenSSH).

Il est de plus en plus utilisé, que ce soit en "selfhosting", en réseau d'entreprise, ou par les fournisseurs de VPNs tels que Tailscale, Netbird.io, etc.

Il présente une faible surface d'attaque (il ne répond sur son port d'écoute qu'aux utilisateurs disposant d'un couple de clefs dont la clef publique est connue du serveur), d'une base de code réduite facilitant son audit, et utilise des algorithmes de chiffrement solides, et pour finir d'excellentes performances (de l'ordre de 950Mbps sur un lien 1Gbps) et une faible utilisation des ressources côté serveur comme client.

VPN over SSH: sshuttle

Si les performances ne sont pas vitales (TCP over TCP), et que l'on ne désire l'accès qu'à des ressources en TCP (même si sshuttle est capable de "router" les requêtes DNS UDP vers un serveur DNS distant), c'est à dire pas d'ICMP (ping) ou d'UDP (pas de jeu), pour un ensemble réduit d'utilisateurs ou en backup d'un lien VPN, sshuttle permet d'accéder à un réseau distant via OpenSSH et une savante manipulation des règles de pare-feu du client.

Il ne nécessite aucune installation côté serveur (juste OpenSSH).

On a ainsi l'avantage du chiffrement asymétrique et de l'authentification UNIX (ou PAM, LDAP, etc) de SSH et d'un VPN permettant l'accès à un réseau distant, et ce sans configuration autre que celle de SSH.

Par contre, les performances ne sont pas exceptionnelles, notamment car on encapsule du TCP dans du TCP, mais sshuttle peut être la différence entre "être enfermé dehors car le VPN est down" et "pouvoir résoudre le problème du serveur VPN sans être enfermé dehors".

SSH: double authentification, authentification via certificats

Bien évidemment, je pars du principe que vous avez déjà correctement configuré SSH, et donc, désactivé l'authentification par login/mot de passe.

Désactivation de la connexion en tant que root

Par défaut, la configuration du serveur SSH permet de se connecter en tant qu'utilisateur root via clefs de chiffrement asymétrique. On peut tout simplement désactiver cette possibilité en remplaçant la ligne:

PermitRootLogin prohibit-password

Par:

PermitRootLogin no

De même, on peut aussi vouloir n'autoriser la connexion que d'un seul, ou plusieurs utilisateur(s):

Limiter les utilisateurs autorisés à se connecter en SSH

Pour n'autoriser, par exemple, que l'utilisateur "michel" à se connecter, on peut utiliser la configuration suivante:

AllowUsers michel
Match User michel
        AuthenticationMethods publickey

Et répéter pour chaque utilisateur amené à se connecter en SSH à la machine. Par exemple, si michel et alice sont autorisés à se connecter:

AllowUsers michel alice
Match User michel
        AuthenticationMethods publickey
Match User alice
        AuthenticationMethods publickey
Désactiver le forwarding X11

Là aussi, très simple:

X11Forwarding no
Couper les sessions utilisateurs inactives au bout d'un certain temps

Il peut aussi être important de terminer les connexions utilisateurs inactives au bout d'un certain temps. Le serveur SSH enverra alors des messages de keepalive à intervalle régulier aux clients, puis coupera la connexion de son côté en cas d'inactivité/absence de réponse au bout d'un certain temps (600 secondes dans cet exemple):

ClientAliveInterval 300
ClientAliveCountMax 2
Désactiver le message of the day (MOTD)

Le MOTD peut parfois fournir des informations indésirables à un attaquant, il peut être intéressant de le désactiver:

PrintMotd no
Changer le port d'écoute du serveur SSH

Concernant le port d'écoute par défaut du serveur SSH (le port 22), et pour minimiser le bruit de fond dans les journaux de connexion, on peut vouloir changer ce port (10458 dans l'exemple suivant):

Port 10458

Cependant, il y a deux écoles concernant cette modification:

A vous de choisir dans quel camp vous vous placez 😃

Double authentification

Afin de sécuriser encore plus l'accès à notre machine (ou nos machines), on peut aussi vouloir mettre en place une double-authentification:

Pour cela, on va commencer par installer le paquet nécessaire sur notre machine:

sudo apt install libpam-google-authenticator

Puis créer nos tokens, clefs, etc:

google-authenticator

Note: on peut utiliser n'importe quel client OTP sur smartphone, pas uniquement le client Google, par exemple FreeOTP sur Android via le magasin de logiciels libres FDroid

Ce qui va nous donner quelque chose comme ça:

capture_d’écran_du_2023-12-27_16-26-19.png

Note: bien évidemment ce QRCode n'est plus valide 😉

Une fois notre QRCode scanné, nos codes de secours dûment notés et sécurisés (!), nous allons pouvoir configurer SSH et PAM pour pouvoir utiliser notre 2FA.

Tout d'abord, côté SSH, nous allons activer le paramètre keyboard-interactive au niveau de notre bloc Match User ainsi que le paramètre KbdInteractiveAuthentication dans notre fichier de configuration SSH (/etc/ssh/sshd_config)

KbdInteractiveAuthentication yes
... [snip] ...
Match User michel
        AuthenticationMethods publickey,keyboard-interactive

On va ensuite modifier le fichier /etc/pam.d/sshd, pour activer notre double-authentification (une fois que notre identité est validée par notre serveur SSH, il va passer l'authentification au système PAM). On va d'abord commenter la ligne:

@include common-auth
# qui doit donc devenir:
#@include common-auth

Et, toujours dans le même fichier, ajouter la ligne:

auth    required        pam_google_authenticator.so

Il ne nous reste plus qu'à redémarrer notre serveur SSH, avec un systemctl restart sshd (ou autre commande équivalente suivant votre distribution/OS), et vérifier le bon fonctionnement:

capture_d’écran_du_2023-12-27_16-44-35.png

Et voilà!

Authentification via clefs+certificats

Comme vous le savez, lors de notre première connexion à un serveur SSH, nous acceptons la clef publique de ce dernier. Dès lors, nous établissons une relation de confiance avec ce serveur, c'est à dire que nous faisons confiance à l'identité de ce serveur. Le client enregistre cette clé publique dans son fichier ~/.ssh/known_hosts.

De la même façon, le serveur fait confiance au client à travers son identité fournie via sa clef publique. L'administrateur du serveur doit placer la clef publique de l'utilisateur dans le répertoire utilisateur de son compte, dans le fichier ~/.ssh/authorized_keys, afin de s'assurer de l'identité de l'utilisateur lors de sa connexion.

Nous allons voir comment utiliser des certificats SSH pour s'assurer de l'identité du client et du serveur.

Avec l'authentification par certificats, le serveur comme le client continuent d'utiliser les clefs SSH pour vérifier l'identité de chaque partie, mais on utilise en plus un certificat, c'est à dire une signature de la clef SSH à laquelle le certificat est associé, signature effectuée par une autre clef SSH représentant notre autorité de certification, associée à un identifiant (principal en anglais), et quelques options (durée de vie du certificat par exemple, et donc, de la clef signée).

Ainsi, notre serveur n'a plus à accorder sa confiance à de multiples clefs publiques présentent dans le fichier authorized_keys mais uniquement à une seule clef publique, notre autorité de certification pour nos clefs "client", et cette clef permet de vérifier l'authenticité des clefs SSH signées par elle.

De la même manière, le client n'aura plus qu'à accorder sa confiance à une clef publique SSH "autorité de certification des serveurs" pour tous les serveurs dont les clefs auront été signées par cette clef "Autorité de certification" (CA dans la suite de ce document, sinon je vais finir par avoir mal aux doigts à force de taper "Autorité de certification" 😃).

Dès lors on voit que nous devons utiliser deux CAs différentes:

On pourrait utiliser un seul couple de clefs pour faire office de CA à la fois pour nos clients et nos serveurs, mais ce n'est pas conseillé: en effet, l'authentification des clients et des serveurs sont deux opérations différentes, dès lors, il est plus rationnel d'utiliser des CAs différentes pour ces opérations.

Idéalement, vous voudrez effectuer la création et le stockage de ces autorités de certifications sur une machine dédiée et correctement isolée, et on utilisera normalement une phrase de passe raisonnablement complexe pour les protéger correctement au cas où elles fuiteraient.

Dans notre cas, on va juste se créer une petite VM (1 coeur, 512Mo de RAM) sur le cluster de virtu (clonez (clone lié!) un template debian bookworm, configurez la partie Cloudinit, comme décrit sur le wiki)

Sur cette machine, nous allons créer les clefs de nos CAs:

ssh-keygen -t ed25519 -C 'Server CA' -f ~/.ssh/ca-servers
ssh-keygen -t ed25519 -C 'Clients CA' -f ~/.ssh/ca-clients

Dans la vraie vie, on utilisera une passphrase solide, là, on va se contenter d'une passphrase basique facilement mémorisable (genre, p@ssword ou autre), car de toute façon on supprimera cette VM par la suite. De même, on va se servir de cette VM comme serveur pour nos tests, mais elle ne devrait en réalité être utilisée que pour signer des clefs 😃

On va se créer une seconde VM, qui nous servira de client, même configuration. Sur cette VM, nous allons nous créer une clef SSH classique:

ssh-keygen -t ed25519

On va copier la clef publique de la machine client sur notre serveur, via nc, ou en copiant collant la clef publique en question via nos terminaux. Maintenant, on va la signer:

ssh-keygen -s ~/.ssh/ca-clients -I "Nom choisi librement" -n identifiant ./id_ed25519.pub

Ici:

On obtient un fichier id_ed25519-cert.pub, on peut l'examiner avec la commande:

ssh-keygen -L -f id_ed25519-cert.pub
id_ed25519-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:yno3p5Ng5lAuPupq8ecb2oIGxlKjWNqZTsMCpkU4F8U
        Signing CA: ED25519 SHA256:5BDCh5rmcFsSGv7c3IZ1XixABjAmnrZ2b8Jfr0ucLGQ (using ssh-ed25519)
        Key ID: "Test key"
        Serial: 0
        Valid: forever
        Principals: 
                lidstah
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

Maintenant, pour que le serveur SSH puisse reconnaître les signatures dans les certificats que les clients vont lui présenter, il faut modifier sa configuration pour lui indiquer où trouver notre CA clients, en lui indiquant le chemin d'un fichier contenant les clefs publiques de ces CAs (on peut tout à fait en avoir plusieurs!) que j'appelle ici ca-clients-keys:

cat .ssh/ca-clients.pub | sudo tee -a /etc/ssh/ca-clients-keys

On va ensuite modifier la configuration du serveur SSH pour lui indiquer où trouver ce fichier grâce à la directive TrustedUserCAKeys:

TrustedUserCAKeys /etc/ssh/ca-clients-keys

On sauvegarde, on quitte, et on relance le serveur SSH: systemctl restart sshd.

Le client doit ensuite placer ce certificat dans son répertoire ~/.ssh, dans notre cas, copié collé entre terminaux, ou un bon vieux netcat. Le répertoire ~/.ssh de notre VM client devrait ressembler à ça:

lidstah@deb-sshcrt-02:~$ ls -lah .ssh
total 24K
drwx------ 2 lidstah lidstah 4.0K Nov 20 19:38 .
drwxr-xr-x 3 lidstah lidstah 4.0K Nov 20 18:39 ..
-rw------- 1 lidstah lidstah  843 Nov 20 18:25 authorized_keys
-rw------- 1 lidstah lidstah  411 Nov 20 19:16 id_ed25519
-rw-r--r-- 1 lidstah lidstah  652 Nov 20 19:38 id_ed25519-cert.pub
-rw-r--r-- 1 lidstah lidstah  103 Nov 20 19:16 id_ed25519.pub

Aucun changement de configuration n'est requis côté client, qui peut directement se connecter (pas besoin de renseigner sa clef publique dans le authorized_keys du serveur!)

Si on regarde les logs du serveur SSH:

sudo journalctl /usr/sbin/sshd
...
Accepted publickey for lidstah from 10.150.50.47 port 45934 ssh2: ED25519-CERT.....
...

Maintenant, passons au certificats serveur

De la même manière que nous avons signé notre clef publique avec l'autorité de certification de nos clients, nous pouvons faire de même pour signer les clefs publiques de nos serveurs (ici, uniquement la clef ECDSA), mais en utilisant cette fois ci notre CA serveurs:

# on se place en root cette fois ci
sudo -s
ssh-keygen -s .ssh/ca-servers -I "Test server" -h -n deb-sshcrt-01 /etc/ssh/ssh_host_ecdsa_key.pub

Ici, les paramètres sont presque identiques, hormis deux détails:

On va ensuite modifier la configuration du serveur pour qu'il sache où trouver son certificat:

# on édite la config du serveur ssh:
sudo vim /etc/ssh/sshd_config
# on ajoute la ligne:
HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub
# on sauvegarde, on quitte, et on relance le serveur ssh:
sudo systemctl restart sshd

Côté client, on va récupérer la clef publique de la CA Serveurs (copié/collé, nc, scp, etc) et l'ajouter à notre fichier ~/.ssh/known_hosts, qui devra contenir:

@cert-authority * ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxCwGCqvI0JDnupN4qRqt8Uwfq1e17WdOl3rcVFlwkk Server CA

Ici, le "*" est volontairement très large. Si notre domaine et tous les serveurs sur lesquels on se connecte appartenaient au domaine lidstah.info, notre ligne cert-authority ressemblerait à ça:

@cert-authority *.lidstah.info ssh-ed25519 AAAA........

Backup chiffré avec Borg Backup

Tout d'abord, nous allons nous créer une VM de backup. On ne va pas la chiffer, mais par contre on va chiffrer les backups via BorgBackup

Nous devons pouvoir nous connecter en ssh depuis notre VM chiffrée avec notre utilisateur de base - ici, on ne sauvegardera que le contenu du $HOME de notre utilisateur.

Sur notre VM de backup, nous allons créer un répertoire /home/backup, et lui donner la propriété à notre utilisateur et groupe par défaut (ici, un utilisateur qu'on appelera user):

sudo mkdir /home/backup
sudo chown -R user: /home/backup

Sur nos deux VMs, nous allons installer Borg Backup. Sous Debian, c'est très simple:

sudo apt install borgbackup

Maintenant, sur notre VM chiffrée, nous allons préparer notre repository (qui sera stocké sur notre VM de backup et copié via SSH). Ici, notre VM de backup a pour IP 192.168.1.153, et mon utilisateur SSH est 'lidstah':

borg init --encryption=repokey ssh://lidstah@192.168.1.153:22/home/backup

Borg va nous demander une passphrase - prenons en une simple dans notre test, mais dans la vraie vie, utilisez-en une complexe que vous stockerez dans un gestionnaire de mots de passe sécurisé.

De même, nous allons aussi sauvegarder la clef privée du repo (là aussi, rangez-moi ça dans un conteneur sécurisé dans la vraie vie!!!):

borg key export ssh://lidstah@192.168.1.153:22/home/backup
BORG_KEY 15fb0cf0c4b11a45205f85619d0c276571fa65d472bcefa3e61ed5f56f456ad5
hqlhbGdvcml0aG2mc2hhMjU2pGRhdGHaAN6Kwe8CwAyLxjd9blW007dFiWYhSvkkjBv39w
U5q7I1QQpsmDWUyke9ExPPni+Gxzc6+9Cr0N53feaC3qTDRylumVn2IOJ+pSZm7LmTSgLR
cC1CRK/N2GmB+GwxwjIJv4rE9GkJBF2I65FlMEe1GFAExlNvvTepkldEhI1ZZGlyBPFWhx
Lyv16lE5P4f59LpV+SpWstnrEJAp1u6YvQegU1FHs7UmgC6rtTz7e+gxc62XeqA1hZk5Ml
fDGDJSQ4DzRpyherhEP5EDbIsRqv0ivwyaLakFPSpbOqJzFhuG2kaGFzaNoAIBIVZCUS/n
nKX+BYf7yxG9miDRiyfhmDdCW/CQznfD7fqml0ZXJhdGlvbnPOAAGGoKRzYWx02gAgpwuM
pmMqtkQKOjvSocr/szyavV/fCVmBVEnNJf6iZCKndmVyc2lvbgE=

Bon là encore, c'est une clef de test, hein, elle n'est pas vraiment importante, mais dans la vraie vie, c'est un SECRET 😃. Si vous perdez votre clef privée et que vous oubliez votre passphrase... c'est fini!

Allez, testons notre repo de backup! On va simplement sauvegarder le HOME de notre utilisateur pour cette démo:

cd
borg create --stats -C zstd,10 ssh://lidstah@192.168.1.153:22/home/backup::2024111901 .
Enter passphrase for key ssh://lidstah@192.168.1.153:22/home/backup: 
------------------------------------------------------------------------------
Repository: ssh://lidstah@192.168.1.153:22/home/backup
Archive name: 2024111901
Archive fingerprint: 517ae101fb388094c132b7ee3c77c456bab179eb7fb907fb90f0aa37ab3a0a57
Time (start): Tue, 2024-11-19 15:45:46
Time (end):   Tue, 2024-11-19 15:45:59
Duration: 13.43 seconds
Number of files: 35
Utilization of max. archive size: 0%
------------------------------------------------------------------------------
                       Original size      Compressed size    Deduplicated size
This archive:              253.79 MB            251.85 MB            251.82 MB
All archives:              253.88 MB            251.89 MB            251.86 MB

                       Unique chunks         Total chunks
Chunk index:                     137                  164
------------------------------------------------------------------------------

Regardons maintenant ce que nous avons dans notre dépôt:

borg list ssh://lidstah@192.168.1.153:22/home/backup
Enter passphrase for key ssh://lidstah@192.168.1.153:22/home/backup: 
2024111701                           Sun, 2024-11-17 18:49:52 [07082f61359c1283cd29cf86506d976bbe087b73c675e807bd4aad4c3c2d6a53]
2024111901                           Tue, 2024-11-19 15:45:46 [517ae101fb388094c132b7ee3c77c456bab179eb7fb907fb90f0aa37ab3a0a57]

Comme vous le voyez, j'ai déjà un backup précédent. Le second est plus gros (j'ai ajouté une iso d'un OS obscur). Rajoutez un fichier (par exemple le miniroot filesystem d'Alpine Linux, ou tout autre fichier pas trop gros mais qui fera une différence) via la commande wget, puis réeffectuez un backup, en incrémentant le numéro du backup (par ex, 2024111902 au lieu de 2024111901). Vérifiez avec borg list que tout est OK.

Maintenant, supprimons notre gros fichier de notre filesystem, oh, zut!

Pas grave, on va le récupérer du backup (dans le répertoire courant):

borg extract --progress ssh://lidstah@192.168.1.153:22/home/backup::2024119101 9front-10522.amd64.iso.gz

Et hop! (Note: on peut aussi utiliser --progress lorsqu'on crée notre backup, hein 😉)

Bien sûr, comme Borg gère la déduplication, je peux renommer mon fichier, resauvegarder, et comme le fichier est identique minus le nom, je ne prendrai pas plus de place!

borg create --stats -C zstd,10 ssh://lidstah@192.168.1.153:22/home/backup::2024111902 .
Enter passphrase for key ssh://lidstah@192.168.1.153:22/home/backup: 
------------------------------------------------------------------------------
Repository: ssh://lidstah@192.168.1.153:22/home/backup
Archive name: 2024111902
Archive fingerprint: 5c70d31b46fa1088f558879e36e9b8b274ed718a09444eb1a00bcd936b0e0485
Time (start): Tue, 2024-11-19 16:05:49
Time (end):   Tue, 2024-11-19 16:05:51
Duration: 2.00 seconds
Number of files: 35
Utilization of max. archive size: 0%
------------------------------------------------------------------------------
                       Original size      Compressed size    Deduplicated size
This archive:              253.79 MB            251.85 MB                691 B
All archives:              507.67 MB            503.74 MB            251.87 MB

                       Unique chunks         Total chunks
Chunk index:                     141                  295
------------------------------------------------------------------------------

Notez la taille dédupliquée: mes environ 504Mo d'archive compressée ne prennent que 251.87Mo en vrai!

Pour extraire mes fichiers, il y a encore plus fort: je peux monter le backup dans un répertoire via borgfs:

# on install fuse3 si ce n'est pas déjà fait:
sudo apt install fuse3
mkdir /tmp/backupmount
borg mount ssh://lidstah@192.168.1.153:22/home/backup::2024111902 /tmp/backupmount
ls /tmp/backupmount
9front.izo.gz  clefbobpub.pem  clefbobrsa  lid.gpg  message.decrypted
message.encrypted.gpg  message.encrypted.gpg.sig  michel.gpg
# on démonte le backup
borg umount /tmp/backupmount

Il y a aussi de nombreuses occasions où on ne veut PAS sauvegarder certains répertoires, par exemple, du cache, ou autre. Dans ce cas, on utilisera, tout comme avec rsync, l'option --exclude, par exemple ici pour ne pas sauvegarder ~/.cache et ~/.config:

borg create --stats -C zstd,10 --exclude '.cache' --exclude '.config' ssh://lidstah@192.168.1.153:22/home/backup::2024111902 .

Bon, c'est bien gentil, mais à un moment ou un autre, déduplication ou pas, il va falloir faire le ménage, non?

Pour ça, deux solutions:

borg delete ssh://lidstah@192.168.1.153:22/home/backup::2024111701
borg compact ssh://lidstah@192.168.1.153:22/home/backup
borg prune --keep-last 365 ssh://lidstah@192.168.1.153:22/home/backup
borg compact ssh://lidstah@192.168.1.153:22/home/backup

Testons vite fait cette méthode:

# créons d'abord quelques backups "bidons":
for i in 3 4 5 6
do
  borg create -C zstd,10 ssh://lidstah@192.168.1.153:22/home/backup::202411190${i} .
done
# on checke:
borg list ssh://lidstah@192.168.1.153:22/home/backup
Enter passphrase for key ssh://lidstah@192.168.1.153:22/home/backup:
2024111701                           Sun, 2024-11-17 18:49:52 [07082f61359c1283cd29cf86506d976bbe087b73c675e807bd4aad4c3c2d6a53]
2024111901                           Tue, 2024-11-19 15:45:46 [517ae101fb388094c132b7ee3c77c456bab179eb7fb907fb90f0aa37ab3a0a57]
2024111902                           Tue, 2024-11-19 16:05:49 [5c70d31b46fa1088f558879e36e9b8b274ed718a09444eb1a00bcd936b0e0485]
2024111903                           Tue, 2024-11-19 16:34:32 [c1d11c8f876025b51effcae9d297e26c29103f405834458c337be548b19d94ae]
2024111904                           Tue, 2024-11-19 16:34:37 [36b4695a687dea636d1aadcdeb1debd87df90bada6c3bcbe9a328788a6bdcf56]
2024111905                           Tue, 2024-11-19 16:34:41 [4f0b8e1d9ecdbcf934a4c173e0a95869350a480d7af32970697dc5bc038512fb]
2024111906                           Tue, 2024-11-19 16:34:46 [5f348b6b4e3833535bb36c27040847dcfe71275c689ed04ecf0b2a9fc3b3e3d7]
# nettoyons tout ça en gardant uniquement les 3 derniers:
borg prune --keep-last 3 ssh://lidstah@192.168.1.153:22/home/backup
# on rechecke:
borg list ssh://lidstah@192.168.1.153:22/home/backup
Enter passphrase for key ssh://lidstah@192.168.1.153:22/home/backup:
2024111904                           Tue, 2024-11-19 16:34:37 [36b4695a687dea636d1aadcdeb1debd87df90bada6c3bcbe9a328788a6bdcf56]
2024111905                           Tue, 2024-11-19 16:34:41 [4f0b8e1d9ecdbcf934a4c173e0a95869350a480d7af32970697dc5bc038512fb]
2024111906                           Tue, 2024-11-19 16:34:46 [5f348b6b4e3833535bb36c27040847dcfe71275c689ed04ecf0b2a9fc3b3e3d7]

Automatiser tout ça avec borgmatic

Eh bien ça, c'est dans votre sujet de TP! \o/ (oui, vous allez me détester, et non, c'est simple à configurer, en vrai!!)