Skip to content

Serveur dédié OVH, panne de SSH et activation réseau

Auteur : Philippe Le Van - @plv@framapiaf.org

Date : 9 octobre 2024

Introduction

Suite à une mise à jour de mon serveur dédié OVH (soyoustart), et un reboot, j'ai perdu mon accès SSH, et les reboots successifs ne me rendaient pas l'accès réseau. L'incident s'est déroulé le 7 octobre 2024.

La cause du problème vient de l'adresse IP de la machine qui est attribuée trop tard au serveur. De daemon SSH a essayé de redémarrer 3 fois avant que l'IP soit attribuée et il a lâché l'affaire. L'IP est attribuée environ 10s plus tard.

Le problème a été résolu en redémarrant le serveur en mode rescue, en modifiant le fichier de démarrage de ssh (l'unit systemd) pour qu'il attende 10s avant chaque tentatives de redémarrage.

Ce document décrit les étapes pour résoudre ce problème et les difficultées rencontrées.

Environnement concerné

  • Serveur dédié OVH (soyoustart)
  • Debian 11
  • systemd
  • SSH
  • Docker et Traefik

Symptômes et difficultés du diagnostic

Symptômes

Après un reboot, je n'ai plus accès à la machine en SSH. En revanche les autres services de la machine tournent bien (sites web, docker, ...).

Difficultés du diagnostic

On parle d'un vieux serveur OVH/Soyoustart. Il n'a pas d'accès console. Le seul moyen de diagnostic que j'ai, c'est un accès au mode rescue.

Le mode rescue d'OVH, c'est un mode où on boote sur une autre machine, et on peut monter les disques de la machine à problème (qui est arrêtée). On peut ainsi consulter les logs, modifier des fichiers de configuration, ....

Pour faire le diagnostic, si on veut avancer pas à pas en modifiant un fichier de config, consulter les logs, remodifier un fichier, reconsulter les logs..., À chaque fois il faut rebooter la machine en mode rescue, monter les disques, faire les modifications, démonter les disques, rebooter en mode normal... Bref, chaque itération prend bien 15 minutes.

Une autre difficulté vient de systemd. SSH est lancé avec une unit systemd. Les logs de SSH sont alors consultables avec l'outil journalctl, mais ne sont pas enregistrés sur le disque. Je n'ai donc pas accès aux logs de SSH en mode rescue. Je n'ai donc pas du tout accès aux logs "classiques" de SSH. J'ai juste accès aux logs dans /var/log/syslog, mais SSH n'est pas du tout verbeux dans ce fichier par défaut.

Mode rescue

Pour utiliser le mode rescue, il faut :

  • se connecter à l'interface OVH/Soyoustart
  • passer le "netboot" en mode rescue
  • Rebooter la machine
  • On reçoit alors un mail avec les instructions pour se connecter en mode rescue
  • Se connecter en SSH en mode rescue en suivant les instructions
  • regarder la liste des disques avec la commande fdisk -l
  • chez moi, le disque principal était dans /dev/md2
  • monter le disque principal dans /mnt avec la commande mount /dev/md2 /mnt
  • on a alors accès au disque de la machine dans /mnt

Approche utilisée

J'ai utilisé 2 approches en parallèle :

  • Installer un webshell pour avoir un accès à la machine sans SSH
  • Essayer de rendre SSH plus verbeux quelque part où je pourrais consulter les logs en mode rescue

Installer un webshell

J'ai ajouté dans systemd une unit qui lance le service Shell In A Box. J'ai utilisé l'image docker suivante : sspreitzer/shellinabox:latest.

Sur cette machine, j'ai docker et traefik v1.7 qui tournent.

Pour celà j'ai créé l'unit suivante (en mode rescue) :

/lib/systemd/system/shell_in_box.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[Unit]
Description=shell_in_box
Wants=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=10

ExecStartPre=-/usr/bin/docker kill shell_in_box
ExecStartPre=-/usr/bin/docker rm shell_in_box


ExecStart=/usr/bin/docker run  --volume /:/host --env-file "/etc/sysconfig/shell_in_box" --label traefik.frontend.rule=Host:shell.example.com --label traefik.port=4200 --label traefik.enable=true   --network=traefik_public --net-alias=shell_in_box --name shell_in_box sspreitzer/shellinabox:latest
ExecStop=/usr/bin/docker kill shell_in_box

[Install]
WantedBy=local.target
WantedBy=default.target

avec des paramètres dans le fichier /etc/sysconfig/shell_in_box

1
2
3
4
5
SIAB_PASSWORD=_un_password_solide_
SIAB_SUDO=true
SIAB_GROUPID=1500
SIAB_USERID=1500
SIAB_SSL=false

Il faut ensuite activer l'unit (mais je suis en mode rescue, je n'ai pas accès à la commande systemctl).

1
2
3
4
5
cd /etc/systemd/system/local.target.wants/
ln -s /lib/systemd/system/shell_in_box.service shell_in_box.service

cd /etc/systemd/system/default.target.wants/
ln -s /lib/systemd/system/shell_in_box.service shell_in_box.service

Il faut ensuite que je crée l'entrée DNS pour shell.example.com.

