Beliebte Suchanfragen

Cloud Native

DevOps

IT-Security

Agile Methoden

Java

|
//

Sicherheitskopien von OpenShift Projekten

13.9.2018 | 6 Minuten Lesezeit

Dr. Jekylls Elixir verdankt seine Wirkung einer ‘unbekannten Verunreinigung’ des Rezepts. Dies führt dazu, dass Dr. Jekyll seine schwindenden Vorräte nicht auffrischen kann und so die Kontrolle über sein gefährliches Alter Ego verliert. Ähnlich kann es uns mit Konfigurationsfehlern ergehen. Oft ist es fast unmöglich zu erkennen, weshalb ein älterer, ohne große Sorgfalt erstellter Versionsstand funktioniert hat, während alle Bemühungen, ihn zu reproduzieren, fehlschlagen. Ich möchte zeigen, dass regelmäßige Sicherheitskopien uns an dieser Stelle weiterhelfen können.

Ich möchte zwischen zwei verschiedenen Ansätzen zu solchen Backups unterscheiden. Zum einen gibt es ein weiteres Fläschchen im Kühlschrank. Sein Inhalt gleicht dem des ursprünglichen Elixirs. Man kann es mit einem Datenbank Snapshot vergleichen. Zum anderen können wir uns einen Laborbericht zum Elixir vorstellen. Dieser stellt vermutlich unsere einzige Chance dar, die ‘unbekannte Verunreinigung’ zu identifizieren und nach Wunsch zu reproduzieren.

In vielen Fällen ist das Fläschchen im Kühlschrank dem Laborbericht vorzuziehen. Man kann sich darunter ein Backup der zentralen etcd Datenbank des Kubernetes Masters vorstellen. Ich möchte mich dennoch auf den Laborbericht konzentrieren. Unter Zeitdruck mag dieser wenig hilfreich erscheinen, aber er bietet eine detaillierte, visuell lesbare Perspektive auf einen Zeitpunkt, zu dem unser Dienst korrekt funktioniert hat.

Obwohl dieser Ansatz nur in Ausnahmefällen die Wiederherstellung eines ganzen Clusters ermöglicht, können wir ein Projekt unter die Lupe nehmen, seine Bestandteile isolieren und hoffentlich die fast unsichtbare Konfigurationseinstellung identifizieren, die den Unterschied zwischen einem erfolgreichen und einem fehgeschlagenen Deployment ausmacht.

Der Vorgang erfordert keine Datenbanksperre. Wir erstellen gültige, eingerückte JSON Objekte, keine Binärartefakte. Wir erzeugen eine gewisse Last, aber keine Unterbrechung.

Man könnte annehmen, dass Laborberichte nicht nötig sind, da unsere Infrastruktur komplett aus Quellcode aufgebaut wird. Alle wichtigen Details sind in Git abgelegt. Sollte da nicht das Rezept reichen? Komplette Übereinstimmung von Infrastuktur und Quellcode bleibt leider meist ein unerfüllter Wunsch. Wer kann behaupten, nie Feineinstellungen an Diensten vorzunehmen (ein Port hier, ein angepasster Health Check da); wer reißt regelmäßig die Cluster ab, um sie komplett neu aufzusetzen? Wir sind anfälliger für Dr. Jekylls Dilemma als wir annehmen.

Export der Projekte

Das Skript export_project.sh im Git Repository openshift/openshift-ansible-contrib stellt unseren Ausgangspunkt dar. Wir verwenden eine angepasste Version (s. Pull Request , inzwischen in Branch Master übernommen).

Eine Stärke der Kubernetes Objekt-Datenbank ist, dass einzelne Objekte als JSON/YAML serialisiert und mit gewöhnlichen Kommandozeilentools gefiltert werden können. Wir bestimmen zum einen, welche Objekte für uns interessant sind, und zum anderen, welche Eigenschaften ausgelassen werden können. So können wir gewöhnlich auf Verwaltungseigenschaften wie .status verzichten.

oc export wird in einer zukünftigen Version entfernt, also benutzen wir oc get -o json (nachbereitet mit jq) um unsere Objektdefinitionen zu exportieren. Pods sind ein gutes Beispiel. Die meisten Podeigenschaften sind für unsere Zwecke wertvoll, aber es gibt auch einige, die wegfallen können: Zusätzlich zur bereits erwähnten Eigenschaft .status filtern wir .metadata.uid, .metadata.selfLink, .metadata.resourceVersion, .metadata.creationTimestamp und .metadata.generation aus.

Hierbei kommt es zu einer gewissen Duplizierung von Eigenschaften. Wir sichern Pod und ReplicationController Definitionen, aber wir sichern außerdem Deploymentkonfigurationen. Wenn ein Objekt des Typs DeploymentConfiguration vorliegt, sind Pods und ReplicationController gewissermaßen redundant. Dennoch scheint es ratsam, alle drei Objekte aufzubewahren. Es ist nicht nötig, von einer bestimmten Deploymentsequenz auszugehen, und einzelne Objekteigenschaften (ein Healthcheck des Pods, zum Beispiel) könnten angepasst worden sein. Wir können die Möglichkeit einer unscheinbaren und dennoch entscheidenden Veränderung nicht ausschließen.

Ich möchte auch betonen, dass dieser Ansatz weder Images noch Applikationsdaten (ob in emptyDir Verzeichnissen oder persistent abgelegt) sichert. Er ergänzt Sicherheitskopien der etcd Datenbank und Dateisysteme, aber er kann sie nicht ersetzen.

