tuxad blog
Syndicate
Site (RSS, Atom)
Contact
Weblog status
Total entries: 33
Last entry: 2014-10-09 12:41:47
Last updated: 2014-10-09 13:35:58
powered by vim, bash, cat, grep, sed, and nb 3.4.2

Notfall–sshd OOM–resistent

Dieser Artikel beschreibt, wie man einen SSH-Dienst mit maximaler Zuverlässigkeit betreibt. Ursprünglich war es ein Blogpost, der wegen seiner Länge (und Komplexität) als Artikel neu angelegt wurde.

In extremen Notfällen, wenn beispielsweise ein "normal" gestarteter sshd durch einen OOM-Kill (Out Of Memory) des Kernels beendet wurde, wünscht sich ein Admin gerne noch eine Login-Möglichkeit.

Hier zeigt sich der große Nachteil eines "normal" gestarteten Daemons (per SysV-Script oder vergleichbar), bei dem vielleicht noch ein PID-File geschrieben wird, es aber keine Instanz gibt, die über ein Ende des Daemons unmittelbar informiert wird. Tools wie monit verschlimmbessern die Lage, da es einen weiteren Prozess gibt, der aber trotzdem das Ende eines Daemons nicht direkt mitbekommt, sondern prüfen muß, ob der Daemon noch läuft.

ssh mit supervising

Einen einfachen Ausweg bietet die supervising-Methode, bei der ein Supervise-Prozess unmittelbar und sofort vom Ende eines als Kind laufenden Daemons vom Kernel informiert wird und diesen neu starten kann.

Die daemontools von DJB bieten Supervising von Prozessen. So sieht beispielhaft eine Prozesshierarchie mit einem supervised sshd aus:

/command/svscan /service/
 \_ supervise sshd-sv
    \_ /usr/sbin/sshd -D -p 8234 -o PidFile=/var/run/sshd.pid

Das von supervise gestartete Script sieht so aus:

#!/bin/sh
exec 2>&1
# don't respawn too fast
/bin/sleep 1
exec /usr/sbin/sshd -D -p 8234 -o PidFile=/var/run/sshd.pid \
     -o UseDNS=no

Da die supervise-Hierarchie über init mit Option "respawn" gestartet wird, ist somit auch der Restart von supervise selbst gesichert (beispielsweise bei den oben erwähnten Out-Of-Memory-Kills des Kernels). Bei SysV-init kann die Konfigurationszeile unmittelbar nach "si" (system init) eingetragen werden, so dass man sich bereits einloggen kann, während die Bootscripts noch gestartet werden. So sehen beispielhaft Konfigurationen für SysV-Init und Upstart aus:

# grep -B1 SV /etc/inittab 
si::sysinit:/sbin/rc sysinit
SV:2345:respawn:/command/svscanboot3
# cat /etc/init/daemontools.conf 
description     "DJB daemontools"
start on filesystem
stop on runlevel [06]
respawn
exec /command/svscanboot3
#

ssh mit supervising und ramfs

So zuverlässig sshd über supervise über svscan über ... init läuft, wenn das root-FS in Notfällen vom Kernel (oder von root per Magic Sysrq) RO-remountet wird, kann supervise keinen sshd mehr starten, da Schreibzugriff benötigt wird. Als einfacher Ausweg aus der Misere bietet sich hier ramfs an. Wenn supervise das run-Script gestartet hat, kann aber innerhalb des Scripts nicht einfach das ramfs gemountet werden, da dann mit svc über die control-Pipe nicht mehr supervise kontrolliert werden kann. Daher wird in dem folgenden run-Script nicht svc genutzt, sondern supervise direkt über ein echo in die control-Pipe beendet, damit ein "neues" supervise von svscan gestartet werden kann, das dann das ramfs im supervise-Verzeichnis nutzt.

#!/bin/sh

exec 2>&1

# don't respawn too fast
/bin/sleep 1

# if supervise is not a ramdisk try to mount it as ramdisk
grep -q sshd-sv.supervise /proc/mounts || {
  /bin/rm -rf supervise-nativefs
  mv supervise supervise-nativefs && {
    if mkdir -p supervise
    then
      if mount -t ramfs /dev/ram0 supervise
      then
        echo -e 'dx\c' >supervise-nativefs/control
      else
        rmdir supervise
        mv supervise-nativefs supervise
      fi
    else
      mv supervise-nativefs supervise
    fi
  }
}

exec /usr/sbin/sshd -D -p 8234 \
     -o PidFile=/var/run/sshd-sv.pid \
     -o UseDNS=no