Avec les labels dockers utilisés dans l'unit pour traefik, le site devrait être accessible à l'adresse shell.example.com au prochain reboot.

Concrêtement ça a bien fonctionné, mais le temps que je mette ça en place, j'ai trouvé une solution pour mon SSH. Je ne l'ai pas utilisé.

Warning

Un shell comme ça peut vite être un trou de sécurité. Il faut le désactiver dès qu'on n'en a plus besoin : systemctl stop shell_in_box et systemctl disable shell_in_box.

Rendre SSH plus verbeux

Les logs accessibles

Les seuls logs accessibles en mode rescue sont les logs de /var/log/syslog. SSH n'est pas très verbeux dans ce fichier. On a juste ça :

1
Oct  7 18:09:08 xxx systemd[1]: ssh.service: Main process exited, code=exited, status=255/EXCEPTION

tentative ratée d'augmentation de la verbosité

J'ai essayé de changer le LogLevel vers DEBUG3 dans /etc/ssh/sshd_config, mais ça concernait la verbosité des logs de journalctl, et je n'y avais pas accès en mode rescue.

tentative réussie d'augmentation de la verbosité dans /var/log/syslog

J'ai édité l'unit qui lance SSH et j'ai ajouté un -d (pour debug) au démarrage : Dans le fichier /lib/systemd/system/ssh.service, j'ai modifié la ligne :

1
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS

par

1
ExecStart=/usr/sbin/sshd -d -D $SSHD_OPTS

On obtient alors des logs plus complets dans /var/log/syslog :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Oct  8 08:15:51 xxxx sshd[633]: debug1: sshd version OpenSSH_8.4, OpenSSL 1.1.1w  11 Sep 2023
Oct  8 08:15:51 xxxx sshd[633]: debug1: private host key #0: ssh-rsa SHA256:iszxxxxxxxxkvBeYA
Oct  8 08:15:51 xxxx sshd[633]: debug1: private host key #1: ecdsa-sha2-nistp256 SHA256:GMcQldxxxxxxxx2YEcQ
Oct  8 08:15:51 xxxx sshd[633]: debug1: private host key #2: ssh-ed25519 SHA256:/WIvOJ8vf8Fvxx/ldXU
Oct  8 08:15:51 xxxx sshd[633]: debug1: rexec_argv[0]='/usr/sbin/sshd'
Oct  8 08:15:51 xxxx sshd[633]: debug1: rexec_argv[1]='-d'
Oct  8 08:15:51 xxxx sshd[633]: debug1: rexec_argv[2]='-D'
Oct  8 08:15:51 xxxx sshd[633]: debug1: Set /proc/self/oom_score_adj from 0 to -1000
Oct  8 08:15:51 xxxx sshd[633]: debug1: Bind to port 22 on xx.xx.xx.xx.
Oct  8 08:15:51 xxxx sshd[633]: Bind to port 22 on xx.xx.xx.xx failed: Cannot assign requested address.
Oct  8 08:15:51 xxxx sshd[633]: Cannot bind any address.
Oct  8 08:15:51 xxxx systemd[1]: ssh.service: Main process exited, code=exited, status=255/EXCEPTION
Oct  8 08:15:51 xxxx systemd[1]: ssh.service: Failed with result 'exit-code'.
Oct  8 08:15:51 xxxx systemd[1]: Failed to start OpenBSD Secure Shell server.

Là on voit que SSH n'arrive pas à se connecter à l'adresse IP de la machine.

Un peu plus loin dans les logs (environ 10s plus tard), on voit que l'adresse IP a été attribuée à la machine, mais entre temps, SSH a essayé de redémarrer 3 fois et a lâché l'affaire avec le log :

1
Oct  8 08:15:52 arbois systemd[1]: ssh.service: Start request repeated too quickly.

Résolution

J'ai modifié l'unit systemd de SSH pour qu'il attende 10s avant chaque tentative de redémarrage.

/lib/systemd/system/ssh.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process

# lignes commentées
# Restart=on-failure
# RestartPreventExitStatus=255

# lignes ajoutées
Restart=always
RestartSec=10

Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service

Après un restart, SSH a bien redémarré et j'ai pu me reconnecter à la machine.

Questions en suspens

Deux question se posent :

  • pourquoi ça marchait avant et pas maintenant ?
  • pourquoi l'adresse IP n'est pas encore attribuée au lancement de SSH, alors que dans la config de l'unit systemd, on a bien :
1
After=network.target auditd.service
  • c'est également bizarre que l'unit systemd de SSH ne soit pas plus robuste à ce genre de problème. Est-ce que j'aurais une unit non standard parce que c'est un serveur qui a déjà été upgradé plusieurs fois de plusieurs versions de Debian ?

Je n'ai pas de réponse à ces questions. J'ai juste une hypothèse un peu bancale : peut-être que le DHCP d'OVH est plus lent qu'avant et peut-être que le network.target est atteint avant que l'IP ne soit attribuée par DHCP...

Si vous avez des suggestions, des réponses, des idées, des remarques, n'hésitez pas à me contacter sur Mastodon : @plv@framapiaf.org