Heimserver & Self-Hosting

etckeeper auf einem Debian-Heimserver - Eine lesbare Historie für /etc

etckeeper auf einem Debian-Heimserver - Eine lesbare Historie für /etc

Ein Debian-Server kann nach einer Konfigurationsänderung weiterlaufen und trotzdem eine unangenehme Frage für später hinterlassen: Was genau hat sich geändert? Vielleicht hat ein Upgrade eine Datei unter /etc verändert, ein Administrator hat eine Nginx-Site angepasst oder eine funktionierende Einstellung wurde bei der Fehlersuche ersetzt. Ein Backup kann Dateien wiederherstellen, liefert aber nicht automatisch eine lesbare Erklärung für jede kleine Änderung.

etckeeper behandelt dieses engere Problem, indem es /etc unter die Kontrolle eines Versionsverwaltungssystems stellt, üblicherweise Git. Dadurch kann die Konfigurationshistorie überprüfbar werden, und das Werkzeug kann sich in Paketoperationen integrieren. Das klingt einfach, doch /etc ist kein gewöhnliches Quellcodeverzeichnis: Es enthält Geheimnisse, aktive Diensteinstellungen, Informationen über Eigentümer sowie Dateien, deren falsche Wiederherstellung einen Rechner außer Betrieb setzen kann. Die nützliche Frage lautet deshalb nicht nur, wie etckeeper installiert wird, sondern wie sich seine Historie nutzen lässt, ohne ihm Aufgaben anzuvertrauen, die es nicht erfüllt.

Was etckeeper aufzeichnet

Git eignet sich gut dazu, Dateiinhalte aufzuzeichnen und Unterschiede zwischen Snapshots anzuzeigen. Es bewahrt jedoch normalerweise nicht jedes Detail zu Eigentümern, Berechtigungen oder leeren Verzeichnissen, das unter /etc wichtig ist. Die vorgelagerte etckeeper-README erläutert, dass etckeeper das Repository um Metadaten in /etc/.etckeeper ergänzt, die von einem Pre-Commit-Hook aktualisiert werden. Sie warnt außerdem vor speziellen Dateien, die ein gewöhnliches Versionsverwaltungssystem möglicherweise nicht darstellen kann.

Das Ergebnis lässt sich am besten als Konfigurationsjournal verstehen. Es kann Fragen wie diese beantworten:

  • Welche verfolgten Dateien unterscheiden sich vom letzten Commit?
  • Welche Zeilen wurden in einer Dienstkonfiguration geändert?
  • Hat eine Paketoperation Dateien unter /etc hinzugefügt, entfernt oder bearbeitet?
  • Welchen Inhalt hatte eine verfolgte Datei in einer früheren Revision?

Es kann nicht feststellen, ob eine Nginx-Direktive gültig ist, ob eine Firewall-Regel der beabsichtigten Richtlinie entspricht oder ob eine historische Konfiguration noch mit den heute installierten Paketen kompatibel ist. Eine Änderung aufzuzeichnen und eine Änderung zu verstehen sind zwei verschiedene Aufgaben.

Installieren und anschließend prüfen, statt anzunehmen

Unter Debian beginnt die Installation mit dem Paket der Distribution:

sudo apt update
sudo apt install etckeeper

Die vorgelagerte Dokumentation sagt, dass eine paketbasierte Installation das Repository wahrscheinlich automatisch initialisiert. „Wahrscheinlich“ ist wichtig: Paketierung und lokaler Zustand können sich unterscheiden. Eine Prüfung ist besser als eine Annahme.

sudo test -d /etc/.git && echo "Git repository present"
sudo git -C /etc status

Wenn kein Repository vorhanden ist, dokumentiert die Debian-Handbuchseite etckeeper(8) init als den Befehl, der das konfigurierte Versionsverwaltungssystem initialisiert:

sudo etckeeper init
sudo git -C /etc status

Der erste Statusbericht sollte nicht vorschnell übergangen werden. Zu prüfen ist, was verfolgt und was ignoriert wird sowie ob rechnerspezifische generierte Dateien ständig störende Änderungen erzeugen würden. Die offizielle Dokumentation zu Git status unterscheidet Änderungen im Arbeitsverzeichnis, im Index bereitgestellte Änderungen und nicht verfolgte Pfade. Diese Unterscheidung ist hier besonders nützlich, weil das Arbeitsverzeichnis die aktive Konfiguration und kein entbehrlicher Checkout ist.

etckeeper verwaltet einen Teil der Ignore-Datei und erlaubt lokale Regeln außerhalb seines verwalteten Blocks. Eine Datei zu ignorieren ist nicht nur eine Frage der Übersichtlichkeit. Wird eine Datei ausgeschlossen, erscheinen ihre künftigen Änderungen nicht in diesem Journal. Wurde sie bereits committet, entfernt eine neue Ignore-Regel den früheren Inhalt nicht aus der Git-Historie.

Ein bewusster Wartungsablauf

Ein kleiner Arbeitsablauf macht die Historie nützlicher als einen Stapel unerklärter Snapshots. Vor einer Bearbeitung sollte geprüft werden, ob bereits eine frühere Änderung wartet:

