20/10/2026

Déverrouiller un disque chiffré à distance avec un tunnel SSH inversé

Objectif : ne plus avoir à venir physiquement devant le serveur pour taper le code de déchiffrement LUKS à chaque redémarrage.

Au démarrage, le serveur chiffré ouvre lui-même un tunnel SSH vers un serveur relais joignable depuis Internet. Il suffit ensuite de se connecter au relais et de passer par le tunnel pour taper le code. Aucun port n’est à ouvrir sur la box du serveur chiffré.

serveur chiffré (initramfs)  ──── tunnel SSH ────►  relais:10022
       Dropbear :4748        ◄────────────────────  ssh -p 10022 root@localhost

Prérequis :

1. Installer Dropbear dans l’initramfs (serveur chiffré)

Dropbear est un petit serveur SSH qui tourne au démarrage, avant le déchiffrement du disque.

apt install dropbear-initramfs
vim /etc/dropbear/initramfs/dropbear.conf
DROPBEAR_OPTIONS="-I 180 -j -k -p 4748 -s -c cryptroot-unlock"
Option Rôle
-I 180 Coupe la session après 180 s d’inactivité
-j -k Interdit les redirections de ports
-p 4748 Écoute sur le port 4748
-s Interdit la connexion par mot de passe (clé uniquement)
-c cryptroot-unlock Lance directement la demande du code de déchiffrement
vim /etc/dropbear/initramfs/authorized_keys

La clé du relais y sera ajoutée à l’étape 4.

2. Préparer le relais

Créer un compte dédié au tunnel

adduser --disabled-password --shell /usr/sbin/nologin --gecos "" tunnel
mkdir -p /home/tunnel/.ssh
touch /home/tunnel/.ssh/authorized_keys
chown -R tunnel: /home/tunnel/.ssh
chmod 700 /home/tunnel/.ssh
chmod 600 /home/tunnel/.ssh/authorized_keys

Brider le compte

vim /etc/ssh/sshd_config
Match User tunnel
    AllowTcpForwarding remote
    PermitTTY no
    X11Forwarding no
    ClientAliveInterval 15
    ClientAliveCountMax 2

Le ClientAlive libère le port en environ 30 secondes si le serveur chiffré redémarre brutalement. Sans ça, l’ancien tunnel bloquerait le port et le nouveau ne pourrait pas s’ouvrir.

sshd -t && systemctl reload ssh

3. Créer la clé du tunnel (serveur chiffré)

dropbearkey -t ed25519 -f /etc/dropbear/initramfs/relay_key
dropbearkey -y -f /etc/dropbear/initramfs/relay_key | grep ^ssh-
restrict,port-forwarding,permitlisten="10022" ssh-ed25519 AAAA...

Cette clé ne peut rien faire d’autre qu’ouvrir le port 10022 sur le relais.

Enregistrer l’empreinte du relais

Au démarrage, dbclient doit reconnaître le relais, sinon il veut demander une confirmation, et comme personne ne peut répondre, il abandonne.

dbclient -N -i /etc/dropbear/initramfs/relay_key -p 2022 -R 10022:127.0.0.1:22 tunnel@relais.exemple.fr
ss -tlnp | grep 10022

Une ligne 127.0.0.1:10022 doit apparaître. Faire Ctrl+C sur le serveur chiffré.

grep relais.exemple.fr /root/.ssh/known_hosts > /etc/dropbear/initramfs/relay_known_hosts

Attention : ne pas utiliser ssh-keyscan. Il écrit [relais.exemple.fr]:2022 ... alors que dbclient cherche relais.exemple.fr ... : l’empreinte ne serait pas reconnue au démarrage.

4. Autoriser le relais à se connecter à Dropbear

ls ~/.ssh/id_ed25519.pub || ssh-keygen -t ed25519
cat ~/.ssh/id_ed25519.pub
vim /etc/dropbear/initramfs/authorized_keys

5. Les scripts de l’initramfs (serveur chiffré)

mkdir -p /etc/initramfs-tools/hooks \
  /etc/initramfs-tools/scripts/init-premount \
  /etc/initramfs-tools/scripts/init-bottom

Le hook

Il copie dbclient, la clé et l’empreinte dans l’initramfs au moment de sa construction.

vim /etc/initramfs-tools/hooks/reverse-tunnel
#!/bin/sh
PREREQ="dropbear"
prereqs() { echo "$PREREQ"; }
case "$1" in prereqs) prereqs; exit 0 ;; esac

. /usr/share/initramfs-tools/hook-functions

copy_exec /usr/bin/dbclient /bin

