Ein bisschen was zu molly-guard

Diesen Beitrag schrieb ich 1 Jahr und 4 Monate zuvor; die nachfolgenden Ausführungen müssen heute weder genau so nach wie vor funktionieren, noch meiner heutigen Meinung entsprechen. Behalte das beim Lesen (und vor allem: beim Nachmachen!) bitte stets im Hinterkopf.

Geschätzte Lesezeit: 3 Minuten

„Originally a Plexiglas cover improvised for the Big Red Switch on an IBM 4341 mainframe after a programmer’s toddler daughter (named Molly) tripped it twice in one day.“

So jedenfalls definiert es Wiktionary: eine Art physischer Barriere, die Dinge vor unerwünschtem Kontakt schützt – und insbesondere eine Abschirmung, die das versehentliche Auslösen eines „roten Knopfes“ verhindert. So weit, so gut.

Wieso molly-guard?

In diesem Artikel soll es nun um das Paket molly-guard gehen, das beispielsweise in Debian 12 als Version 0.7.2 verfügbar ist. Es dient dazu, versehentliche Reboots von Servern über SSH-Verbindungen zu erschweren. Das könnte ja zum Beispiel passieren, wenn du mehrere SSH-Verbindungen parallel offen hast und den Befehl im falschen Terminal absetzt – zumal, wenn der Terminal-Fokus schon gesetzt wird, sobald sich der Mauszeiger darüber befindet.

Passiert ist mir das, klopfAufHolz, noch nie; ich fände es aber auch ganz zauberhaft, wenn das in Zukunft so bleiben würde. Denn im besten Falle verursacht so etwas maximal ein Augenrollen, versehentliche Reboots von Datenbank-, Storage- oder Virtualisierungssystemen tun in der Regel aber mehr weh…

Um genau solche Systeme vor genau solchem Unsinn zu schützen, kannst du das Paket molly-guard installieren.

apt install molly-guard

Wie funktioniert molly-guard?

molly-guard klemmt sich sozusagen vor die eigentlichen Befehle und führt jene Checks durch, die in /etc/molly-guard/run.d/ definiert sind. Und nur, wenn diese Checks erfolgreich durchlaufen werden, wird das eigentliche Kommando dann auch wirklich ausgeführt. Das funktioniert für die folgenden Aufrufe: coldreboot, halt, reboot, shutdown, poweroff, pm-hibernate, pm-suspend, pm-suspend-hybrid, welche in einem Debian 12 Symlinks zu /bin/systemctl darstellen.

Nach der Installation von molly-guard sind sie hingegen Symlinks zu /lib/molly-guard/molly-guard, einem Shell-Script.

$ which reboot
/sbin/reboot
$ file /sbin/reboot
/sbin/reboot: symbolic link to /lib/molly-guard/molly-guard

Ein typischer Ablauf ließe sich folgendermaßen skizzieren:

  • Das Kommando reboot triggert nun also die Ausführung von /lib/molly-guard/molly-guard.
  • Dadurch erkennt molly-guard die Ausführung über eine SSH-Verbindung, so dass es den Nutzer im Sinne der Verifizierung dieser Aktion dazu auffordert, den Hostnamen des Systems einzutippen.
  • Stimmt diese Nutzereingabe nun nicht mit der Angabe in /etc/hostname (beziehungsweise des FQDN, s.u.) überein, bricht der Vorgang ab, und der Server wird nicht rebootet.
  • Ist die Angabe hingegen korrekt, erfolgt nun die Ausführung von /lib/molly-guard/reboot, was seinerseits wiederum ein Symlink auf /bin/systemctl ist.

Gut zu wissen: --molly-guard-do-nothing zeigt dir jederzeit an, was ausgeführt werden würde, ohne es jedoch konkret zu tun – eine Art dry run, wenn du so willst.

$ reboot --molly-guard-do-nothing
I: demo mode; molly-guard will not do anything due to --molly-guard-do-nothing.
W: molly-guard: SSH session detected!
Please type in hostname of the machine to reboot: database1.stage.example.com
molly-guard: would run: /lib/molly-guard/reboot

Weitergehende Konfiguration von molly-guard

Die weitergehende Konfiguration erfolgt in /etc/molly-guard/rc:

  • ALWAYS_QUERY_HOSTNAME=true – Damit legst du fest, dass molly-guard immer den Hostnamen des Systems erfragt – auch dann, wenn keine SSH-Verbindung erkannt wurde.
  • USE_FQDN=true – Damit legst du fest, dass die Nutzereingabe immer aus dem vollen Namen des Hosts (FQDN) bestehen muss, also beispielsweise database1.stage.example.com und nicht nur database1.

Außerdem kannst du in /etc/molly-guard/messages.d eigene Nachrichten hinterlegen: erstellst du beispielsweise eine Datei /etc/molly-guard/messages.d/reboot, so wird deren Inhalt ausgegeben, sobald ein Nutzer das Kommando reboot eingibt. Analog kannst du für jedes der oben gelisteten Kommandos eine Message erzeugen. Und/oder du erzeugst eine /etc/molly-guard/messages.d/default: deren Inhalt wird für jene Befehle ausgegeben, für die es keine eigene Datei in messages.d gibt.

Und natürlich kannst du /etc/molly-guard/run.d um eigene Skripte und Checks erweitern – so, wie es in deiner Umgebung nötig und sinnvoll erscheint.

Wo funktioniert molly-guard bekanntermaßen nicht?

Es gibt Konstellationen, in denen molly-guard nicht wie erwartet funktionieren wird:

  • Wenn du sudo innerhalb eines screen oder umgekehrt ausführst: denn sudo schluckt die Variable SSH_CONNECTION, und screen erstellt ein neues PTY.
  • Wenn du dir das Terminalfenster deines Servers per X-Forwarding auf deinen lokalen Rechner holst.
  • Wenn du systemctl reboot, systemctl halt, systemctl poweroff ausführst: diese triggern die jeweilige Aktion direkt und umgehen dadurch molly-guard.

Was ist in automatisierten Umgebungen zu beachten?

Automatisierst du Tasks, beispielsweise durch die Nutzung von Configuration Management Tools, wirst du nun natürlich an eine Wand laufen: der Versuch, automatisiert einen Reboot zu initiieren, führt dann nämlich dazu, dass das System endlos auf eine Nutzereingabe warten wird. Schlimmstenfalls erfolgt dazu auch keine sinnvolle Ausgabe, sondern „es geht nur einfach nicht“.

Abhilfe schafft hier, falls möglich, die Pfade entsprechend zu korrigieren: lenkst du ein reboot direkt auf /lib/molly-guard/reboot, so umgeht dies sämtliche molly-guard-Logik und geht, wie oben ausgeführt, direkt auf systemctl. Für Ansible sieht ein Real-World-Schnipsel in meiner Rolle folgendermaßen aus:

- name: Reboot the server (if required)
  ansible.builtin.reboot:
    msg: "Reboot due to system upgrades initiated by Ansible!"
    boot_time_command: uptime | cut -d ',' -f 1,2
    reboot_timeout: 720
    search_paths: ['/lib/molly-guard', '/sbin']
  when: reboot_required_file.stat.exists == true or pve_kernel_upgrade == true
Hintergrundbild © Marianne Spiller · Alle Rechte vorbehalten

Hinterlasse einen Kommentar

Ich freue mich über jeden Kommentar, es sei denn, er ist blöd.
Deshalb sind die Kommentare auf dieser Seite auch generell moderiert.

(Nick)Name: (erforderlich)
E-Mail: (erforderlich, wird nicht veröffentlicht)
Website: (optional)