sudo git -C /etc status --short
sudo git -C /etc diff

status nennt die betroffenen Pfade; diff zeigt zeilenweise noch nicht bereitgestellte Änderungen. Die Pro-Git-Erklärung zum Aufzeichnen von Änderungen ist hier hilfreich: Ein Commit ist ein Snapshot des vorbereiteten Zustands, während nicht bereitgestellte und nicht verfolgte Inhalte Aufmerksamkeit erfordern. Ein sauberer Ausgangspunkt erleichtert es, den nächsten Diff mit der jeweiligen Wartungsaufgabe zu verbinden.

Nach der Änderung eines Dienstes sollte vor einem Reload oder Neustart dessen eigener Validierungsmechanismus verwendet werden. Nginx, OpenSSH, sudoers und andere Komponenten verwenden keinen gemeinsamen universellen Validator. Ein kopierter Befehl kann daher ihre aktuelle Dokumentation nicht ersetzen. etckeeper übernimmt diese semantische Prüfung nicht.

Anschließend wird der entstandene Diff geprüft und eine Nachricht aufgezeichnet, die den Zweck erklärt:

sudo git -C /etc diff
sudo etckeeper commit "Restrict example service to the LAN"
sudo git -C /etc status --short

Der Befehl etckeeper commit zeichnet alle von etckeeper verwalteten Änderungen auf. Das ist bequem, bedeutet aber auch, dass der Diff zuerst gelesen werden sollte. Eine unbeteiligte Passwortänderung, eine paketgenerierte Bearbeitung oder eine temporäre Datei sollte nicht unbemerkt in einem irreführend benannten Commit landen.

Kleine, zweckgebundene Commits erzeugen eine später lesbare Zeitleiste. „Restrict example service to the LAN“ vermittelt mehr als „update config“. Die Nachricht beweist dennoch nicht, dass die Änderung korrekt war; sie bewahrt den angegebenen Grund des Administrators und gibt dem Diff damit Kontext.

Was rund um APT geschieht

Die Integration in die Paketverwaltung ist ein Grund, etckeeper statt eines bloßen Git-Repositorys zu verwenden. Laut der vorgelagerten README und der Debian-Handbuchseite prüft der Pre-Install-Hook den Zustand vor Paketarbeiten, während der Post-Install-Hook interessante Dateien hinzufügt und von Paketen verursachte Änderungen committet. Dadurch lassen sich paketbedingte Bearbeitungen von späteren manuellen Arbeiten trennen.

Automatisierung ersetzt keine Überprüfung. Ein Paket-Commit zeigt, dass sich Dateien im Umfeld einer Installation oder eines Upgrades geändert haben. Er belegt weder, dass jeder Unterschied von einem einzigen Paket stammt, noch dass sich die neue Konfiguration wie gewünscht verhält. Auch die Planung zusätzlicher periodischer Commits kann vom installierten Paket und der lokalen Konfiguration abhängen. Ein verlässliches Modell sollte sich auf die tatsächlich sichtbare Repository-Historie und ausdrückliche manuelle Commits stützen, nicht auf einen angenommenen Timer.

Die Historie lässt sich mit gewöhnlichen Git-Befehlen durchsuchen:

sudo git -C /etc log --oneline --decorate -n 10
sudo git -C /etc show --stat HEAD
sudo git -C /etc show HEAD -- nginx/

Der letzte Befehl beschränkt den angezeigten Commit auf einen relativ zu /etc angegebenen Pfad. nginx/ wird durch den betreffenden verfolgten Pfad ersetzt. Einen gezielten Diff zu lesen ist normalerweise sicherer und informativer, als einen vollständigen Paket-Snapshot als ein unteilbares Ereignis zu behandeln.

Das Repository enthält sensible Daten

Dies ist die wichtigste Grenze. /etc kann Passwort-Hashes, private Schlüssel, Datenbankzugangsdaten, Token, WLAN-Geheimnisse und Material zur Zugriffskontrolle enthalten. Die vorgelagerte Sicherheitswarnung nennt /etc/shadow als offensichtliches Beispiel und erklärt, dass das gesamte .git-Verzeichnis geheim bleiben muss. Git speichert historische Objekte; den Zugriff auf die aktuelle Arbeitsdatei zu beschränken reicht nicht, wenn Repository-Objekte gelesen werden können.

etckeeper erstellt sein Repository mit eingeschränktem Zugriff. Dieser Schutz kann jedoch verloren gehen, wenn jemand es kopiert, klont, archiviert oder an einen anderen Ort pusht. Ein öffentliches oder breit geteiltes Git-Hosting ist deshalb kein geeigneter Standard-Remote. Jede entfernte Kopie benötigt ein ausdrücklich definiertes Bedrohungsmodell, vertrauenswürdigen Speicher, sicheren Transport, eingeschränkten Zugriff, Aufbewahrungsentscheidungen und einen getesteten Wiederherstellungsweg.