Welche Veränderungen wurden am Skript vorgenommen? Der Pull Request adressiert drei Probleme: Der Exportprozess bricht nicht mehr ab wenn ein Ressourcentyp nicht erkannt wird. Er gibt lediglich eine Warnung aus. So können ältere OpenShift Versionen unterstützt werden. Ganz ähnlich fährt der Export fort wenn der Master Nutzern Zugriff auf einen Ressourcentyp verwehrt. Damit wird nicht-Admins die Nutzung des Skripts ermöglicht. Drittens gibt der Export stets gültiges JSON aus. Die ‘stacked JSON’ Ausgabe des Originals wird zwar von jq und auch oc unterstützt, aber es scheint für den Backupgebrauch zu riskant, sich darauf zu verlassen, dass wir zu einem späteren Zeitpunkt mit ungültigem JSON arbeiten können. python -m json.tool, zum Beispiel, erfordert gültiges JSON mit einem Rootelement und lehnt die Ausgabe des ursprünglichen Skripts ab. ‘Stacked JSON’ ist eine ausgezeichnete Wahl für die Übertragung von Zeitreihendaten wie Logeinträgen, aber nicht für Sicherheitskopien von JSON Objekten.

Automatisierte Backups

Jetzt können wir uns der Automatisierung widmen. Gehen wir von nächtlichen Projektbackups aus. Wir erstellen Exports für alle Projekte, komprimieren die Ausgabe, fügen einen Datumstempel hinzu und legen das Archiv in permanentem Speicher ab. Wenn das gelingt, rotieren wir die Archive indem wir alle Dateien löschen, die älter als eine Woche sind. Die Parameter (wann und wie oft der Export ausgeführt wird, die Vorhaltezeit, usw.) werden dem CronJob-Template bei der Erstellung mitgegeben.

Angenommen, wir haben das System eingerichtet und gestartet. Was genau geschieht im Projekt cluster-backup?

Abb. 1 Backup Dienst

Das nächtliche CronJob Objekt erstellt einen Pod, der das Skript project_export.sh für alle Projekte im Cluster ausführt. Auf dem Pod sind lediglich oc und jq installiert. Es mag praktisch erscheinen, diesem Pod die Wiederherstellung aus gezogenen Backups zu ermöglichen, aber wir sollten dieser Versuchung widerstehen, da dies sehr großzügigen Schreibzugriff auf den Cluster erfordern würde.

Der permanente Speicher ist mit Zugriffsmodus ReadWriteMany ausgestattet, so dass wir auch während eines laufenden Backups unsere Archive erreichen können. Dies geschieht mit Hilfe eines stets laufenden Pods, der sonst exakt dem kurzlebigen Pod des CronJobs entspricht:

$ oc project cluster-backup
$ POD=$(oc get po | grep Running | cut -d' ' -f1)
$ oc exec ${POD} -- ls -1 /openshift-backup
openshift-backup20180911.zip
openshift-backup20180912.zip
openshift-backup20180913.zip

Rollenkonzept

Der Aspekt Rechtevergabe ist entscheidend. Der technische User des Pods erhält cluster-reader Rechte und eine zusätzliche, für diesen Zweck erstellte Clusterrolle secret-reader. Ihre Definition ist folgende:

kind: ClusterRole
apiVersion: v1
metadata:
  name: ${NAME}-secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]

Das ist eine sehr mächtige Rolle insbesondere in Verbindung mit cluster-reader Privilegien. Die Hauptsache ist jedoch, dass es eine strikt lesende Rolle ist. Ein besonders wertvoller Aspekt von maßgeschneiderten Clusterrollen ist, dass sie uns davor bewahren, technische User mit cluster-admin Rechten zu versehen.

Unsere Sicherung der Projekte darf nicht an der Entscheidung scheitern, Ressourcen wie Secrets oder Routen auszuschließen. Man sollte auch nicht in die Verlegenheit kommen, Teile des Exportskripts auszukommentieren, nur damit das Backup durchläuft. Die Rechtevergabe erfolgt über die Definition des technischen Users. Jeder Ressourcentyp wird auf Verfügbarkeit und Zugriffsberechtigung geprüft. Exportiert wird nur das, was der technische User sehen kann.

Abb. 2 Rollenkonzept

Administratorzugang wird nur beim Erstellen des Projekts benötigt. Die Annahme ist, dass dies durch angemeldete (menschliche) Nutzer geschieht. Wie Abb. 2 zeigt, erhält der Pod, der die eigentliche Arbeit ausführt, ‘security context constraint restricted’ und ‘security context non-privileged’. Im wesentlichen hat der technische User des Pods lesenden Zugriff auf die etcd Datenbank und Schreibberechtigung für den permanenten Backup Speicher.

Wo fange ich an – und warum?

Um das Projekt aufzusetzen, reicht die folgende Eingabe:

$ git clone https://github.com/gerald1248/openshift-backup
$ make -C openshift-backup

Wer nicht auf den nächtlichen CronJob warten möchte, kann wie oben die Variable POD setzen und eine Sicherheitskopie aller Projekte erstellen:

$ oc exec ${POD} openshift-backup
Exporting 'rc' resources to myproject/rcs.json
Exporting 'rolebindings' resources to myproject/rolebindings.json
Skipped: list empty
Exporting 'serviceaccounts' resources to myproject/serviceaccounts.json
...
|

Beitrag teilen

Gefällt mir

0

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.