mkdir -p "${DESTDIR}/root/.ssh"
cp /etc/dropbear/initramfs/relay_key "${DESTDIR}/root/.ssh/relay_key"
cp /etc/dropbear/initramfs/relay_known_hosts "${DESTDIR}/root/.ssh/known_hosts"
chmod 700 "${DESTDIR}/root/.ssh"
chmod 600 "${DESTDIR}/root/.ssh/relay_key"

Le script qui ouvre le tunnel

Il s’exécute au démarrage, avant la demande du code.

vim /etc/initramfs-tools/scripts/init-premount/reverse-tunnel
#!/bin/sh
PREREQ="dropbear"
prereqs() { echo "$PREREQ"; }
case "$1" in prereqs) prereqs; exit 0 ;; esac

. /scripts/functions

RELAY_HOST="relais.exemple.fr"
RELAY_PORT="2022"
RELAY_USER="tunnel"
TUNNEL_PORT="10022"

configure_networking
ip link set lo up 2>/dev/null || ifconfig lo up 2>/dev/null

if [ ! -s /etc/resolv.conf ]; then
  for f in /run/net-*.conf; do
    [ -e "$f" ] && . "$f" && [ -n "$IPV4DNS0" ] && echo "nameserver $IPV4DNS0"
  done > /etc/resolv.conf
  [ -s /etc/resolv.conf ] || echo "nameserver 1.1.1.1" > /etc/resolv.conf
fi

(
  export HOME=/root
  while true; do
    /bin/dbclient -N -K 30 -i /root/.ssh/relay_key -p "$RELAY_PORT" \
      -R "${TUNNEL_PORT}:127.0.0.1:4748" "${RELAY_USER}@${RELAY_HOST}"
    sleep 10
  done
) >/dev/null 2>&1 &

echo $! > /run/reverse-tunnel.pid

Important : la ligne ip link set lo up est indispensable. Dans l’initramfs, l’interface loopback n’est pas activée : sans elle, 127.0.0.1 n’existe pas et la connexion est coupée avec Connection reset by peer.

Le script qui coupe le tunnel

Il s’exécute une fois le disque déverrouillé.

vim /etc/initramfs-tools/scripts/init-bottom/reverse-tunnel
#!/bin/sh
PREREQ=""
prereqs() { echo "$PREREQ"; }
case "$1" in prereqs) prereqs; exit 0 ;; esac

[ -f /run/reverse-tunnel.pid ] && kill "$(cat /run/reverse-tunnel.pid)" 2>/dev/null
for p in $(pidof dbclient); do kill "$p" 2>/dev/null; done
exit 0

Rendre exécutable et reconstruire

chmod +x /etc/initramfs-tools/hooks/reverse-tunnel \
  /etc/initramfs-tools/scripts/init-premount/reverse-tunnel \
  /etc/initramfs-tools/scripts/init-bottom/reverse-tunnel
update-initramfs -u

Vérifier le contenu de l’initramfs

lsinitramfs /boot/initrd.img-$(uname -r) | grep -E 'dbclient|\.ssh|reverse-tunnel'

Il doit y avoir usr/bin/dbclient, root/.ssh/relay_key, root/.ssh/known_hosts et les deux scripts reverse-tunnel.

rm -rf /tmp/initrd && unmkinitramfs /boot/initrd.img-$(uname -r) /tmp/initrd
cat $(find /tmp/initrd -path '*init-premount/reverse-tunnel')

6. Configurer le relais pour déverrouiller

Raccourci SSH

vim ~/.ssh/config
Host unlock
    HostName localhost
    Port 10022
    User root
    HostKeyAlias unlock-initramfs
    StrictHostKeyChecking accept-new
    ConnectTimeout 5

Le HostKeyAlias évite les conflits de clé avec les autres connexions à localhost.

Attendre le tunnel automatiquement

vim ~/.bashrc
unlock() {
    echo "En attente du tunnel du nas..."
    until ss -tln | grep -q ':10022 '; do sleep 2; done
    echo "Tunnel prêt, connexion."
    ssh unlock
}
source ~/.bashrc

7. Utilisation

unlock

Si un shell s’affiche au lieu de la demande du code, taper cryptroot-unlock.

Dépannage

Symptôme Cause probable
unlock attend indéfiniment Le tunnel ne se monte pas : vérifier relay_known_hosts, passer le script en >/dev/console et regarder l’écran au démarrage
Connection reset by peer La loopback n’est pas activée (ip link set lo up manquant) ou Dropbear n’écoute pas sur 4748
Permission denied (publickey) La clé du relais n’est pas dans /etc/dropbear/initramfs/authorized_keys, ou update-initramfs -u n’a pas été relancé
Le port est déjà utilisé sur le relais Choisir un port de tunnel différent du port SSH du relais
journalctl -u ssh -f | grep -i tunnel

À retenir : après toute modification de la clé, de l’empreinte, des scripts ou de authorized_keys, relancer update-initramfs -u.