Daraus folgt noch etwas: Das Löschen eines Geheimnisses aus der aktuellen Datei entfernt frühere Kopien nicht aus der Historie. War ein Geheimnis für eine unbefugte Person zugänglich, ersetzt das Umschreiben der Git-Historie nicht seine Rotation. Eine Bereinigung der Historie kann die fortbestehende Offenlegung reduzieren, doch die Zugangsdaten müssen danach behandelt werden, wohin sie bereits kopiert worden sein könnten.

Historie ist kein Backup

Ein unter /etc/.git gespeichertes Repository befindet sich auf demselben System und gewöhnlich auf demselben Datenträger wie die aufgezeichneten Dateien. Datenträgerausfall, Dateisystemschaden, Diebstahl oder ein ausreichend privilegierter Angriff können beides entfernen oder verändern. Lokale Historie ist für Prüfungen und kleine Wiederherstellungsaufgaben wertvoll, aber für sich allein kein unabhängiges Backup.

Umgekehrt beantworten ein Backup und etckeeper unterschiedliche Fragen. Ein Backup soll Daten nach einem Verlust wiederherstellen. Eine lesbare Commit-Historie soll schrittweise Änderungen erklären. Es kann sinnvoll sein, beides zu verwenden, doch das sensible Repository benötigt mindestens dieselbe Sorgfalt wie die ursprünglichen Geheimnisse. „Irgendwohin pushen“ ist kein vollständiges Backup-Konzept.

Immer nur eine Sache wiederherstellen

Der verlockendste Wiederherstellungsbefehl ist oft der gefährlichste: eine alte Revision über das aktive /etc auszuchecken. Das vorgelagerte Tutorial warnt davor, dass Git direkt auf der Systemkonfiguration arbeitet, und empfiehlt, potenziell gefährliche Arbeiten in einem separaten Staging-Verzeichnis vorzunehmen. Ein umfassender Checkout kann unbeteiligte Dateien ersetzen, veraltete Einstellungen wiederbeleben oder alte Konfiguration mit heutigen Paketversionen vermischen.

Ein engerer Ansatz sucht zuerst die betreffende Revision und prüft eine einzelne Datei, ohne das Arbeitsverzeichnis zu verändern:

sudo git -C /etc log --oneline -- path/to/file
sudo git -C /etc diff <older-revision>..HEAD -- path/to/file
sudo git -C /etc show <older-revision>:path/to/file

Die offizielle Dokumentation zu Git show beschreibt, wie der Befehl Objekte einschließlich des reinen Inhalts von Blobs anzeigt. Die Ausgabe in eine nur für root zugängliche Staging-Datei umzuleiten kann sinnvoll sein, doch zunächst müssen Revision und Pfad bestätigt werden. Danach wird der historische Inhalt mit der aktiven Datei verglichen, bei Bedarf an aktuelle Software angepasst, mit dem dienstspezifischen Validator geprüft, bewusst installiert und in einem neuen Commit aufgezeichnet.

Das ist langsamer als ein ungeprüfter Checkout, und genau das ist ein Vorteil. Eine Wiederherstellung unter /etc sollte den Unterschied zwischen „diese Datei enthielt früher diese Bytes“ und „diese Bytes sind heute für den Server sicher“ bewahren.

Wann etckeeper zu viel oder nicht genug ist

Bei einer nahezu unveränderlichen Appliance mit reproduzierbaren Images und vollständig an anderer Stelle generierter Konfiguration kann ein aktives Git-Repository einen stärkeren Source-of-Truth-Ablauf doppeln. Auf einem Rechner mit vielen generierten Änderungen kann das Journal unübersichtlich werden, wenn Ignore-Regeln nicht sorgfältig gewählt werden.

Auf der anderen Seite ist etckeeper kein Konfigurationsmanagement. Es deklariert nicht den Sollzustand vieler Rechner, verteilt keine Änderungen, schützt Geheimnisse nicht von sich aus und beweist nicht, dass ein wiederhergestellter Server booten kann. Ebenso wenig ersetzt es Diensttests, Monitoring, Backups oder Wiederherstellungsübungen. Seine Stärke ist kleiner: Es gibt einem gewöhnlichen Server ein lesbares Gedächtnis für Konfigurationsänderungen.

Fazit

etckeeper kann aus „etwas hat sich unter /etc geändert“ eine Frage mit Belegen machen: einem Statusbericht, einem Diff, einer Commit-Nachricht und einer früheren Datei zur Prüfung. Das ist auf einem Heimserver gerade deshalb nützlich, weil sich mit der Zeit viele kleine manuelle und paketbedingte Änderungen ansammeln.

Dieselbe Historie verlangt Vorsicht. Sie enthält sensibles Material, liegt neben der aktiven Konfiguration und kann nicht entscheiden, ob eine alte Einstellung heute gültig ist. Das Repository sollte als geheim behandelt, unabhängige Backups sollten aufbewahrt, Änderungen mit dem betreffenden Dienst validiert und nur gezielt wiederhergestellt werden. Innerhalb dieser Grenzen ist etckeeper keine Undo-Schaltfläche, sondern eine klarere Aufzeichnung darüber, wie der Rechner seinen heutigen Zustand erreicht hat.

References