Normale Ansicht

Ältere BeiträgeMy-IT-Brain

Update 2025-01 zur Dokumentation für den Notfall

13. Januar 2025 um 06:00

Während ich den Jahresrückblick 2024 schrieb, wurde mir bewusst, dass ich das im April 2024 behandelte Thema Dokumentation für den Notfall bzw. das digitale Erbe immer noch nicht angegangen hatte. Dies ärgerte mich und so nutzte ich die Zeit zwischen den Jahren, um dies zu ändern.

Der Umschlag für „wichtige Passwörter“

Im ersten Schritt habe ich meine KeePassXC-Datenbank in eine CSV-Datei exportiert und die Zeilen gelöscht, die für meine Erben keine Bedeutung haben. Damit mir die CSV-Datei nicht abhanden kommt, habe ich diese bewusst nur in einem Verzeichnis auf meinem Laptop verarbeitet, das nicht synchronisiert wird und dessen Partition verschlüsselt ist.

Im Anschluss habe ich die CSV-Datei ausgedruckt und in einen Briefumschlag gesteckt. Der Umschlag wurde beschriftet, verklebt und an einem Ort deponiert, der nur meiner Frau und mir bekannt ist.

Kommen im Laufe der Zeit weitere wichtige Passwörter hinzu, wird dieser Prozess wiederholt und der vorhergehende Umschlag vernichtet.

Die IT-Notfalldokumentation

Jeder Systemadministrator schätzt eine gute Dokumentation. Kein Systemadministrator schreibt gerne Dokumentation.

Meinung des Autors

Da die Dokumentation allerdings nicht von allein entsteht, nahm ich mir vor, jeden Tag wenigstens 10 Minuten daran zu arbeiten. Ich öffnete also TeXstudio und tippte auf die Tasten. Die Aussicht, ein feines LaTeX-Dokument zu produzieren, welches in ein gut lesbares PDF mündet, motivierte mich zusätzlich. Einmal angefangen, ging es dann deutlich schneller, als zuerst gedacht und am 27. Dezember war die erste Fassung fertig.

Screenshot der ersten Seite des fertigen PDF

Die roten Rahmen in obigen Bild zeigen an, dass es sich um klickbare Links im PDF handelt. Im Ausdruck erscheinen diese nicht.

Das Dokument enthält Abbildungen der eingesetzten Hardware mit einer Standortbeschreibung, so dass man diese im Zweifel auch schnell findet. Informationen zu Vertrags-, Kundennummern, Online-Kundencentern und Einwahldaten gehören ebenfalls dazu. Ich habe mich bei der Frage, welche Informationen ich aufnehmen soll, daran orientiert, wonach ich gefragt habe, wenn ich bei Kunden vor Ort war und Probleme mit dem Internetzugang oder dem Netzwerk beheben sollte. Eine schematische Übersicht der Netzwerkinfrastruktur gehört natürlich auch dazu:

Schematische Darstellung der heimischen IT-Infrastruktur

Das ausgedruckte Dokument habe ich meiner Frau in die Hand gedrückt mit der Bitte um Korrektur und Meinung. Es gefällt ihr und Sie findet es gut, dieses für den Notfall zu haben.

Eine zu Hilfe gerufene IT-Fachkraft kann sich damit schnell einen Überblick verschaffen, was die Zeit zur Lösung eines etwaigen Problems deutlich verkürzen sollte.

Erkenntnisse

Der Aufwand ist geringer als gedacht

Einmal angefangen war die Dokumentation schnell erstellt. Ich habe nicht auf die Uhr geschaut. Doch habe ich, denke ich, nicht länger als drei Stunden daran gesessen. Mich zum Anfangen zu überwinden war schwer, danach lief es wie geschmiert.

Es kommen auch gar nicht viele Seiten zusammen, wenn man sich auf das Wesentliche beschränkt.

Diese Dokumentation ist nicht vollständig

Mir ist bewusst, dass diese Dokumentation nicht vollständig ist. Je länger ich darüber nachdenke, desto mehr Dinge werden mir einfallen, die ich noch aufnehmen möchte. Und das ist vollkommen in Ordnung.

Es ist gut, richtig und wichtig mit den wichtigsten Punkten zu beginnen. Weitere Abschnitte können im Laufe der Zeit ergänzt werden. Wartet bitte nicht, bis ihr glaubt, eine vollständige Gliederung vorliegen zu haben, bevor ihr mit dem Schreiben beginnt. Ich kann mir z.B. vorstellen, noch einen Abschnitt zum Multifuntionsgerät in unserem Netzwerk und zum Troubleshooting häufig auftretender Probleme zu ergänzen.

Mit der Verfügbarkeit steigt auch die Komplexität

Gibt es nur einen Internetanschluss, stellt man schnell fest, ob dieser funktioniert oder nicht. Hat man zwei Internetanschlüsse, die an einer Firewall in einer Failover-Gruppe zusammengeführt werden, wird es schwieriger, denn fällt ein Anschluss aus, merkt man es zuerst gar nicht, wenn der Failover funktioniert.

Kamen früher nur DNS, das WLAN und die ConnectBox in Verdacht, gesellt sich nun die OPNsense zum Kreis der Verdächtigen hinzu. Dies ist evtl. nicht für jeden Heimnetzwerkadministrator oder Laien sofort ersichtlich. Und auch nicht alle Kundendienst-Techniker von Internetdiensteanbietern sind mit der Konfiguration von professionellen Firewalls vertraut.

Mit der vorhandenen Notfalldokumentation und den darin enthaltenen Verweisen auf die OPNsense-Dokumentation kommt man im Notfall zurecht. Ich werde mir jedoch noch Gedanken machen, wie ich dies weiter verbessern kann.

Fazit

Die nun existierende IT-Dokumentation ist definitiv besser, als gar keine zu haben. Es ist keine Schritt-für-Schritt-Anleitung zur Dienst-/Zugangs-Wiederherstellung, bietet aber die wichtigsten Informationen, um sich selbst helfen zu können.

Die Informationen sind ausgedruckt auch dann verfügbar, wenn die gesamte IT ausfällt und z.B. das WLAN oder der Zugriff auf das Dokumenten-Management-System nicht verfügbar sind.

Ich habe ein gutes Gefühl, diese Doku im Schrank liegen zu haben.

Der My-IT-Brain Jahresrückblick 2024

30. Dezember 2024 um 06:00

Zum Jahresende möchte ich kurz zurückblicken und reflektieren, wie dieses Jahr für meinen kleinen Blog verlaufen ist.

Anzahl veröffentlichter Artikel

Behandelte Themen

Thematisch haben sich fast alle Artikel mit Freier Software und Open Source beschäftigt oder waren daran angelehnt. Wie auch in den vorangegangenen Jahren habe ich keine bewussten Themenschwerpunkte gesetzt, sonder über die Themen geschrieben, dich mich in der jeweiligen Zeit interessierten und mich beschäftigt haben.

Zu Beginn des Jahres hatte es mir das Thema IPv6 angetan, wozu vier Beiträge erschienen sind:

Das Thema begleitet mich auch weiterhin, jedoch gibt es bisher keine spannenden Neuigkeiten, die ich für berichtenswert halte. Ich fürchte, IPv6 wird sobald nicht die Weltherrschaft an sich reißen.

Ein Thema, welches mir sehr wichtig war und ist, ist die Dokumentation für den Notfall bzw. das digitale Erbe. Wie die Kommentare zu diesem Artikel bezeugen, bin ich nicht der Einzige, der sich darum Gedanken macht. Leider bin ich 2024 kaum damit vorangekommen und schiebe es weiter vor mir her. Dies ärgert mich etwas, da ich mir wünsche, mich für ein so wichtiges Thema besser aufraffen zu können.

In 2024 wurden wir auf allen Kanälen mit Künstlicher Intelligenz, Maschinellem Lernen und großen Sprachmodellen überflutet. Es fällt schon fast schwer noch irgendeine Anwendung oder ein Produkt ohne AI kaufen zu können. Abseits des Hypes habe ich mich ebenfalls mit dem Thema beschäftigt und zwei Beiträge ( [1] und [2]) dazu geschrieben. Ich bin überzeugt, dass die verschiedenen Spielarten der künstlichen Intelligenz unser Leben und unsere Art zu Arbeiten stark beeinflussen und verändern werden. Daher werde auch ich hier am Ball zu bleiben, um nicht von der laufenden Entwicklung abgehängt zu werden.

Fazit

Damit sind 2024 insgesamt 26 Artikel erschinen. Das sind 19 weniger als in 2023. Mein selbst gestecktes Ziel, jeden Monat mindestens zwei Artikel zu veröffentlichen habe ich ebenfalls nicht erreicht. Da dies mein Hobby ist und mir primär Freude bereiten soll, setze ich mich durch diese Zielverfehlung nicht unter Druck.

Das Jahr 2025 lasse ich ohne große Ziele und Bestrebungen auf diesen Blog zukommen. Nur eines ist sicher, ich werde meine Texte weiterhin selbst und ohne KI-Unterstützung schreiben. Denn damit würde ich mir nur selbst die Freude am Bloggen nehmen.

Ich freue mich, wenn ich auch 2025 wieder interessantes Wissen in meinen Texten mit euch teilen kann. Ich wünsche euch einen guten Rutsch ins Jahr 2025!

Meine privaten Arbeitsmittel 2024

16. Dezember 2024 um 06:00

Dies ist ein Update des Artikels aus dem letzten Jahr. Eine aktuelle Hardwareübersicht gibt es hier.

Smartphone

Als privates Mobiltelefon benutze ich seit 2022 ein Samsung Galaxy S22 mit einem Congstar-Tarif, welcher mich im Monat 10,- EUR kostet. Ich bin mit dem Gerät weiterhin zufrieden und plane, es in 2025 ebenfalls zu nutzen.

Im Folgenden führe ich einige von mir genutzte Apps auf, mit einer kurzen Erklärung, wofür ich diese verwende. Wo möglich verlinke ich in den F-Droid Store. Wo dies nicht möglich ist, führen diese in den Google Play Store.

Hier die am häufigsten verwendeten Apps zählen in alphabetischer Reihenfolge:

Zu den eher sporadisch genutzten Apps zählen in alphabetischer Reihenfolge:

Evtl. ist euch aufgefallen, dass eine prominente App in obiger Aufzählung fehlt. Tatsächlich widerstehe ich weiterhin dem sozialen Druck und verweigere mich der Nutzung von WhatsApp. Der Verzicht auf WhatsApp schnitt mich leider ausgerechner bei der Freiwilligen Feuerwehr von einem Teil der Kommunikation ab. Daher freue ich mich nun umso mehr, dass unsere Feuerwehr zur Planung von Dienstabenden, Veranstaltungen und sonstigen Terminen auf Spond (Google Play Store) umgestiegen ist.

Ich nutze auch Online-Banking-Apps auf dem Smartphone. ich nutze diese z.B., um am Laptop getätigte Überweisungen oder Online-Einkäufe zu autorisieren. Darüber hinaus schätze ich die Benachrichtigung über getätigte Umsätze.

Insgesamt sind aktuell 168 Apps installiert. Ehrlicherweise werde ich vermutlich erst ausmisten, wenn der Speicher knapp wird.

Ach ja, telefonieren tue ich damit natürlich auch. ;-)

Tablet

Seit Mitte 2019 [verwende ich] auch ein Samsung T830 Galaxy Tab S4 Wi-Fi Tablet. Durch seine 10,5 Zoll (ca. 27 cm) Bildschirmdiagonale, das geringe Gewicht und mit der App ReadEra eignet es sich hervorragend zum Lesen von PDF-Dateien und E-Books.

https://www.my-it-brain.de/wordpress/meine-privaten-arbeitsmittel-anfang-2022/

Darüber hinaus nutze ich das Gerät:

  • Für Online-Shopping (mehr als das Smartphone)
  • Lesen im Internet (Blogs, Dokus, etc.) mit Firefox Klar

Dabei verwende ich mehr oder weniger die gleichen Apps wie auf dem Smartphone. Für den Zugriff auf Mastodon verwende ich hier statt Fedilab die App Tusky (F-Droid).

Seit 2024 neu auf dem Tablet sind FeedMe (Google Play Store) und Wallabag (Google Play Store). FeedMe teste ich als Alternative zu Feedly (Google Play Store), da dieser die Synchronisierung mit meiner FreshRSS-Instanz unterstützt. Er ist etwas langsam, ansonsten zufriedenstellend. In Wallabag speichere ich Artikel, die ich später lesen oder für Workshops, Talks und Blog-Artikel nutzen möchte.

Laptop

  • Ich arbeite weiterhin mit einem Lenovo ThinkPad T14s (seit 2021)
  • Das Betriebssystem wurde im Laufe der Zeit von Fedora 37 auf Fedora 40 aktualisiert; Das Upgrade auf Fedora 41 folgt bald
  • Nach Rambox ist auch hamsket entsorgt worden, da mich diese Apps im Laufe der Zeit doch mehr genervt als unterstützt haben
    • Dienste wie Element, Mastodon, GMail, Slack, etc. nutze ich jetzt direkt im Webbrowser
    • Ich nutze die Funktion Tabs zu pinnen, um häufig verwendete Dienste im Browser im schnellen Zugriff zu haben

Der Laptop ist mein Hauptarbeitsmittel, den ich für so gut wie alle anfallenden Aufgaben verwende. Lediglich zum Lesen von E-Books bevorzuge ich das Tablet und zum Instant Messaging das Smartphone.

  • Mein Lieblingsbrowser ist Firefox
  • Mein Lieblingseditor ist Vim
  • Thunderbird ist die Anwendung meiner Wahl für Aufgaben, E-Mail und Kalender
  • TeXstudio ist mein Lieblings-LaTeX-Editor

Ich habe immer mal wieder Evolution ausprobiert, da dies eine bessere Integration in GNOME bietet. Doch bin ich nie damit warm geworden. Da ich mehrere E-Mail-Konten bei verschiedenen Anbietern sowie Kalender für verschiedene Zwecke habe, finde ich die Zusammenführung und Nutzung in Thunderbird ideal.

Desktop-/Server-PC

Mein ehemaliger Desktop-PC ist in ein 19-Zoll-Gehäuse und mit diesem in einen Serverschrank im Keller umgezogen. Die ganze Geschichte dazu kann in „Ein Serverschrank mit Kompromissen“ nachgelesen werden.

  • Ein Selbstbau mit RHEL dient mir als Libvirt/KVM-Hypervisor für virtuelle Maschinen

Auf diesem Rechner laufen dauerhaft zwei virtuelle Maschinen:

Als dauerhaft laufender Rechner führt dieser Host meine Cronjobs und Ansible-Playbooks aus, erzeugt Backups und kopiert/synchronisiert Daten von hier nach dort.

Die Untersützung von Podman bzw. der weiteren Container-Tools Buildah und Skopeo in RHEL ist super. Die kostenlose Developer Subscription for Individuals ermöglicht mir die produktive Nutzung von bis zu 16 RHEL-Servern. Das sind mehr als genug für meine privaten Zwecke.

Sonstige Geräte im Netzwerk

  • Mein Brother DCP-540CN wurde dieses Jahr nach 18 Jahren ausgemustert; ich nutze jetzt einen Brother MFC-J890DW im Haus mit, falls ich mal etwas drucken muss
  • Meine Synology Diskstation DS213air dient mir seit 2013 als Netzwerkspeicher (NAS)
    • Dient als Backup-Senke
    • Beheimatet Foto-, Video- und Musiksammlung
    • Stellt Netzlaufwerke für Windows und Linux bereit
    • Bietet aktuell 2,7 TB Speicherkapazität (2 Disks als RAID 1)
    • Externe USB-Festplatte (500 GB) für lokale Backups
    • Sie ist alt, aber verrichtet zuverlässig ihren Dienst
  • Neu seit diesem Jahr dabei ist eine Protectli VP2410 – 4 Port Intel ® CeleVP2410 – 4 Port Intel ® Celeron J4125ron J4125 mit OPNSense
    • Dieses Gerät lag seit 2023 ungenutzt herum, da sich die Anschaltung des Glasfaseranschlusses um ein Jahr verzögert hat; jetzt ist er in Betrieb
    • Die OPNSense wird in 2025 meinen Pi-Hole ablösen und den Zugang zum Internet über Dual-WAN bereitstellen

Cloud-Dienste

Hier hat es im laufenden Jahr keine Änderungen gegeben. Ich gehe davon aus, dass es hier in 2025 ebenfalls keine Änderungen geben wird. Drei neue Dienste sind hinzugekommen, die ich bei adminforge.de nutze. Dies sind:

  • DNSforge
  • Bandbreite messen
  • ToDo App
  • FreshRSS Reader
  • Linkwarden
  • Wallabag

Die letzten vier befinden sich noch in der Testphase. Ob die Nutzung in 2025 anhält, werdet ihr im nächsten Rückblick erfahren können.

Ich freue mich, wenn euch dieser kleine Überblick gefällt und ihr vielleicht die ein oder andere Inspiration darin findet. Ich freue mich auch, wenn ich in euren Blogs lesen kann, womit ihr 2024 so gearbeitet habt.

Wie kann ich die Dokumentation von docs.redhat.com am einfachsten als PDF herunterladen?

18. November 2024 um 05:00

Unter ‚http://docs.redhat.com‚ findet man gesammelt und sortiert Red Hats Dokumentation, z.B. zu Ansible Automation Platform, OpenShift, RHEL, RHV, Satellite, etc.

Neben der Online-Version im Single- und Multi-Page-Format kann man die einzelnen Texte auch als PDF herunterladen. Dies manuell zu tun, ist allerdings mühselig. Deutlich leichter geht es mit dem PDF Document Downloader von Kazuo Moriwaka. Es handelt sich dabei um ein Bash-Skript, bestehend aus awk, curl, grep, und parallel, welches als Argument die Basis-URL für eine Produktkategorie übernimmt und anschließend alle PDF-Dateien ermittelt und herunterlädt.

Klingt gut? So bekommt ihr das Skript:

  1. Ladet euch die aktuelle Version als Zip-Datei aus dem Gist herunter
  2. Entpackt das Zip-Archiv in ein Verzeichnis eurer Wahl, z.B. nach ~/bin/
  3. Macht das Skript ausführbar: chmod u+x ~/bin/fetchdoc.sh

Folgender Code-Block zeigt einige Beispiele, mit denen ich mir einen Teil der Dokumentation auf mein Laptop gezogen habe:

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10-beta

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.5

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_satellite/6.15

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_satellite/6.16

$ ~/bin/fetchdoc.sh https://docs.redhat.com/en/documentation/red_hat_virtualization/4.4

Thank you Kazuo Moriwaka for this awesome little helper!

Gedanken zur Release-Versionierung von Software-Projekten

28. Oktober 2024 um 05:00

Kürzlich habe ich auf Fryboyter diesen Artikel gelesen: Wie sollte man Veröffentlichungen versionieren?

Meine Gedanken zu dem Artikel und dem Thema möchte ich an dieser Stelle mit Fryboyter und euch teilen.

Fryboyter favorisiert nach eigener Darstellung Calendar Versioning (CalVer), da dies seiner Meinung nach aussagekräftiger ist, als z.B. 0.78.1, was sehr stark nach Semantic Versioning (SemVer) aussieht. Meiner Meinung nach kann man dies nicht pauschal sagen, da beide Versionsschemata ihre eigenen Vor- und Nachteile haben. Doch wann sollte man zu welchem Schema greifen?

Calendar Versioning

Die folgende Liste ist eine Übersetzung des englischen Textes, welcher hier zu finden ist. Wenn einer der in dieser Liste genannten Punkte auf ein Projekt zutrifft, scheint CalVer ein geeignetes Schema für die Versionierung zu sein.

  • Hat Ihr Projekt einen großen oder ständig wechselnden Umfang?
  • Große Systeme und Frameworks, wie Ubuntu und Twisted.
  • Amorphe Gruppen von Dienstprogrammen, wie Boltons.
  • Ist Ihr Projekt in irgendeiner Weise zeitkritisch? Beeinflussen externe Änderungen neue Projektveröffentlichungen?
  • Geschäftliche Anforderungen, wie Ubuntus Fokus auf Unterstützungstermine.
  • Sicherheitsupdates, wie certifi’s Notwendigkeit, Zertifikate zu aktualisieren.
  • Politische Veränderungen, wie die Handhabung von Zeitzonenänderungen durch die IANA-Datenbank.

Einige Betriebssysteme wie z.B. Ubuntu haben einen festen Veröffentlichungsrythmus und Unterstützungszeitraum. So werden Ubuntu LTS Versionen ohne Zusatzverträge für 5 Jahre unterstützt und mit Aktualisierungen versorgt. Bei Ubuntu 24.04 LTS kann man bereits am Namen erkennen, wie alt dieses Release ist und wie lange es mit Aktualisierungen versorgt wird. Ubuntu veröffentlicht Aktualisierungen für die enthaltenen Pakete in unregelmäßigen Abständen, meist sobald diese verfügbar sind. Aufgrund der vielen enthaltenen Pakete und der Aktualisierungsrichtlinie scheint SemVer (siehe nächster Abschnitt) hier nicht vorteilhaft zu sein.

Bei Debian 12, RHEL 9 oder SLES 15 erkennt man das Datum der Veröffentlichung hingegen nicht. Hier hilft nur ein Blick in die jeweilige Versionshistorie der Projekte, um Informationen über den Zeitpunkt der Veröffentlichung und der jeweiligen Unterstützungszeiträume zu finden.

Semantic Versioning

Auf Grundlage einer Versionsnummer von MAJOR.MINOR.PATCH werden die einzelnen Elemente folgendermaßen erhöht:
1. MAJOR wird erhöht, wenn API-inkompatible Änderungen veröffentlicht werden,
2. MINOR wird erhöht, wenn neue Funktionalitäten, die kompatibel zur bisherigen API sind, veröffentlicht werden, und
3. PATCH wird erhöht, wenn die Änderungen ausschließlich API-kompatible Bugfixes umfassen.

Quelle: https://semver.org/lang/de/

SemVer ist stringent, einfach nachzuvollziehen und bietet für mich als Systemadministrator die folgenden Vorteile.

Wird PATCH erhöht, weiß ich, dass lediglich Fehler behoben wurden, sich am Funktionsumfang einer Anwendung jedoch nichts ändert. Das Einzige, was mir hierbei den Tag vermiesen kann, sind Regressionen. Das Risiko, dass irgendetwas kaputtgeht oder schlimmer wird, ist jedoch gering.

Wird MINOR erhöht, weiß ich, dass die Anwendung neue Funktionalität enthält und ich weiß, dass nun ein genauerer Blick erforderlich ist, um zu entscheiden, ob diese Funktionalität in meiner Umgebung bereitgestellt werden soll bzw. darf. Gegebenenfalls sind vor einer Aktualisierung Anwenderschulungen durchzuführen und interne Prozessbeschreibungen zu aktualisieren, bevor die neue Version zur Nutzung freigegeben werden kann.

Einem an Featureritis erkrankter Nerd mag jede neue Funktion gefallen. Unzureichend geplante Veröffentlichungen neuer Funktionen in Unternehmen können hingegen interessante Folgen haben.

Wird MAJOR erhöht, ist ein Blick in die Release Notes angeraten. Denn man weiß schon mit einem Blick auf die Versionsnummer, dass diese Version Breaking Changes enthält. Dies können sein:

  • API-inkompatible Änderungen
  • Entfallene bzw. entfernte Funktionalität
  • Geänderte Architektur
  • Geändertes Format der Konfigurationsdatei(en)
  • etc.

Eine solche Aktualisierung kann man in aller Regel nicht ohne sorgfältige Planung installieren. Das Risiko, dass dabei etwas kaputtgeht und Stress und Produktionsausfall folgen ist einfach zu groß.

Aussagekraft

Fryboyter schreibt: „Zumal meiner Meinung nach 2024.10.11 aussagekräftiger als 0.78.1 ist.“

Aber ist es wirklich aussagekräftiger? Wenn ich nur das Datum sehe, weiß ich lediglich, wann die Version veröffentlicht wurde. Welchen Funktionsumfang die Version hat, welche Änderungen es zur vorhergehenden Version es gibt, ob diese Version stabil ist oder ob es die aktuellste Version ist, erkennt man nicht. Bei zwei Daten erkennt man zumindest, welches die aktuellere Version ist.

Sehe ich nur 0.78.1, weiß ich nicht, wann diese Version veröffentlicht wurde. Ich sehe jedoch auf den ersten Blick, dass sich diese Version in einer initialen Entwicklungsphase befindet, der Funktionsumfang nicht abschließend definiert ist und sich jederzeit ändern kann. Kurz gesagt, mit jeder weiteren Erhöhung von MINOR und PATCH ist damit zu rechnen, dass sich das Verhalten und der Funktionsumfang signifikant ändern. Da die einzelnen Elemente bei SemVer ausschließlich erhöht jedoch nie gesenkt werden, kann man bei Vorliegen von zwei Versionsnummern der gleichen Anwendung erkennen, welches die aktuellere ist. Details zu Änderungen gegenüber der Vorgängerversion verrät SemVer zwar auch nicht, doch kann ich den Umfang der Änderungen erkennen. Für mich besitzt SemVer damit in den meisten Fällen die größere Aussagekraft.

Die Frage wann es Zeit für Version 1.0.0 ist, beantwortet SemVer wie folgt:

Wenn die Software schon in der Produktion verwendet wird, sollte sie bereits in Version 1.0.0 vorliegen. Falls eine stable API existiert, auf die sich Nutzer bereits verlassen, sollte es ebenfalls die Version 1.0.0 sein. Auch wenn Kompatibilität zu vorherigen Versionen bereits eine wichtige Rolle spielt, ist Version 1.0.0 angebracht.

Quelle: https://semver.org/lang/de/#woher-wei%C3%9F-ich-wann-es-zeit-ist-version-100-zu-ver%C3%B6ffentlichen

Abschließende Bemerkung

Ich gehöre tendenziell eher zu Team SemVer und denke, dass dies eine höre Aussagekraft als CalVer besitzt.

Grundsätzlich halte ich es für sinnvoll und wichtig, wenn sich Entwickler bzw. Organisationen Gedanken machen, welches Versionsschema am besten zu ihrem Projekt passt.

Wie denkt ihr darüber? Hinterlasst doch gern einen Kommentar mit eurer Meinung oder veröffentlicht einen eigenen Text dazu in eurem Blog.

Buildah baut meine Container-Images

30. September 2024 um 05:00

Dieser Artikel gibt meine Motivation für den Bau von Container-Images und die Vorgehensweise wieder und zeigt, wie ich mit Buildah meine OCI-kompatiblen Container-Images erstelle.

Es handelt sich dabei mehr um einen Erfahrungsbericht als ein Tutorial und ich erhebe keinen Anspruch auf Vollständigkeit. Das behandelte Beispiel ist jedoch zum Einstieg und zur Nachahmung für all jene geeignet, die Container ausführen können und diese gerne ohne Verwendung von Containerfiles bauen möchten.

Motivation

Ich möchte die Ansible-Rollen aus meiner Collection tronde.nextcloud mit Molecule und Podman-Containern testen. Als Zielplattform für das Deployment der Nextcloud unterstütze ich zunächst Debian und RHEL.

Die Tests sollen verifizieren, dass Nextcloud im Container in einer rootless-Podman-Umgebung bereitgestellt werden kann. Da der Test unter Verwendung von Podman-Containern durchgeführt werden soll, müssen diese Container eine solche rootless-Podman-Umgebung bereitstellen.

Für RHEL 8 und RHEL 9 habe ich entsprechende Container-Images gefunden. Für Debian bin ich nicht fündig geworden und habe daher beschlossen, diese Container-Images selbst zu erstellen.

Buildah ist das Werkzeug meiner Wahl, da:

  • Container-Images damit interaktiv erstellt werden können,
  • die verwendeten Befehle am Ende in einem Bash-Skript gesammelt werden können,
  • sich damit sogar interaktive Abfragen mit Heredocs beantworten lassen,
  • man kein containerfile(5) benötigt und
  • ich das Werkzeug noch nicht kenne und es gerne kennenlernen möchte.

Für mich sind dies ausreichend Gründe, um mich kopfüber in ein neues Container-Projekt zu stürzen. Wer mehr über die Beziehung von Buildah zu Podman erfahren möchte, dem empfehle ich den englischsprachigen Artikel: Buildah and Podman Relationship von Tom Sweeney.

Mein Weg zum Image

Um rootless Podman in einem Container zum Laufen zu bekommen, habe ich mich an dem englischsprachigen Artikel How to use Podman inside of a container von Dan Walsh orientiert. Das Ergebnis findet ihr in meinem GitHub-Repo tronde/container-image-forge.

Die folgenden Code-Blöcke zeigen Auszüge aus dem Skript buildah_create_debian_bookworm_with_rootless_podman.sh (Commit 7634ed8). Die enthaltenen Befehle werden unter dem jeweiligen Code-Block erläutert. Alle Befehle werden als normaler Benutzer ohne Root-Rechte ausgeführt.

# Name of target container image
tctri=debian_rootless_podman

# Get a base image
ctr=$(buildah from --pull=newer docker://docker.io/library/debian:bookworm)
  • Die Variable tctri nimmt den Namen des Container-Images auf, welches ich erzeugen werde
  • Die Variable ctr nimmt den Namen des Containers auf, welcher durch den buildah-from(1)-Befehl erzeugt wird; mit diesem Container wird im Folgenden gearbeitet
  • Die Option --pull=newer sorgt dafür, dass das Image nur dann aus der angegebenen Registry heruntergeladen wird, wenn es aktueller als das evtl. lokal gespeicherte Image ist
buildah run -- $ctr apt -y update
buildah run -- $ctr apt -y upgrade
buildah run -- $ctr apt -y install podman fuse-overlayfs libvshadow-utils libcap2-bin ca-certificates
  • Mit buildah-run(1) werden Befehle innerhalb des Arbeits-Containers ausgeführt
  • Ich aktualisiere die im Basis-Image enthaltenen Pakte und
  • installiere die für rootless Podman benötigten Pakete
  • Das Paket ca-certificates wird benötigt, um später Container-Images aus einer Registry herunterladen zu können
buildah run -- $ctr useradd podman
buildah run -- $ctr sh -c "echo podman:1:999 > /etc/subuid"
buildah run -- $ctr sh -c "echo podman:1001:64535 >> /etc/subuid"
buildah run -- $ctr sh -c "echo podman:1:999 > /etc/subgid"
buildah run -- $ctr sh -c "echo podman:1001:64535 >> /etc/subgid"
buildah run -- $ctr setcap cap_setuid+epi /usr/bin/newuidmap
buildah run -- $ctr setcap cap_setgid+epi /usr/bin/newgidmap
  • Mit den hier dargestellten Befehlen wird der nicht-privilegierte Benutzer podman erstellt
  • Die IDs für /etc/sub[g,u]id habe ich mir aus dem ubi9/podman-Image abgeschaut
  • Die setcap-Befehle sind notwendig, um rootless Podman ausführen zu können; ich habe sie durch Internetrecherche und Trial-and-Error zusammengestellt
buildah config -v /var/lib/containers $ctr
buildah config -v /home/podman/.local/share/containers $ctr
  • Das Image wird in der Lage sein, rootful und rootless Podman auszuführen
  • Mit den beiden Befehlen werden die Volumes hinzugefügt, die Podman als Container Storage nutzt
    • Rootful Podman verwendet /var/lib/containers
    • Rootless Podman verwendet /home/podman/.local/share/containers
buildah run -- $ctr chown -R podman:podman /home/podman
buildah run -- $ctr sh -c "mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock"
buildah config --env _CONTAINERS_USERNS_CONFIGURED="" $ctr
  • Der Benutzer podman bekommt ein HOME-Verzeichnis
  • Ich erstelle die Verzeichnisse, die ich im Artikel [7] gefunden habe
  • Ich erstelle die Environment-Variable, die ich ebenfalls in genanntem Artikel [7] gefunden habe
buildah run -- $ctr apt -y reinstall uidmap
buildah run -- $ctr apt -y clean
buildah run -- $ctr rm -rf /var/lib/apt/lists/*
  • Aus mir nicht bekannter Ursache muss das Paket uidmap neu installiert werden, um ein UID/GID-Mapping sicherzustellen; dies scheint analog zur Neuinstallation der shadow-utils in Artikel [7] notwendig zu sein
  • Die beiden folgenden Befehle sollen den Paket-Cache aufräumen, um die Größe des resultierenden Images zu verkleinern, zeigen jedoch keinen sichtbaren Effekt
# Commit to an image
buildah commit --rm $ctr $tctri
# Alternative: Use this and add GPG fingerprint for image signing
# buildah commit --sign-by <fingerprint> --rm $ctr $tctri

# Tag the image just created
buildah tag $tctri $tctri:bookworm-$(date --iso)
  • Mit buildah-commit(1) wird der Inhalt des Arbeits-Containers $ctr in ein Container-Image namens $tctri geschrieben
  • Durch Angabe der Option --rm wird der Arbeits-Container entfernt
  • Die Kommentarzeile lässt erkennen, dass ich zukünftig beabsichtige, meine Images digital zu signieren
  • buildah-tag(1) fügt dem Image einen Tag mit Datumsstempel hinzu; siehe auch: Recommendations for tagging and versioning container images

Der Befehl buildah-commit(1) fügt dem neuen Image übrigens nur einen weiteren Layer hinzu, egal wie viele Befehle zuvor im Arbeits-Container ausgeführt wurden. Das erzeugte Image umfasst also die Layer des Basis-Image plus einen weiteren.

Zwischenfazit

An diesem Punkt habe ich ein Basis-Image ausgewählt, mithilfe von buildah zusätzliche Software installiert, einen Benutzer hinzugefügt und ein neues Image erzeugt.

Um den Build-Prozess zu automatisieren, habe ich die notwendigen Befehle in Bash-Skripte geschrieben und unter https://github.com/Tronde/container-image-forge abgelegt.

Die fertigen Images halte ich in der Registry https://quay.io/repository/rhn-support-jkastnin/debian_rootless_podman vor. Fühlt euch frei, diese für eigene Experimente zu benutzen, doch verwendet sie nur mit Vorsicht in Produktion. Ich erzeuge diese Images nur nach Bedarf neu, so dass die veröffentlichen Versionen veraltet und voller Sicherheitslücken sein können.

Validierung

Jetzt, wo die Images fertig sind, kann ich prüfen, ob sich rootless Podman darin auch wie gewünscht ausführen lässt.

Die Prozesse innerhalb des von meinem Container-Image instanziierten Containers laufen als Benutzer root. Um die Prozesse als Benutzer podman auszuführen, ist dies beim Aufruf von podman run explizit mit anzugeben. Der folgende Code-Block verdeutlicht dies und zeigt zugleich den ersten Fehler beim Versuch rootless Podman auszuführen.

]$ podman run --rm localhost/debian_rootless_podman:bookworm-2024-09-21 id
uid=0(root) gid=0(root) groups=0(root)
]$ podman run --rm --user podman localhost/debian_rootless_podman:bookworm-2024-09-21 id
uid=1000(podman) gid=1000(podman) groups=1000(podman)
]$ podman run --rm --security-opt label=disable --user podman --device /dev/fuse localhost/debian_rootless_podman:bookworm-2024-09-21 podman info
time="2024-09-21T18:43:35Z" level=error msg="running `/usr/bin/newuidmap 15 0 1000 1 1 1 999 1000 1001 64535`: newuidmap: write to uid_map failed: Operation not permitted\n"
Error: cannot set up namespace using "/usr/bin/newuidmap": exit status 1

Der Fehler deutet auf fehlende capabilities(7) hin. Um diese Hypothese zu testen, wiederhole ich den letzten Befehl mit der Option --privileged (siehe dazu podman-run(1)):

]$ podman run --rm --security-opt label=disable --user podman --device /dev/fuse --privileged localhost/debian_rootless_podman:bookworm-2024-09-21 podman info
host:
…

Damit funktioniert es. Leider geben sich viele Menschen an dieser Stelle mit dem Ergebnis zufrieden. Doch ich möchte diese Container nicht einfach mit --privileged ausführen. Also studiere ich die Manpage capabilities(7) und teste mich Stück für Stück heran, bis ich mit dem folgenden Kommando ebenfalls erfolgreich bin:

]$ podman run  --rm --user podman --security-opt label=disable --device /dev/fuse --cap-add=setuid,setgid,sys_admin,chown localhost/debian_rootless_podman:bookworm-2024-09-21 podman info
host:
…

Dies ist schon deutlich besser, da dem Container hiermit deutlich weniger Privilegien eingeräumt werden müssen. Das Thema Container-Privilegien und capabilities(7) werde ich noch genauer untersuchen. Eventuell folgt dazu dann auch ein weiterer Artikel. Für den Moment ist das Ergebnis gut genug.

Quellen und weiterführende Links

  1. Buildah.io
  2. Ansible Collection tronde.nextcloud
  3. Mein Wochenendprojekt Nextcloud im Container
  4. Podman Images im Red Hat Catalog
  5. Buildah and Podman Relationship von Tom Sweeney
  6. About Ansible Molecule
  7. How to use Podman inside of a container by Dan Walsh
  8. Using podman containers
  9. Having trouble getting started with rootless podman running rootless podman inside a Debian 12 image #23838
  10. Recommendations for tagging and versioning container images

Kommentar zum 2024 State of Open Source Report

16. September 2024 um 05:00

In meinem heutigen Beitrag kommentiere ich den 2024 State of Open Source Report und vergleiche die enthaltenen Ergebnisse mit meinen persönlichen Erfahrungen.

Der 2024 State of Open Source Report (im Folgenden auch als Bericht oder Report bezeichnet) wurde von der Firma OpenLogic in Zusammenarbeit mit der Open Source Initiative (OSI) und der Eclipse Foundation erstellt. Der Bericht kann hier als PDF kostenlos heruntergeladen werden (der Haken für den Empfang von Kommunikation muss nicht gesetzt werden). Ich werde in diesem Text häufig auf den Bericht als Quelle verweisen, sodass ich euch empfehle, den Report ebenfalls verfügbar und im besten Fall gelesen zu haben. Seitenangaben beziehen sich auf das PDF mit dem Bericht.

Transparenzhinweis: Ich arbeite als Technical Account Manager für die Firma Red Hat. Meine Arbeit beeinflusst meinen Blick auf den Bericht. Dieser Kommentar stellt ausschließlich meine persönliche Sicht dar.

Informationen zum Bericht

Im Zeitraum vom 10. Oktober bis 8. November 2023 wurde weltweit eine anonyme Umfrage durchgeführt, welche insgesamt 2046 Antworten erhielt (siehe S. 4-6). Es findet sich darin kein Hinweis, ob die Umfrage repräsentativ ist. Es werden jedoch Angaben darüber gemacht, aus welcher Weltregion, Unternehmensgröße und Job-Rolle die Antworten stammen, um diese einordnen zu können.

Nutzung und Verbreitung von Open Source in Unternehmen

Es freut mich zu lesen, dass 95 Prozent der Antworten belegen, dass der Anteil an Open Source in den an der Umfrage teilnehmenden Unternehmen gestiegen (67,57 %) oder gleichgeblieben (27 %) ist (siehe S. 7). Auffällig ist allerdings auch, dass im Mittleren Osten 22,22% angaben, dass der Einsatz von Open Source zurückgegangen ist. Unternehmen, die gar keine Open-Source-Software einsetzen, haben vermutlich nicht an der Umfrage teilgenommen. Der Bericht macht dazu keine Aussage.

Auf Seite 8 findet sich die Aussage, dass 40 % aus der C-Level-Abteilung (z.B. CEO, CTO, CIO, CFO, etc.) angegeben haben, dass der Anteil an Open Source gleichgeblieben ist, während über 60% der Teilnehmer aus technischen Rollen eine Zunahme von Open Source sehen. Laut Bericht deutet dies auf eine mögliche Entfernung bzw. Trennung der Führung von der Basis hin. Dieser Ansicht mag ich mich nicht anschließen, da immerhin 58,46% der Führungskräfte ebenfalls eine Zunahme von Open Source in ihren Unternehmen sehen; das ist von den 60% der technischen Rollen doch nun wirklich nicht weit weg.

Interessant finde ich die genannten Gründe für den Einsatz von Open Source in Unternehmen (siehe S. 9-10). Ein wenig betrübt es mich, dass knapp 37 % „Keine Lizenzkosten“ und „Kostenminimierung“ als wichtigstes Argument für den Einsatz von Open Source nannten; hat Open Source in meinen Augen doch so viel mehr zu bieten, während sich das Ziel der Kostenminimierung nicht in jedem Fall erreichen lässt.

Meiner persönlichen Erfahrung nach verschieben sich die Aufwände in vielen Fällen lediglich. So stellten einige Organisationen fest, dass der Einsatz kostenlos verfügbarer Open-Source-Software mit einem höheren Personalbedarf bzw. einem erhöhten Aufwand für Wissensaufbau und Fehleranalysekompetenz einhergeht. Hier finden sich zum Teil die Kosten wieder, die man zuvor für Lizenzen und externen Support aufgewendet hat. Es gibt hier keine pauschal gültige Empfehlung. Jedes Unternehmen muss für sich selbst bewerten, ob es das erforderliche Personal selbst aufbauen bzw. einstellen kann oder ob der Einkauf externer Unterstützung in Zeiten von Fachkräftemangel nicht doch günstiger ist.

Macht man sich von externem Wissen abhängig, läuft dies dem Ziel entgegen, sich mit Open Source unabhängiger von einzelnen Herstellern machen zu wollen. Hier ist darauf zu achten, wie viel Auswahl an Anbietern am Markt besteht.

Ich nehme allerdings ebenfalls wahr, dass die wirtschaftliche Situation in vielen Unternehmen angespannt ist und kann das Ziel, Kosten zu reduzieren, nachvollziehen. Ich hoffe darauf, dass Unternehmen, die Open Source zur Kostensenkung einführen, auch die weiteren Vorteile, wie z.B. die Vermeidung von Vendor Lock-ins sowie offene Standards und Interoperabilität erkennen und zu schätzen lernen. Die zuletzt genannten Punkte sind immerhin 21 % der Befragten heute schon wichtig.

Herausforderungen beim Einsatz von Open Source

Wie bereits im vorangegangenen Abschnitt erwähnt, ist für den Einsatz von Open Source die Verfügbarkeit des notwendigen Wissens und entsprechende Fertigkeiten notwendig. Immerhin 38 % der befragten Unternehmen sehen es als eine Herausforderung an, das notwendige Wissen und die Fähigkeiten zum effizienten Einsatz von Open Source im Unternehmen verfügbar zu machen (S. 13). Dabei versuchen sie, dies auf unterschiedlichen Wegen verfügbar zu machen. Das Diagramm auf Seite 14 zeigt, dass die Mehrheit mit 45% auf Training des eigenen Personals setzt. Weitere 38% versuchen, Personal mit dem benötigten Wissen einzustellen.

Ich arbeite aktuell selbst in einem Unternehmen, in dem die Fort- und Weiterbildung der eigenen Mitarbeiter einen hohen Stellenwert besitzt. Ich freue mich sehr, dass mein Unternehmen mich aktiv dabei unterstützt, mein Wissen aktuell zu halten und in verschiedenen Bereichen auszubauen.

Ohne einen Beleg zur Hand zu haben, meine ich mich zu erinnern, dass die Qualifizierung bestehenden Personals für ein Unternehmen häufig günstiger ist, als neues Personal einstellen und einarbeiten zu müssen. Falls ihr dazu eine gute Quelle habt, teilt sie mir doch bitte in den Kommentaren mit.

Updates und Patches

Auf Seite 13 des Berichts findet sich die Aussage, dass es für 40 % aller Umfrageteilnehmer eine große bis sehr große Herausforderung darstellt, die Systeme und Anwendungen auf einem aktuellen Stand (Patchlevel) zu halten.

Nach meiner Erfahrung zählen ein geringer Automatisierungsgrad, unzureichende Testprozeduren und eine zu starre Aufbauorganisation mit komplizierten und langwierigen Abstimmungsprozessen zu den größten Problemen in diesem Bereich. Wenn Wartungsfenster zur Installation von (Sicherheits-)Updates mit 3-6 Monaten Vorlauf angekündigt und geplant werden müssen und es keinen Prozess für schnelle Notfallupdates gibt, kann man halt nicht innerhalb von 72 Stunden reagieren und Schwachstellen schließen. Wenn die Kommunikation zwischen Betriebs- und Anwendungs-Team rein über Ticketsystem läuft, hat man zwar einen sauberen Prozessablauf mit Genehmigungs- und Prüfschritten; werden die Schritte jedoch alle manuell ausgeführt, darf man sich nicht wundern, wenn Updates vier Tage statt vier Stunden brauchen.

Noch immer begegnen mir im Gespräch Szenarien, wo Anwendungsteams nicht über Testsysteme und Testpläne verfügen. Die Folgen eines Updates/Patches lassen sich nur direkt in Produktionsumgebung prüfen. Bei Fehlern kommt es dann sofort zu einer Beeinträchtigung des Dienstes und der Stresslevel steigt. Wo es bereits an der Fähigkeit mangelt, Änderungen zeitnah zu verifizieren, fehlt oft auch die Möglichkeit, auf einen zuletzt als funktionierend bekannten Stand zurückzurollen. Hier bleibt nur der Weg voran unter Einsatz aller verfügbaren Ressourcen, bis das Problem behoben oder das Unternehmen insolvent ist.

Nicht immer ist es ganz so dramatisch. Häufig löst mangelnde Automation einen langwierigen Abstimmungsprozess aus. Viele Personen müssen Zeit einplanen, um diverse Schritte im Prozessablauf manuell auszuführen, zu testen und zu dokumentieren. Schnell sind 3,6 kg Excel-Dateien erstellt, das Update aber immer noch nicht abgeschlossen.

Ich erinnere mich an die schöne Zeit zwischen 2011 und 2014. Unser damaliger stellvertretender Abteilungsleiter hatte die Idee, DevOps auszuprobieren. Dazu wurden Teams aus Entwicklern und Systemadministratoren gebildet, die nun gemeinsam für den Betrieb und die Verfügbarkeit bestimmter Anwendungen verantwortlich waren. Statt den auf Papier dokumentierten Verantwortungsübergängen und dem daraus häufig folgenden Hin- und Herschiebens des schwarzen Peters saßen wir jetzt gemeinsam in einem Boot und hatten gemeinsame Ziele. Wir lernten dabei die Sicht- und Arbeitsweise der jeweils anderen Job-Rolle kennen und zu verstehen. Und im gemeinsamen Dialog, gelang es uns Automationsprozesse zu entwickeln, um Updates schneller und erfolgreicher durchführen zu können. Leider überlebte dieses Modell die Zeit nicht. Heute ist mir bekannt, dass mit dem Wechsel dieses Modells auch die alten Probleme zurückkehrten und deutlich weniger Updates durchgeführt werden.

Oft liegt die Verantwortung für die Installation von Updates/Patches beim Betrieb. Jedoch ist nur das Anwendungsteam in der Lage, die korrekte Funktionsfähigkeit der Anwendung/des Dienstes zu beurteilen. Auch wenn manche Abteilungsleiter es nicht gerne hören, es geht am besten gemeinsam, mit kurzen Abstimmungswegen über Team- und Abteilungsgrenzen hinweg.

Der zweite Schlüssel zum Erfolg ist Automation. Lasst den Automaten die einzelnen Prozessschritte ausführen, welche in der Regel wie folgt aussehen:

  1. Anwendung bzw. Dienste stoppen
  2. Updates/Patches installieren
  3. System neu starten
  4. Anwendung bzw. Dienste starten
  5. Anwendung/Dienst auf korrekte Ausführung testen
  6. Bei Fehlschlag –> Rollback bzw. bei Erfolg –> Update erfolgreich

Zeit und Energie, die hier investiert werden, zahlen sich in aktuellen Systemen mit weniger Sicherheitslücken aus. Schafft einen Raum, in dem sich eure Experten aus Systemadministration und Anwendungsentwicklung austauschen und abstimmen können.

Selbstverständlich haben die Qualität der vom Hersteller bereitgestellten Updates ebenfalls einen großen Einfluss auf den Erfolg von Patchinstallationen. Sollte es hier wiederholt Probleme geben und keine Besserung in Sicht sein, ist ggf. ein Wechsel des Anbieters in Erwägung zu ziehen. Doch bevor ihr euch Hals über Kopf in die Migration stürzt, denkt daran, dass das Gras auf der anderen Wiese stets grüner wirkt, als es ist. Es geht nicht ohne ausführliche Tests.

Ich wünsche allen, die sich für Updates und Patches Nächte und Wochenenden um die Ohren schlagen müssen, dass sich die Situation für euch bessert und sich dies im nächsten Open Source Statusbericht ablesen lässt.

Wartung von End-of-Life Versionen

Manche nennen es den Giftschrank, andere die Schmuddelecke. Gemeint sind damit Betriebssystem-Releases und Anwendungen, die das Ende ihres Lebenszyklus erreicht oder schon überschritten haben. Laut Seite 13 des Berichts ist dies für 42 % der Umfrageteilnehmer ein Thema.

Die Gründe warum diese Systeme noch existieren, lauten häufig sehr ähnlich. Fast immer läuft eine geschäftskritische Anwendung darauf,

  • Von der im Unternehmen niemand mehr weiß, wie sie funktioniert, um sie auf ein neues Betriebssystem zu migrieren
  • Für deren Migration keine Ressourcen verfügbar sind
  • Mit der komplizierte und langwierige Abstimmungsprozesse zur Migration verbunden sind; niemand will das Ding anfassen
  • Die für keine aktuellere Betriebssystem-Version zertifiziert ist

Im hier kommentierten Bericht wird auf Seite 15 ausgewiesen, dass 22 % der Befragten noch CentOS einsetzten, dessen Release 7 seit dem 30. Juni 2024 End-of-Life (EoL) ist. In der Umfrage kommt es sogar auf Platz 3 der am häufigsten eingesetzten Distributionen.

Egal ob man nun EoL-Betriebssysteme oder EoL-Laufzeitumgebungen betrachtet, die Lösung ist stets dieselbe. Die dazugehörige Anwendung muss zuerst auf einer neueren und unterstützten Version laufen, bevor die alte abgeschaltet werden kann. Dazu müssen Teams in der Lage sein, Anwendungen neu deployen und das Deployment testen zu können. Auch hier helfen Testsysteme, -prozeduren und Automation. Auch hierbei ist es unerlässlich, dass Betrieb und Anwendungsteams zusammenarbeiten, um den Erfolg der Migration sicherzustellen. Je schneller Feedback-Loops und Abstimmungsprozesse sind, desto schneller sind notwendige Prozeduren etabliert. Die Zeit für Releasewechsel lässt sich so signifikant verkürzen. Ressourcen sind damit schneller frei und können für innovative Entwicklungsprojekte genutzt werden.

Leider erlebe ich häufig, dass Abteilungen nur in ihrem eigenen Bereich nach Lösungen suchen und den Kontakt zu anderen Abteilungen meiden, ja beinahe scheuen. Doch ist dies kein technisches Problem. Es ist eine organisatorische Herausforderung, die angegangen werden muss. Es liegt doch im Interesse aller Beteiligten, regelmäßig wiederkehrende Releasewechsel schnell und störungsarm abwickeln zu können.

In meinem beruflichen Alltag erlebe ich häufig, dass In-Place-Upgrades als Allheilmittel angesehen werden. Ich hingegen bin kein großer Freund davon. Sie sind der vermeintlich einfache Weg, doch führen sie zur dunklen Seite der Macht. Ein In-Place-Upgrade aktualisiert das Betriebssystem inkl. der installierten Bibliotheken und Laufzeitumgebungen. Es befreit nicht von der obligatorischen Aufgabe, die darauf laufenden Anwendungen im Anschluss zu testen. Stellt man dabei Fehler fest, gibt es häufig kein Zurück mehr. Eine Ausnahme bilden hier virtuelle Umgebungen, bei denen man zuvor einen Snapshot der virtuellen Maschine erstellen kann.

Wer eine Anwendung immer nur mit In-Place-Upgrades von einem Release auf das nächste rettet, verliert mit einer größeren Wahrscheinlichkeit die Fähigkeit, die Anwendung sauber neu zu deployen. Man tut sich hiermit keinen Gefallen.

Ich bin der Überzeugung, dass Organisationen in der Lage sein müssen, ihre geschäftskritischen Anwendungen mit einem definierten Zustand automatisiert ausrollen zu können. Dies unterstützt Releasewechsel, erleichtert den Auf- und Abbau von Testumgebungen sowie die Verifizierung von Fehlern und das Nachstellen von Bugs. Anwendungen können so auch deutlich leichter und schneller gegen neuen Bibliotheken und Laufzeitumgebungen getestet werden. Es lohnt sich, Zeit zum Schärfen der Axt zu investieren, bevor man mit dem Fällen der Bäume beginnt. Oder anders ausgedrückt, wer keine Zeit hat, den Zaun zu reparieren, weil er mit Kühe einfangen beschäftigt ist, wird nie zum Melken kommen.

Open Source Distributionen

In dieser Kategorie auf Seite 15 listet der Bericht die Linux-Distributionen auf, die von den Umfrageteilnehmern verwendet werden. Ubuntu führt diese Liste an und liegt mit 46 % vor Debian mit 23%. Platz 3 geht an CentOS mit 22%. Den undankbaren vierten Platz belegt Amazon Linux mit knapp 20%. Die noch recht neue Distribution CentOS Stream findet sich auf Platz 13 mit 9,5%.

Ich habe diese Werte mit denen aus dem State of Open Source Report von 2023 verglichen. Ubuntu hat im Vergleich um 27 % zugelegt (Platz 1 mit 29% in 2023). Debian kam 2023 mit 16,63% auf Platz 6 hinter CentOS Stream mit 16,74%. Die Plätze 2 und 3 wurden 2023 von Alpine Linux (21,1%) und Oracle Linux (19,72%) belegt. CentOS kam damals mit 15% auf Platz 8.

Der Bericht von 2024 spekuliert, dass Red Hat’s Änderung beim Zugriff auf den RHEL Quelltext und das EoL von CentOS mitverantwortlich für diese Veränderungen sind, kann jedoch keine klaren Belege dafür liefern. Laut Bericht sind die Linux Wars noch nicht entschieden und wir können auf den kommenden Bericht gespannt sein.

Es hat mich überrascht, dass RHEL und SLES es gar nicht in das Ranking geschafft haben. Unter Berücksichtigung, dass die Kostenreduktion in diesem Bericht die Hauptmotivation für den Einsatz von Open Source darstellt, lässt sich ggf. erklären, warum Distributionen gerade nicht hoch im Kurs stehen, die kostenpflichtige Support-Subskriptionen für den produktiven Einsatz voraussetzen.

Ich freue mich schon darauf, herauszufinden, wie dieses Ranking im nächsten Bericht aussieht.

Cloud-Native Open Source Technologies

Das Diagramm auf Seite 17 zeigt das Ranking der wichtigsten Cloud-Native Open Source Technologies für die Umfrageteilnehmer. Platz 1 wird von Docker mit 44,6 % eingenommen, gefolgt von Kubernetes mit 33,61 %.

Der große Vorsprung von Docker vor Podman mit 16,6 % hat mich ein wenig überrascht. Ich hätte den Abstand nicht als so groß eingeschätzt. Hier interessiert mich, welche Vorteile die Nutzer in Docker gegenüber Podman sehen. Leider macht der Bericht hierzu keine Aussage. Ich selbst nutze Podman unter Debian, Fedora und RHEL. In Debian stehen ungünstigerweise nur ältere Podman Releases zur Verfügung, denen wichtige Funktionen fehlen. Dies ist in meinen Augen eine Erklärung, warum Podman gerade in diesen Distributionen wenig genutzt wird. Dies ist allerdings nur wilde Spekulation meinerseits. Ich kann dies nicht belegen.

Für mich ebenfalls unerwartet ist OpenStack mit knapp 18 % sowie OKD und Rancher mit jeweils unter 10%. In diesem Bereich leide ich vermutlich an Betriebsblindheit. Wenn man bei Red Hat arbeitet, kann man leicht den Eindruck gewinnen, dass die ganze Welt nur noch OpenShift macht.

Ich freue mich darauf, diese Kategorie über die nächsten Jahre zu beobachten und zu sehen, wie sich Podman entwickelt, wofür ich eine gewisse Vorliebe habe.

Automations- und Konfigurations-Management

Wer die Kategorie Ansible in diesem Blog kennt, weiß bereits, dass ich mich gerne mit Ansible beschäftige. So freut es mich zu sehen, dass Ansible im betrachteten Bericht auf Seite 25 Platz 1 mit 30% belegt. Überraschend finde ich hingegen, dass 27% angaben, keinerlei Open Source Automations- bzw. Konfigurationsmanagement zu verwenden. Der Bericht führt dies auf Antworten aus jungen Unternehmen zurück, die (noch) keine Notwendigkeit für Automation sehen. Ich möchte diesen Unternehmen empfehlen, frühzeitig eine Automation First Philosophie zu entwickeln, da ich überzeugt bin, dass sich ein konsequenter Einsatz von Automations- und Konfigurationsmanagementwerkzeugen schnell auszahlt.

Unter den Systemadministratoren liegen Ansible (40 %) und Puppet (36%) als beliebteste Werkzeuge nah beieinander. Es ist immer gut, Auswahl und Wettbewerb zu haben. Ich freue mich über den Anteil von Puppet, gerade weil ich in den Nachrichten nur noch wenig Notiz davon nehme.

Salt liegt bei unter 10 % und ich habe auch schon längere Zeit nichts mehr von diesem Projekt gehört. Schade, die Architektur von Salt finde ich ganz interessant.

Im aktuellen Bericht nutzen knapp 23 % Terraform und der Lizenzwechsel zeigt noch keine große Abwanderung zu dessen Fork OpenTofu. Da die Datenerhebung jedoch Ende 2023 durchgeführt wurde, kann der Bericht eine etwaige Nutzerabwanderung noch nicht darstellen. In 2024 hat IBM die Übernahme von Hashi Corp bekannt gegeben. Ich bin gespannt, wie es mit den Produkten und deren Nutzung weitergeht. Hoffentlich gibt der nächste Bericht erste Einblicke.

Fazit

Durch die Arbeit in einem großen IT-Unternehmen mit einem starken eigenen Portfolio fällt es leicht, eine Betriebsblindheit für die Entwicklungen außerhalb des eigenen Kosmos zu entwickeln. Berichte wie der 2024 State of the Open Source Report helfen, der Betriebsblindheit entgegenzuwirken.

Ich habe nicht alle Kategorien des aktuellen Berichts im Detail betrachtet, sondern mir diejenigen herausgepickt, die mein persönliches Interesse ansprechen. Darüber in diesem Blog zu schreiben, hilft mir, über den Bericht und meine Erfahrungen zu reflektieren. Und wenn euch dieser Kommentar ebenfalls gefällt, freue ich mich umso mehr.

Information zum heutigen Ausfall von My-IT-Brain.de

02. September 2024 um 18:12

Der Virutal Private Server (VPS), welcher diesen Blog ausliefert, war heute in der Zeit zwischen 08:06 Uhr und 17:52 Uhr nicht erreichbar.

Screenshot aus meiner Uptime-Kuma-Instanz

Ursache ist eine Störung im Nürnberger Rechenzentrum meines Anbieters Contabo. Die Störung besteht offenbar schon seit dem 30.08. (siehe Screenhot der Meldung unten), betraf meinen VPS aber erst heute.

Screenshot einer Contabo-Status-Meldung aus meinen RSS Feed Reader
Screenshot der Contabo-Störungs-Meldung zum Zeitpunkt 2024-09-02T20:11+02

Die Störung bei Contabo ist noch nicht behoben. Es ist nicht auszuschließen, dass dieser Blog nocheinmal davon betroffen sein wird. Ich bitte in diesem Fall um etwas Geduld.

Update 2024-09-16: Root Cause Analysis of September 2024 Nuremberg Data Center Outage

Contabo hat einen Blog zur Aufarbeitung der Störung vom 2. September 2024 veröffentlicht. Die URL lautet: https://contabo.com/blog/nuremberg-incident-root-cause-analysis/

Demonstration von Ansible Lint am Beispiel einer Ansible Collection

02. September 2024 um 05:00

In diesem Beitrag erkläre ich kurz, was Ansible Lint ist und demonstriere dessen Anwendung am Beispiel meiner Ansible Collection tronde/nextcloud.

Er richtet sich primär an Personen, die mit Ansible Lint noch nicht vertraut sind. Linting-Profis werden vermutlich keine neuen Erkenntnisse gewinnen.

Was ist Ansible Lint und wofür ist es gut?

Lint (englisch für „Fussel“) ist eine Software zur statischen Code-Analyse. Davon abgeleitet hat sich das Verb linten (englisch to lint) für das Durchführen der statischen Code-Analyse etabliert.

https://de.wikipedia.org/wiki/Lint_(Programmierwerkzeug)

Dem obigen Zitat und der Projektdokumentation folgend, ist Ansible Lint dementsprechend ein Werkzeug zur statischen Code-Analyse von Ansible Playbooks, Roles und Collections. Mit der Anwendung dieses Werkzeugs auf die eigenen Ansible-Inhalte kann sichergestellt werden, dass diese gängigen Konventionen und Standards entsprechen.

Wie wird Ansible Lint installiert?

Die Dokumentation beschreibt verschiedene Installationsverfahren. Ich habe ansible-lint als Bestandteil der Ansible Development Tools (ADT) installiert. Dies ist ein Werkzeugkasten mit weiteren Programmen wie z.B. `ansible-core` und Ansible Molecule, welche ich für die Entwicklung meiner Ansible Collection nutze.

Auf meiner Fedora Workstation habe ich die ADT wie folgt installiert:

~]$ mkdir venv
~]$ cd venv
venv]$ ]$ python -m venv adt
venv]$ source adt/bin/activate
(adt) venv]$ pip install pip --upgrade
Requirement already satisfied: pip in ./adt/lib64/python3.12/site-packages (23.3.2)
Collecting pip
  Using cached pip-24.2-py3-none-any.whl.metadata (3.6 kB)
Using cached pip-24.2-py3-none-any.whl (1.8 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 23.3.2
    Uninstalling pip-23.3.2:
      Successfully uninstalled pip-23.3.2
Successfully installed pip-24.2
(adt) venv]$  pip install ansible-dev-tools
Collecting ansible-dev-tools
  Using cached ansible_dev_tools-24.7.2-py3-none-any.whl.metadata (11 kB)
… Ausgabe gekürzt
(adt) venv]$ adt --version
ansible-builder                          3.1.0
ansible-core                             2.17.3
ansible-creator                          24.7.1
ansible-dev-environment                  24.7.0
ansible-dev-tools                        24.7.2
ansible-lint                             24.7.0
ansible-navigator                        24.8.0
ansible-sign                             0.1.1
molecule                                 24.8.0
pytest-ansible                           24.8.0
tox-ansible                              24.8.0

Ansible Lint liefert eine ganze Reihe von Profilen mit, welche Autoren unterstützen, die Code-Qualität schrittweise zu verbessern. Der Befehl ansible-lint --list-profiles gibt die verfügbaren Profile mit einer Beschreibung aus.

Ich werde im Folgenden mit dem Profil shared arbeiten, welches für Autoren gedacht ist, die ihre Collection auf https://galaxy.ansible.com veröffentlichen möchten.

Eine Collection linten

Bevor es zur Sache geht, wechsel ich in das Projektverzeichnis meiner Ansible Collection und erstelle einen neuen Branch, mit dem Befehl git checkout -b lint. Die in meinem Repo vorhandene Datei .ansible-lint-ignore lösche ich, da ich im folgenden alle Fehler und Regelverstöße sehen möchte. Zu Beginn stellt sich mein Arbeitsverzeichnis wie folgt dar:

(adt) nextcloud]$ git status
On branch lint
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	deleted:    .ansible-lint-ignore

no changes added to commit (use "git add" and/or "git commit -a")

Das Programm ansible-lint besitzt mit der Option --fix die Fähigkeit, Fehler automatisch zu korrigieren und auch YAML-Dateien neu zu formatieren. Der folgende Code-Block umfasst die gekürzte Ausgabe, wenn das Kommando ansible-lint --profile=shared --fix im Arbeitsverzeichnis ausgeführt wird.

(adt) nextcloud]$ ansible-lint --profile=shared --fix
WARNING  Listing 37 violation(s) that are fatal
galaxy[no-changelog]: No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.
galaxy.yml:1

var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex. (NC_HTML) (vars: NC_HTML)
roles/backup_restore_nextcloud/defaults/main.yml:4

…

risky-file-permissions: File permissions unset or incorrect.
roles/backup_restore_nextcloud/tasks/main.yml:18 Task/Handler: Copy backup files to container host

no-changed-when: Commands should not change things if nothing needs doing.
roles/backup_restore_nextcloud/tasks/main.yml:40 Task/Handler: Import tarball contents into an existing podman volume

no-changed-when: Commands should not change things if nothing needs doing.
roles/backup_restore_nextcloud/tasks/main.yml:54 Task/Handler: Export podman volumes to tarballs

var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex. (MYSQL_DATABASE) (vars: MYSQL_DATABASE)
roles/deploy_nextcloud_with_mariadb_pod/defaults/main.yml:13

…

Read documentation for instructions on how to ignore specific rule violations.

Modified 6 files.
                     Rule Violation Summary                      
 count tag                    profile rule associated tags       
    33 var-naming[pattern]    basic   idiom                      
     1 risky-file-permissions safety  unpredictability           
     1 galaxy[no-changelog]   shared  metadata                   
     2 no-changed-when        shared  command-shell, idempotency 

Failed: 37 failure(s), 0 warning(s) on 25 files. Profile 'shared' was required, but 'min' profile passed.

Obige Ausgabe:

  • Benennt Funde mit Pfadangabe und Zeilennummer
  • Führt 37 Fehler auf, inkl. der Regeln, die nicht eingehalten werden; Beispiele
    • galaxy[no-changelog]: No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.
    • risky-file-permissions: File permissions unset or incorrect.
    • no-changed-when: Commands should not change things if nothing needs doing.
    • var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex.
  • Informiert, dass ansible-lint Änderungen an 6 Dateien vorgenommen hat

Mit git diff verschaffe ich mir einen Überblick, welche Änderungen ansible-lint vorgenommen hat. Dies sind in meinem Fall:

  • Quoting von Strings
  • Einrückung von Kommentaren

Als Nächstes sehe ich mir die übrigen Fehler der Reihe nach an. Die Dokumentation beinhaltet eine Übersicht mit Beschreibungen der einzelnen Regeln. Dies ist nützlich, wenn der kurze Text in der Ausgabe von ansible-lint nicht ausreichend ist.

galaxy[no-changelog]: No changelog found. Please add a changelog file.

Unter Galaxy: Changelog Details finden sich Hinweise, wie dieser Fehler zu beheben ist. Ich erstelle die leere Datei CHANGELOG.md im Wurzelverzeichnis meiner Collection und der Fehler ist abgestellt.

Natürlich werde ich diese Datei zukünftig nutzen, um die wichtigsten Änderungen zu dokumentieren. ;-)

risky-file-permissions: File permissions unset or incorrect.

Auch hier habe ich kurz in der Dokumentation unter risky-file-permissions nachgesehen. Den Fehler habe ich abgestellt, indem ich den Parameter mode: 0600 zum Task hinzugefügt habe.

Dies war ein Flüchtigkeitsfehler, wie er häufig passieren kann, wenn man seinen Code nicht konsequent überprüft. Ohne den Dateimode explizit zu setzen, kann dies zu unvorhersehbaren bzw. überraschenden Verhalten führen.

no-changed-when: Commands should not change things if nothing needs doing.

An zwei Stellen bin ich leider nicht herumgekommen, das ansible.builtin.command Modul zu verwenden, da kein natives Modul für diese Aufgabe existiert. Betrachtet man sich die beiden Tasks fällt auf, dass diese jedes Mal Daten verarbeiten werden. Sie sind nicht idempotent. Im Ergebnis können sie erfolgreich sein oder fehlschlagen, aber sie werden immer Daten verarbeiten und dadurch ändern.

 41     - name: Import tarball contents into an existing podman volume
 42       ansible.builtin.command:
 43         cmd: |
 44           podman volume import
 45           {{ item }} {{ backup_restore_nextcloud_import_path }}/{{ item }}.tar
 46       loop:
 47         - "{{ NC_HTML }}"
 48         - "{{ NC_APPS }}"
 49         - "{{ NC_CONFIG }}"
 50         - "{{ NC_DATA }}"
 51         - "{{ MYSQL_DATA }}"
 52            
 53 # I need to use the command module as the volume module lacks the functionality
 54 # to export podman volumes.
 55 - name: Export podman volumes to tarballs
 56   ansible.builtin.command:
 57     cmd: podman volume export {{ item }} --output {{ backup_restore_nextcloud_export_path }}/{{ item }}.tar
 58   loop:    
 59     - "{{ NC_HTML }}"
 60     - "{{ NC_APPS }}"
 61     - "{{ NC_CONFIG }}"
 62     - "{{ NC_DATA }}"
 63     - "{{ MYSQL_DATA }}"
 64   tags:    
 65     - never
 66     - backup

Um herauszufinden, wie ich ansible-lint zufriedenstellen kann, schaue ich wieder in der Doku unter no-changed-when nach. Nach der dortigen Beschreibung ist mein Fehler, dass ich den Rückgabewert des Kommandos nicht behandel. Daher registriere ich nun eine Variable je Task, die die Task-Ausgabe aufnimmt und prüfe den Rückgabewert. Ist der Rückgabewert gleich 0 wird der Task-Status auf changed gesetzt, ist der Rückgabewert ungleich 0 wird der Status entsprechend auf failed gesetzt. Das ganze sieht nun wie folgt aus:

 41     - name: Import tarball contents into an existing podman volume
 42       ansible.builtin.command:
 43         cmd: |
 44           podman volume import
 45           {{ item }} {{ backup_restore_nextcloud_import_path }}/{{ item }}.tar
 46       register: __import_tar_output
 47       changed_when: __import_tar_output.rc == 0
 48       failed_when: __import_tar_output.rc != 0
 49       loop:
 50         - "{{ NC_HTML }}"
 51         - "{{ NC_APPS }}"
 52         - "{{ NC_CONFIG }}"
 53         - "{{ NC_DATA }}"
 54         - "{{ MYSQL_DATA }}"
 55  
 56 # I need to use the command module as the volume module lacks the functionality
 57 # to export podman volumes.
 58 - name: Export podman volumes to tarballs
 59   ansible.builtin.command:
 60     cmd: podman volume export {{ item }} --output {{ backup_restore_nextcloud_export_path }}/{{ item }}.tar
 61   register: __import_tar_output
 62   changed_when: __import_tar_output.rc == 0
 63   failed_when: __import_tar_output.rc != 0
 64   loop:
 65     - "{{ NC_HTML }}"
 66     - "{{ NC_APPS }}"
 67     - "{{ NC_CONFIG }}"
 68     - "{{ NC_DATA }}"
 69     - "{{ MYSQL_DATA }}"
 70   tags:
 71     - never
 72     - backup

Collection-intern verwendete Variablen leite ich mit zwei Unterstrichen (‚_‘) ein, um mir zu verdeutlichen, dass diese nicht durch den Nutzer gesetzt werden und daher auch nicht im README.md oder defaults/main.yml dokumentiert sind.

var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex.

Hier brauche ich nicht weiter nachzuschlagen. Ich verstoße gegen diese Regel, da ich meine Variablen-Namen großgeschrieben habe. Die Ausgabe von ansible-lint zeigt dies deutlich:

var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex. (NC_HTML) (vars: NC_HTML)
roles/backup_restore_nextcloud/defaults/main.yml:4

Diese Meldungen lassen sich mit folgendem Bash-Einzeiler abstellen:

$ for text in $(cut -d':' -f 1 roles/deploy_nextcloud_with_mariadb_pod/defaults/main.yml | grep -v '^$\|^#\|---'); do find roles -type f -iname "*.yml" | xargs sed -i -e "s/$text/\L&/g"; done

Aus verschiedenen Gründen hebe ich mir die Überarbeitung für später auf und nutze die Meldung, um zu demonstrieren, wie man ansible-lint dazu bringt, bestimmte Fehler zu ignorieren.

Um Regeln für ausgewählte Dateien zu ignorieren, spezifiziert man den jeweiligen Dateinamen und den Namen der Regel in der Datei .ansible-lint-ignore, welche im Wurzelverzeichnis der Collection erstellt wird:

nextcloud]$ cat .ansible-lint-ignore 
roles/deploy_nextcloud_with_mariadb_pod/defaults/main.yml var-naming[pattern]
roles/backup_restore_nextcloud/defaults/main.yml var-naming[pattern]

Zweiter Durchgang mit ansible-lint

Damit habe ich alle Probleme, die im ersten Durchlauf von ansible-lint gefunden wurden, adressiert. Ein zweiter Durchlauf zeigt das Ergebnis meiner Arbeit:

(adt) nextcloud]$ ansible-lint --profile=shared
WARNING  Listing 33 violation(s) marked as ignored, likely already known
var-naming[pattern]: Variables names should match ^[a-z_][a-z0-9_]*$ regex. (NC_HTML) (vars: NC_HTML) (warning) # ignored
roles/backup_restore_nextcloud/defaults/main.yml:4

…Ausgabe gekürzt

WARNING  Listing 1 violation(s) that are fatal
yaml[octal-values]: Forbidden implicit octal value "0600"
roles/backup_restore_nextcloud/tasks/main.yml:22

Read documentation for instructions on how to ignore specific rule violations.

                Rule Violation Summary                 
 count tag                profile rule associated tags 
     1 yaml[octal-values] basic   formatting, yaml     

Failed: 1 failure(s), 33 warning(s) on 27 files. Profile 'shared' was required, but 'min' profile passed.

Die ignorierten Regelverstöße werden als Warnung weiterhin ausgegeben, nehmen jedoch keinen Einfluss auf die abschließende Bewertung. Dafür habe ich einen neuen Fehler (yaml[octal-values]) eingebaut. Nach dem aktuellen Regelwerk erfordern oktale Werte ein explizites Quoting, um als Strings verarbeitet zu werden.

Nachdem ich das Problem mit mode: '0600' behoben habe, endet ein weiterer Lauf von ansible-lint schlussendlich mit:

Passed: 0 failure(s), 33 warning(s) on 27 files. Profile 'shared' was required, but 'production' profile passed.

Damit erfüllt meine Collection aktuell sogar die Anforderungen des nächst höheren Profils production; allerdings nur, weil ich einige Regeln bewusst ignoriere. Daher ist aktuell noch nicht sichergestellt, dass meine Collection tatsächlich bei einem Import auf Ansible Galaxy akzeptiert wird.

Zusammenfassung

  • Ansible Lint ist ein Werkzeug zur statischen Analyse von Ansible Playbooks, Roles und Collections
  • Das Werkzeug unterstützt Autoren dabei, gängige Konventionen und Standards einzuhalten und die Qualität des eigenen Codes auf einem Mindest-Niveau zu halten
  • Ansible Lint bietet mehrere Profile für verschiedene Anwendungsfälle
  • Regeln können bei Bedarf ignoriert werden, was zwar das Ergebnis des Linting beeinflusst, die Qualität jedoch nicht steigert
  • Linting sollte fester Bestandteil des eigenen Entwicklungsworkflows sein und stets nach Änderungen durchgeführt werden

Ich persönlich führe ansible-lint gern in einem eigenständigen Schritt aus. Es besteht jedoch auch die Möglichkeit, dies in den verwendeten Editor, die genutzte IDE oder Molecule zu integrieren und bei Änderungen automatisch laufen zu lassen.

Ich freue mich, wenn euch dieser Artikel gefallen hat.

Quellen und weiterführende Links

Meine zweite Ansible Collection

19. August 2024 um 05:00

Dies ist ein Erfahrungsbericht zur Migration meiner Ansible-Rolle „Nextcloud im Container“ in eine Ansible Collection. Er umfasst die Migration der bestehenden Rolle und die Ergänzung der neuen Collection um eine weitere Rolle, welche sich um die Aufgaben Backup und Restore kümmert.

Wer es ganz eilig hat, kann direkt zur Zusammenfassung springen. Allen anderen wünsche ich viel Spaß bei der Lektüre.

Für grundlegende Informationen zu Ansible Collections siehe:

Randnotiz: Dass ihr zu meiner ersten Ansible Collection hier im Blog nicht fündig werdet, liegt darin begründet, dass meine Arbeit daran eingeschlafen ist.

Die Entwicklung der hier beschriebenen Collection könnt ihr auf Codeberg.org verfolgen. Die Repo-URL lautet: https://codeberg.org/Tronde/nextcloud

Motivation

Für mein Wochenendprojekt „Nextcloud im Container“ habe ich eine Ansible-Rolle entwickelt und auf Github veröffentlicht, die dem Zweck dient, Nextcloud mit einer MariaDB in einer rootless Podman-Umgebung zu installieren.

Wie ihr in Teil 5 der Artikel-Serie nachlesen könnt, war ich mit der Lösung für Backup und Restore nicht ganz zufrieden. Ich möchte dieses Thema erneut angehen und mithilfe einer Ansible-Rolle lösen.

Backup und Restore beschreiben jedoch andere Anwendungsfälle als die Bereitstellung, weswegen ich den dafür notwendigen Quelltext nicht mit in die bestehende Rolle pressen möchte. Da Backup und Restore für mich jedoch zum Betrieb dazugehören, möchte ich alle Ansible-Rollen, die ich zum Betrieb meines Nextcloud-Setups benötige, in einer Collection zusammenfassen.

Migration der bestehenden Rolle in eine Collection

Ich orientiere mich hierzu an der englischsprachigen Dokumentation „Migrating a role to a collection“. Da ich bereits einen Galaxy Namespace besitze, nutze ich diesen auch für die Erstellung der Collection. Der folgende Codeblock zeigt die verwendeten Befehle.

]$ ansible-galaxy collection init tronde.nextcloud
- Collection tronde.nextcloud was created successfully

]$ mkdir tronde/nextcloud/roles/deploy_nextcloud_with_mariadb_pod && rsync -a ../roles/ansible_role_deploy_nextcloud_with_mariadb_pod/ tronde/nextcloud/roles/deploy_nextcloud_with_mariadb_pod/

]$ tree -L 3 tronde/nextcloud/
tronde/nextcloud/
├── docs
├── galaxy.yml
├── meta
│   └── runtime.yml
├── plugins
│   └── README.md
├── README.md
└── roles
    └── deploy_nextcloud_with_mariadb_pod
        ├── defaults
        ├── meta
        ├── README.md
        ├── tasks
        ├── tests
        └── vars

]$ rm -rf tronde/nextcloud/roles/deploy_nextcloud_with_mariadb_pod/.git

Im letzten Schritt entferne ich das .git-Verzeichnis, da ich die Collection als Ganzes in einem Repository verwalten möchte, statt alle Rollen einzeln zu versionieren und dann in die Collection einzufügen.

Anschließend aktualisiere ich die Dateien galaxy.yml und README.md. In der Rolle habe ich ein Playbook zum Testen verwendet, welches im Pfad deploy_nextcloud_with_mariadb_pod/tests/test.yml liegt. Um konform mit der Struktur einer Ansible Collection zu sein, erstelle ich im Wurzelverzeichnis meiner Collection das Verzeichnis playbooks und kopiere das Test-Playbook hier hinein:

]$ tree playbooks/
playbooks/
└── deploy_nextcloud_with_mariadb_pod.yml

An dieser Stelle halte ich zunächst inne und überlege mir, welche Tools ich noch benötige, um meine Collection entwickeln und testen zu können.

Ansible Development Tools

Ansible Development Tools (ADT) ist ein Projekt mit dem Ziel, einen Werkzeugkasten mit allen wichtigen Werkzeugen zur Entwicklung von Ansible Content zu bieten. Genau so etwas habe ich gesucht. Das probiere ich gleich aus.

Um mir mein System nicht zu verhunzen, installiere ich die ADT in ein Python Virtual Environment und lasse mir anzeigen, welche Werkzeuge ADT mitbringt:

]$ python -m venv adt
]$ . adt/bin/activate
(adt) ]$ pip install --upgrade pip
(adt) ]$ pip install ansible-dev-tools
(adt) ]$ pip install molecule-podman
(adt) ]$ adt --version
ansible-builder                          3.1.0
ansible-core                             2.17.1
ansible-creator                          24.7.0
ansible-dev-environment                  24.7.0
ansible-dev-tools                        24.7.1
ansible-lint                             24.7.0
ansible-navigator                        24.7.0
ansible-sign                             0.1.1
molecule                                 24.7.0
pytest-ansible                           24.7.0
tox-ansible                              24.7.0

Bei molecule-podman handelt es sich um einen Molecule-Treiber, welcher benötigt wird um Molecule-Tests in Podman-Containern ausführen zu können. Ich habe dieses Paket mitinstalliert, da ich mir vorstellen kann, dies in naher Zukunft zu nutzen.

ansible-lint

Ansible Lint ist das erste Werkzeug aus der ADT-Sammlung, welches ich verwende, um den Quelltext meiner Collection zu prüfen. Dazu wird das Kommando einfach im Wurzelverzeichnis der Collection ausgeführt. Anschließend können die gefundenen Fehler behoben werden.

Da es den Rahmen dieses Artikels sprengen würde, werde ich dem Thema einen eigenen Text widmen.

molecule

Ansible Molecule eignet sich zum Testen von Ansible-Rollen und Collections. Ich nutze meine Ansible Collection, um mich mit diesem Werkzeug vertraut zu machen.

Zwar gibt es auch hier erst eine Lernkurve, doch wird mir eine durchdachte Test-Konfiguration bei der weiteren Entwicklung sicher zugutekommen. Ich orientiere mich zu Beginn am Ansible Molecule Getting Started Guide.

Zu Beginn möchte ich meine in die Collection migrierte Rolle testen. Dazu bearbeite ich die Datei tronde/nextcloud/extensions/molecule/default/converge.yml. Sie enthält schließlich folgenden Inhalt:

extensions]$ cat molecule/default/converge.yml 
---
- name: Converge
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Test collection role deploy_nextcloud_with_mariadb_pod
      ansible.builtin.import_role:
        name: tronde.nextcloud.deploy_nextcloud_with_mariadb_pod

Und mit folgendem Befehl teste ich, ob meine Nextcloud-Instanz erfolgreich deployt wird:

extensions]$ molecule converge
…
PLAY RECAP *********************************************************************
localhost                  : ok=10   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

extensions]$ podman ps
CONTAINER ID  IMAGE                                    COMMAND               CREATED             STATUS             PORTS                    NAMES
48438d1bd884  quay.io/centos/centos:stream8            bash -c while tru...  7 minutes ago       Up 7 minutes                                instance
104c525a6b50  localhost/podman-pause:5.1.1-1717459200                        About a minute ago  Up About a minute  127.0.0.1:40671->80/tcp  e34ddf4d4203-infra
f27842b12d56  docker.io/library/mariadb:10.11.2        mariadbd              About a minute ago  Up About a minute  127.0.0.1:40671->80/tcp  nc_mariadb
9ee391a57fbd  docker.io/library/nextcloud:25-apache    apache2-foregroun...  13 seconds ago      Up 13 seconds      127.0.0.1:40671->80/tcp  nextcloud

Das Ergebnis ist positiv und kann durch Aufruf von http://127.0.0.1:40671 im Webbrowser überprüft werden. Ein Login mit den Default-Werten aus tronde/nextcloud/roles/deploy_nextcloud_with_mariadb_pod/defaults/main.yml bestätigt das erfolgreiche Deployment.

Es handelt sich hierbei noch nicht um ein adäquates Test-Setup; doch für den Moment ist es ausreichend. Ich werde mich noch weiter einarbeiten müssen, um das Test-Setup verbessern zu können. Vermutlich wird auch dazu dann ein weiterer Artikel folgen.

Falls sich jemand wundert, es ist durchaus Absicht, dass die Nextcloud nur via 127.0.0.1 und per HTTP erreichbar ist. Ich betreibe diese hinter einem Reverse-Proxy. Details können in Nextcloud im Container — Teil 3: Mit Reverse-Proxy nachgelesen werden.

Backup und Restore für die Nextcloud

Um die Konfiguration und die in der Nextcloud gespeicherten Daten sichern und wiederherstellen zu können, werde ich eine Offline-Sicherung der verwendeten Podman Volumes durchführen. Der Ablauf für die Sicherung sieht wie folgt aus:

  1. Den Pod ˋnc_podˋ inkl. aller darin enthaltenen Container stoppen
  2. Alle zum Setup gehörenden Podman Volumes in Tarballs exportieren
  3. Diese Tarballs vom managed Node auf den Control Node sichern
  4. Den ˋnc_podˋ wieder starten

Die Wiederherstellung läuft sinngemäß andersherum ab:

  1. Die Tarballs werden vom Control Node auf den Managed Node kopiert
  2. Der Pod ˋnc_podˋ inkl. aller darin enthaltenen Container wird gestoppt
  3. Die Podman Volumes aus Schritt 1 werden importiert
  4. Der nc_pod wird wieder gestartet
  5. Die zur Wiederherstellung auf den Managed Node kopierten Tarballs werden wieder entfernt

Um diese neue Rolle der Collection hinzuzufügen, navigiere ich in das Rollenverzeichnis tronde/nextcloud/roles/ und erstelle dort das Grundgerüst für die Rolle: ansible-galaxy role init backup_nextcloud

Die Struktur sieht bei mir wie folgt aus, wobei nicht benötigte Verzeichnisse noch nicht entfernt wurden:

ansible_collections]$ tree -L 2 tronde/nextcloud/roles/backup_restore_nextcloud/
tronde/nextcloud/roles/backup_restore_nextcloud/
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

9 directories, 8 files

Den aktuellen Entwicklungsstand könnt ihr unter dieser URL einsehen: https://codeberg.org/Tronde/nextcloud/src/branch/main/roles/backup_restore_nextcloud

Das dortige README.md enthält wie bei dedizierten Rollen die Dokumentation zu dieser Rolle. Um doppelte Texte zu vermeiden, verweise ich im Collection-README auf die jeweiligen README-Dateien in den einzelnen Rollen.

Getestet wird diese Rolle ebenfalls mit Molecule. Zu den Tests mit Molecule werde ich noch mehr schreiben, sobald ich dies etwas verfeinert habe.

Fallen mir noch weitere Anwendungsfälle ein, können diese nun einfach als weitere Rollen der Collection hinzugefügt werden.

Ansible-Variablen definieren

Jede Rolle in dieser Collection ist für sich alleine nutzbar. Somit definiert jede Rolle die Eingangs-Variablen in der defaults/main.yml der jeweiligen Rolle.

Bei der Entwicklung achte ich darauf, dass Variablen, die z.B. den Namen eines Podman Volumes enthalten, in allen Rollen gleich geschrieben werden. Damit ist es möglich, diese Variablen an anderer Stelle zu definieren und in den verschiedenen Rollen nutzbar zu machen. So können an individuelle Deployments angepasste Variablen in Playbooks, group_vars, host_vars, etc. definiert werden.

Wo Variablen definiert werden können und welche Präzedenz diese besitzen, kann in der offiziellen Doku nachgelesen werden: Variable precedence: Where should I put a variable?

Zusammenfassung

Eine Ansible-Rolle ohne Plug-ins in eine Ansible Collection zu überführen, ist mit dem kurzen Abschnitt aus der Dokumentation schnell erledigt.

Weitere Rollen können der Collection hinzugefügt werden, indem man sie im Verzeichnis roles der Collection-Verzeichnisstruktur wie gewohnt mit ansible-galaxy role init <Rollenname> erstellt und mit Leben füllt. Sorgfalt ist und bleibt bei der Benennung von Variablen und deren Präzedenz geboten, um nicht wahnsinnig zu werden. Dies ist nicht wirklich schwierig, doch muss ich fast jedes Mal in der Dokumentation nachschlagen, um sicher zu sein.

Die Ansible Development Tools (ADT) sind eine praktische Sammlung von Werkzeugen zur Entwicklung von Rollen und Collections für Ansible. Für mich sind aktuell Ansible Lint und Ansible Molecule die wichtigsten Werkzeuge aus dieser Sammlung. Wobei gerade die Dokumentation von Molecule auf dem Weg zu meinem Ziel, nämlich meine Collections in verschiedenen rootless Podman Containern mit nested Podman und Ansible zu testen, leider viele Fragen offen lässt. Grundsätzlich lassen sich Testpläne damit realisieren und vereinfachen mein bisheriges Testsetup bestehend aus diversen Skripts und virtuellen Maschinen. Und sie bieten Stoff für weitere Einträge in diesem Blog.

Die weitere Entwicklung meiner Nextcloud Collection findet auf Codeberg statt. Ihr findet sie dort unter der URL: https://codeberg.org/Tronde/nextcloud

In 2024 wurde ein Lenovo T570 für Debian Cinnamon beschafft

05. August 2024 um 05:00

Vor einigen Wochen habe ich um Empfehlungen für Laptop-Hardware, eine Linux-Distribution und eine Desktopumgebung gebeten. Für die vielen Rückmeldungen, die ich erhalten habe, an dieser Stelle vielen Dank.

Heute möchte ich euch wissen lassen, welche Kombination es geworden ist.

Die Hardware

Ich habe mich für ein wiederaufbereitetes Lenovo T570 entschieden, welches für günstige 240 Euro im Onlinehandel verfügbar war. Da war dann auch noch für 30 Euro ein Schutzbrief drin, der Flüssigkeiten und Stürze abdeckt.

Mit dem Intel Core-i5 der 6. Generation, 8 GB RAM und einer 256 GB SSD bietet dieses Gerät mehr als ausreichend Leistung.

Das Gerät weist einige Gebrauchsspuren auf. Den Preis empfinde ich dennoch günstig, da Geräte dieser Klasse nicht unter 1.000 Euro Neupreis zu bekommen sind. Viel wichtiger jedoch ist, dass der Nutzer sich ebenfalls über das Gerät freut.

Linux-Distribution und Desktopumgebung

Wer die Wahl hat, hat die Qual. Um mir einen ersten Eindruck zu verschaffen, habe ich mir einen USB-Stick mit Ventoy und einer Auswahl an verschiedenen Linux-Distributionen erstellt. So konnte ich die verschiedenen Live-Systeme booten und prüfen, ob alles funktioniert und wie es sich in der Oberfläche navigieren lässt.

Schlussendlich habe ich mich für Debian Cinnamon entschieden. Dies machte nach dem ersten kurzen Test insgesamt den besten Eindruck. Firefox, Thunderbird, Bookmarks, Desktop-Verknüpfungen und Zoom-Client waren schnell eingerichtet und das Gerät bereit zur Übergabe.

Die Übergabe ist erfolgt

Mit der Übergabe gab es eine kurze Einweisung in das Gerät:

  • Wo schließt man das Netzteil an
  • Wo schaltet man das Gerät ein
  • Wie meldet man sich an
  • Wo findet man die Programme inkl. Tests aller wichtigen Dienste
  • Druck eines Anhangs aus Thunderbird
  • Wie fährt man das Gerät herunter

So reibungslos hat das bisher noch nie geklappt. Die Nutzungserfahrung ist positiv. Wir freuen uns.

Wie wird im Ansible Automation Controller eine neue Inventory Source hinzugefügt?

22. Juli 2024 um 05:00

In diesem Überblick beschreibe ich am Beispiel der Proxmox inventory source, wie eine eigene Inventory Source im Ansible Automation Controller hinzugefügt werden kann.

Die folgenden Schritte wurden mit der Ansible Automation Platform 2.4 getestet. Die einzelnen Schritte sollten in gleicher Weise auch in Ansible AWX ausgeführt werden können.

Um diesem Text folgen zu können, werden Kenntnisse im Umgang mit Ansible und Git auf der Kommandozeile vorausgesetzt.

Der Text verweist, wo möglich, auf bestehende Dokumentation. Es handelt sich bei diesem Text nicht um ein klassisches Tutorial. Er dient mir als Gedächtnisstütze und mag euch eine Anregung sein, bzw. im besten Fall die Wissenslücken schließen, die sich mit der Dokumentation allein nicht schließen lassen.

Ausgangssituation

Abschnitt 18.4.5.1. Inventory sources im Automation Controller User Guide führt die in der Ansible Automation Platform (AAP) unterstützten Inventory Sources auf. Möchte man nun bspw. Proxmox Virtual Environment (PVE), Microsoft Active Directory oder Cisco DNA Center als Quelle für sein Inventar benutzen, wird man auf den ersten Blick nicht fündig.

Für das Beispiel in diesem Text werden Hosts aus der Bestandsliste eines PVE als Inventory Source hinzugefügt. Die dabei verwendete Vorgehensweise kann auch für andere Inventory Plugins verwendet werden. Die Entwicklung von Inventory Plugins ist jedoch nicht Gegenstand dieses Textes. Hierzu wird auf die Dokumentation unter „Developing dynamic inventory“ verwiesen.

Mein Kollege Steffen Scheib hat mir geholfen, das Proxmox-Plugin zu konfigurieren, wofür ich ihm an dieser Stelle nochmal ganz herzlich danke. Es liegt auf meiner Arbeitsstation als Ansible Project in folgender Verzeichnisstruktur vor:

]$ tree proxmox_inventory/
proxmox_inventory/
├── collections
│   └── requirements.yml
├── inventory
│   └── inventory.proxmox.yml
└── vault_password_file

3 directories, 3 files

Mit Ausnahme der Datei vault_password_file wurden alle Dateien und Verzeichnisse in Git aufgenommen. Ich verwende einen einfachen Git-Server in meiner Laborumgebung, auf welchen ich meine lokalen Repositorys pushe. Der Automation Controller synchronisiert das Projekt aus dem Git-Repo, um es als Inventory Source verfügbar zu machen.

Die Vorgehensweise im Überblick

  1. Ansible Credential für Source Control erstellen
  2. Ein Ansible Projekt hinzufügen
  3. Einen Custom Credential Type erstellen
  4. Ein Ansible Inventory hinzufügen

Ansible Credential für Source Control erstellen

Das Proxmox Inventory Plugin befindet sich in einem Git-Repository, auf welches mit SSH-Key-Authentifizierung zugegriffen werden kann. Damit auch der Automation Controller auf dieses Repository zugreifen kann, wird ein Credential vom Typ Source Control erstellt.

Beipsiel für einen Source Control Credential Typ im Ansible Automation Controller

Der SSH-Private-Key wurde von meinem Host hochgeladen und verschlüsselt im Automation Controller gespeichert. Der Key lässt sich in der GUI nicht wieder sichtbar machen, lediglich ersetzen.

Ein Ansible Projekt hinzufügen

Der Dokumentation folgend, wird ein Projekt hinzugefügt:

Beispiel einer ausgefüllten Maske im Automation Controller, zum Hinzufügen eines Projekts.

Wenn alles passt, wird das Projekt nach dem Speichern erfolgreich synchronisiert:

Dieses Projekt wird in einem späteren Schritt zur Erstellung des Inventory benötigt.

Einen Custom Credential Type erstellen

Bevor ich auf die Erstellung selbst eingehe, möchte ich kurz beschreiben, warum dieser Schritt notwendig ist.

Folgender Codeblock zeigt meine Datei inventory.proxmox.yml welche einige mit Ansible Vault verschlüsselte Werte enthält:

]$ cat inventory/inventory.proxmox.yml 
---
plugin: 'community.general.proxmox'
url: 'https://pve.example.com'
user: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          30623661316338386633623162303036346562346238386162633263636164636338393532613565
          3332616265353962326139363533313261623739643765640a623032613034613139653162356266
          34646464323233313964663939643631313539353736313364333433643136306632633065633664
          3234346635396563350a656334353632643830353534386636306365656261356436613662623163
          31663535363264356537336531393731633164613733316537383433653334643433
token_id: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          62356662336534646661353666356263363734666231643932393430336639363032303266636432
          3762343235633335613663393838343532326230353130380a616161313830373265306137346562
          61613662333764393565316362623838633332376366373161646237363163663039613863393439
          3165616664626633390a396465343430373837343662373634653634643138613131633034306432
          62623438366166353765366339323263393833396133653866343833663335663766
token_secret: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386338643463373837666164396332306261366634396630306430663937613963346164636433
          3362396566343932393234353439383932316436396437380a336365393038373566383534623136
          30353332383464356664393666383664636536666531663463623232353136353636363366653431
          3234616531623537630a393530643437376363653438643036636436316636616265316361623661
          35313832613063633662363531346164306638373538393164373663633335333863646430663232
          6339343164633865636239356538326438333937366134613738

validate_certs: false

# fail if a variable is not resolvable
strict: true

# facts are required to retrieve proxmox_vmtype
want_facts: true

# only allow qemu VMs
filters:
  - "proxmox_vmtype == 'qemu'"

Auf der Kommandozeile meines Hosts kann ich den Inhalt des Dynamic Inventory wie folgt anzeigen lassen:

ansible-inventory -i inventory/inventory.proxmox.yml --list --vault-password-file vault_password_file

Die Datei vault_password_file befindet sich jedoch nicht im Git, da sie das Passwort im Klartext enthält. Aus diesem Grund möchte ich die Datei auch nicht auf dem Automation Controller ablegen. Irgendwie müssen auf dem Automation Controller jedoch Credentials hinterlegt werden, um die Ansible Vault encrypted_strings zu entschlüsseln. Die Lösung steckt in diesem Kommentar auf Github. Im Automation Controller User Guide gibt es dazu Chapter 11. Custom credential types.

Fertig sieht das dann so aus:

Quelle: https://github.com/ansible/awx/issues/4089#issuecomment-1632066592

Das Schlüssel-Wert-Paar secret: true stellt sicher, dass das Passwort verschlüsselt gespeichert wird. Es kann danach im Automation Controller nicht mehr im Klartext angezeigt werden. Nachdem der neue Credential Typ erstellt ist, kann dieser instanziiert werden:

Beispiel des neuen Custom Credential Typs ‚encrypted_vault_password‘

Das Vault Passwort wird in das entsprechende Formularfeld kopiert. Es ist standardmäßig nicht sichtbar und wird wie oben bereits erwähnt, verschlüsselt gespeichert. Mit diesem Credential verfügt der Automation Controller nun über die notwendigen Informationen, um das Proxmox Inventory auszulesen.

Ein Ansible Inventory hinzufügen

Zuerst wird ein Inventory nach Dokumentation erstellt. Anschließend wird diesem eine Inventory Source hinzugefügt.

Die Formularfelder sind dabei wie folgt zu befüllen:

  • Name: Kann frei vergeben werden
  • Source: Sourced from a Project
  • Credential: Hier wird das im vorangegangenen Schritt erstellte Credential ausgewählt
  • Project: Hier wird das in obigen Abschnitt erstellte Projekt ausgewählt
  • Inventory file: Kann in diesem Fall auf `/ (project root)` gesetzt werden
Eine Inventory Source mit Proxmox als Beispiel

Nach dem Speichern wird die Inventory Source durch Klick auf ‚Sync‘ synchronisiert:

In dieser Ansicht wurde die Inventory Source bereits erfolgreich synchronisiert

Und wir haben 17 Hosts in unserem Inventory:

Damit endet dieser kurze Überblick auch schon. Ich wünsche euch viel Freude bei der Inventarpflege.

Beispiele für Ansibles ‚var is defined‘

08. Juli 2024 um 05:00

In diesem Beitrag gebe ich einige Beispiele mit Erklärungen zu Ansible Conditionals, welche mir in der Dokumentation fehlen. Dieser Artikel dient mir zur Erinnerung und mag Einsteigern helfen, ein besseres Verständnis der Bedingung is defined zu gewinnen.

Wird in einem Task eine Variable verwendet, welche nicht definiert ist, bricht Ansible die Verarbeitung eines Playbooks mit einem Fehler ab. Der folgende Code-Block zeigt ein einfaches Playbook mit anschließender Ausgabe des Playbooklaufs, um dies zu verdeutlichen. Der Task beinhaltet dabei bereits eine Bedingung. Er soll nur dann ausgeführt werden, wenn die Variable my_var den Wert Hello world! enthält.

]$ cat test_conditionals.yml 
---
- name: Play around with conditionals
  hosts: localhost
  gather_facts: false

  tasks:
    - name: >-
        When all conditionals are met, print the variable value using
        ansible.builtin.debug
      when:
        - my_var == "Hello world!"
      ansible.builtin.debug:
        var: my_var

]$ ansible-playbook -i hosts test_conditionals.yml 

PLAY [Play around with conditionals] *******************************************

TASK [When all conditionals are met, print the variable value using ansible.builtin.debug] ***
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'my_var == \"Hello world!\"' failed. The error was: error while evaluating conditional (my_var == \"Hello world!\"): 'my_var' is undefined. 'my_var' is undefined\n\nThe error appears to be in '/home/tronde/ansible/test_conditionals.yml': line 7, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n    - name: >-\n      ^ here\n"}

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Der Text 'my_var' is undefined in obiger Fehlerausgabe benennt den Grund des Scheiterns.

Nun gibt es Fälle, in denen Tasks, welche undefinierte Variablen enthalten, nicht zum Abbruch des gesamten Playbooks führen sollen. Stattdessen soll der betroffene Task einfach übersprungen werden. Dies erreicht man mit der Bedingung `is defined`. Der nächste Code-Block liefert wieder ein Beispiel dazu.

]$ cat test_conditionals.yml
---
- name: Play around with conditionals
  hosts: localhost
  gather_facts: false

  tasks:
    - name: >-
        When all conditionals are met, print the variable value using
        ansible.builtin.debug
      when:
        - my_var is defined
        - my_var == "Hello world!"
      ansible.builtin.debug:
        var: my_var

]$ ansible-playbook -i hosts test_conditionals.yml

PLAY [Play around with conditionals] *******************************************

TASK [When all conditionals are met, print the variable value using ansible.builtin.debug] ***
skipping: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Der Task mit der undefinierten Variable wurde übersprungen (skipped) und das Playbook erfolgreich beendet.

Im nächsten Beispiel habe ich die Variable my_var im Playbook definiert und den passenden Wert zugewiesen.

]$ cat test_conditionals.yml
---
- name: Play around with conditionals
  hosts: localhost
  gather_facts: false
  vars:
    my_var: Hello world!

  tasks:
    - name: >-
        When all conditionals are met, print the variable value using
        ansible.builtin.debug
      when:
        - my_var is defined
        - my_var == "Hello world!"
      ansible.builtin.debug:
        var: my_var

]$ ansible-playbook -i hosts test_conditionals.yml

PLAY [Play around with conditionals] *******************************************

TASK [When all conditionals are met, print the variable value using ansible.builtin.debug] ***
ok: [localhost] => {
    "my_var": "Hello world!"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Das war auch schon alles für heute. Ihr seht, es ist keine Hexerei. Mir hilft es, die Bedeutung von is defined zu erinnern, wenn ich es einmal aufgeschrieben habe.

Zum Ende gibt es noch einen Code-Block, der zeigt, dass dies auch mit Dictionaries funktioniert:

]$ cat test_conditionals.yml
---
- name: Play around with conditionals
  hosts: localhost
  gather_facts: false
  vars:
    my_dict:
      my_var: Hello world!

  tasks:
    - name: >-
        When all conditionals are met, print the variable value using
        ansible.builtin.debug
      when:
        - my_dict.my_var is defined
        - my_dict.my_var == "Hello world!"
      ansible.builtin.debug:
        var: my_dict.my_var

]$ ansible-playbook -i hosts test_conditionals.yml

PLAY [Play around with conditionals] *******************************************

TASK [When all conditionals are met, print the variable value using ansible.builtin.debug] ***
ok: [localhost] => {
    "my_dict.my_var": "Hello world!"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In der Kategorie Ansible findet ihr weitere Artikel rund um Ansible. Viel Spaß beim Stöbern.

Ich bin mit meinem aktuellen Job sehr zufrieden

24. Juni 2024 um 05:00

Und in diesem Text möchte ich euch mitteilen, welche Faktoren zu meiner Zufriedenheit beitragen.

Seit März 2023 arbeite ich als Senior Technical Account Manager (TAM) bei Red Hat. In diesem Artikel habe ich beschrieben, wie eine Arbeitswoche für mich aussehen kann.

Doch was gefällt mir nun so sehr an diesem Job?

  • Ich arbeite full remote. Dies passt aktuell am besten zu meinen Lebensumständen. Hier findet sich ein Erfahrungsbericht dazu.
  • Dass ich nicht mehr pendeln muss, gibt mir mehr Zeit für die Familie und schont die Umwelt.
  • Unser gesamtes Team arbeitet full remote und alle beherrschen unsere Tools, sodass die Zusammenarbeit reibungslos klappt.
  • Wir haben eine tolle Unternehmenskultur und ich fühlte mich selten von so hilfsbereiten Menschen umgeben.
  • Diese Kultur motiviert mich, mich selbst stets einzubringen und zu unterstützen, wo ich kann.
  • Wir haben anspruchsvolle Ziele und stets mehr als genug zu tun. Dennoch nehmen wir uns stets die Zeit einander zu helfen, unser Wissen zu teilen.
  • Wenn jemand mal nicht direkt helfen kann, wird man nicht mit Sätzen wie: „Dafür bin ich nicht zuständig.“ oder „Da kenne ich mich selbst nicht mit aus.“ abgespeist. Bei uns hört man dann eher:
    • „Da kann ich dir leider nicht direkt helfen, aber versuch es mal bei XY, die haben mir schonmal in einer ähnlichen Angelegenheit geholfen.“
    • Oder die Anfrage wird direkt an das richtige Team weitergeleitet
  • Wir sind in unserer Arbeitsweise sehr frei. Es gibt kein Mikromanagement. Unser aller Ziel ist, unseren Enterprise-Kunden eine gute Erfahrung zu bescheren. Natürlich gibt es Leitlinien, die einen Rahmen vorgeben. Diese empfinde ich nicht als Einschränkung, sondern als richtungsweisend.
  • Im Zweifel haben wir das gemeinschaftlich gepflegte TAM Manual, das uns erklärt, wie was gemacht wird.
  • Wir ziehen Besprechungen nicht in die Länge. Wenn wir fertig sind, hören wir einfach auf. Selbst dann, wenn die Zeit noch nicht vorbei ist.

Natürlich gibt es auch bei Red Hat genug Dinge, die verbessert werden können bzw. sollten. Doch konzentriere ich mich hier bewusst auf die Punkte, die zu meiner Zufriedenheit führen, um mich daran zu erfreuen.

Die obigen Punkte beziehen sich nicht ausschließlich auf mein eigenes Team. Ich erlebe dies regelmäßig auch teamübergreifend. Das ist eine tolle Erfahrung.

Mein Tipp für euch: Denkt nicht immer nur an Dinge, die euch nicht gefallen. Macht euch aktiv der Dinge bewusst, die euch gefallen und motivieren. Ihr werdet evtl. erstaunt sein, wie viel Energie ihr draus schöpfen könnt. Mich hat bspw. die Methode Journaling dabei unterstützt, zu einem positiven Mindset zu finden.

Was gefällt euch besonders an eurem Job? Teilt eure Gedanken und Erfahrungen gerne mit uns.

Suche Empfehlungen für Hardware und Linux-Distribution

18. Juni 2024 um 19:15

Liebe Leser*innen,
heute seid ihr gefragt. Denn ich möchte von euch wissen, welchen Laptop und welche Linux-Distribution, ihr für ältere, nicht EDV-affine Menschen und Windows-Umsteiger empfehlen könnt.

Hardware

Der Laptop soll über folgende Merkmale verfügen:

  • Größe: 15-17 Zoll
  • Webcam
  • Mikrofon und Lautsprecher
    • für Videokonferenzen
    • zum Schauen von Videos in sozialen Netzwerken
  • Linux- und Windows-Unterstützung

Die Unterstützung von Linux und Windows ist sehr wichtig. Sollte der Feldversuch mit Linux scheitern, möchte auf der gleichen Hardware ein aktuelles Windows-Betriebssystem installieren können.

Mir schwebt etwas in der Richtung der Lenovo IdeaPad oder ein ThinkPad der L-Serie vor, ich bin jedoch auf eure Empfehlungen gespannt.

Desktop-Umgebung

Ich suche nach einer Desktop-Umgebung, die folgende Merkmale bietet:

  • Ein Startmenü, welches sich in der unteren linken Ecke befindet
  • Erstellungen von Anwendungsstartern und Verknüpfungen auf der Desktopoberfläche

Dies sind Muss-Kriterien, die unbedingt erfüllt sein müssen. Ich möchte, dass die Desktopoberfläche diese Eigenschaften in der Standardkonfiguration erfüllt und ich diese nicht erst konfigurieren oder drölfzig Plug-ins installieren muss, um diesen Zustand zu erreichen.

Software

Die wichtigsten Anwendungen sind:

  • Thunderbird für E-Mail
  • Aktuelle Webbrowser (Chrome/Firefox) für den Rest
    • Facebook
    • YouTube
    • Zoom, MS Teams, Webex und wie sie alle heißen
  • Ein PDF-Anzeigeprogramm
  • Libre/Open Office zum Lesen von MS Office-Dokumenten

Linux-Distribution

Die Linux-Distribution muss die oben genannten Anforderungen an die Desktop-Umgebung und die Software erfüllen und dabei stabil allerdings nicht steinalt sein.

Ich möchte nicht vor jeder Videokonferenz mit den Audio-Einstellungen kämpfen müssen, um deutlich zu machen, wo meine Priorität liegt.

Kandidaten, die ich mir ansehen möchte, sind:

Was könnt ihr mir empfehlen? Bitte nutzt die Kommentare und verlinkt, wo möglich zu den Projekten, die ihr empfehlt.

InstructLab: Das erste Training ist beendet

10. Juni 2024 um 05:00

Dies ist die Fortsetzung von „Mit InstructLab zu Large Language Models beitragen“. Hier beschreibe ich, wie es nach dem Training weitergeht.

Das Training auf einer virtuellen Maschine mit Fedora 40 Server, 10 CPU-Threads und 32 GB RAM dauerte 180 Std. 44 Min. 7 Sek. Ich halte an dieser Stelle fest, ohne GPU-Beschleunigung fehlt es mir persönlich an Geduld. So macht das Training keinen Spaß.

Nach dem Training mit ilab train findet man ein brandneues LLM auf dem eigenen System:

(venv) tronde@instructlab:~/src/instructlab$ ls -ltrh models
total 18G
-rw-r--r--. 1 tronde tronde 4.1G May 28 20:34 merlinite-7b-lab-Q4_K_M.gguf
-rw-r--r--. 1 tronde tronde  14G Jun  6 12:07 ggml-model-f16.gguf

Test des neuen Modells

Den Chat mit dem LLM starte ich mit dem Befehl ilab chat -m models/ggml-model-f16.gguf. Das folgende Bild zeigt zwei Chats mit jeweils unterschiedlichem Ergebnis:

Das Bild zeigt zwei Chats mit dem neuen LLM. Es ist zu sehen, dass es zu zwei unterschiedlichen Ausgaben kommt, von denen keine die richtige Antwort liefert.
Zwei Chats mit dem frisch trainierten LLM. Beide Male erhalte ich nicht die erhoffte Antwort.

Fazit

Schade, das hat nicht so funktioniert, wie ich mir das vorgestellt habe. Es kommt weiterhin zu KI-Halluzinationen und nur gelegentlich gesteht das LLM seine Unkenntnis bzw. seine Unsicherheit ein.

Für mich sind damit 180 Stunden Rechenzeit verschwendet. Ich werde bis auf Weiteres keine Trainings ohne Beschleuniger-Karten mehr durchführen. Jedoch werde ich mir von Zeit zu Zeit aktualisierte Releases der verfügbaren Modelle herunterladen und diesen Fragen stellen, deren Antworten ich bereits kenne.

Wenn sich mir die Gelegenheit bietet, diesen Versuch auf einem Rechner mit entsprechender GPU-Hardware zu wiederholen, werde ich die Erkenntnisse hier im Blog teilen.

Mit InstructLab zu Large Language Models beitragen

03. Juni 2024 um 05:00

Dies ist mein Erfahrungsbericht zu den ersten Schritten mit InstructLab. Ich gehe darauf ein, warum ich mich über die Existenz dieses Open Source-Projekts freue, was ich damit mache und was ich mir von Large Language Models (kurz: LLMs, zu Deutsch: große Sprachmodelle) erhoffe. Der Text enthält Links zu tiefergehenden Informationen, die euch mit Hintergrundwissen versorgen und einen Einstieg in das Thema ermöglichen.

Dieser Text ist keine Schritt-für-Schritt-Anleitung für:

  • die Installation von InstructLab CLI,
  • die Installation und das Training von LLMs

Terminologie und Abkürzungen in diesem Text

Die Begriffe Künstliche Intelligenz (KI) oder englisch artificial intelligence (AI) werden in diesem Text synonym verwendet und zumeist einheitlich durch KI abgekürzt.

Beim Bezug auf große Sprachmodelle bediene ich mich der englischen Abkürzung LLM oder bezeichne diese als KI-ChatBot bzw. nur ChatBot.

Was ist InstructLab?

InstructLab ist ein von IBM und Red Hat ins Leben gerufenes Open Source-Projekt, mit dem die Gemeinschaft zur Verbesserung von LLMs beitragen kann. Jeder

  • mit einem Linux-Notebook oder
  • MacBook und
  • der Fähigkeit Anleitungen zu folgen und
  • wer YAML-Dateien schreiben kann,

der kann nun teilhaben und ausgewählte LLMs lokal auf seinem Endgerät ausführen, testen und verbessern. Für eine ausführliche Beschreibung siehe:

Informationen zu Open Source LLMs und Basismodellen für InstructLab bieten diese Links:

Meine Einstellung gegenüber KI-ChatBots

Gegenüber KI-Produkten im Allgemeinen und KI-ChatBots im Speziellen bin ich stets kritisch, was nicht bedeutet, dass ich diese Technologien und auf ihnen basierende Produkte und Services ablehne. Ich versuche mir lediglich eine gesunde Skepsis zu bewahren.

Was Spielereien mit ChatBots betrifft, bin ich sicherlich spät dran. Ich habe schlicht keine Lust, mich irgendwo zu registrieren und unnötig Informationen über mich preiszugeben, nur um anschließend mit einer Büchse chatten und ihr Fragen stellen zu können, um den Wahrheitsgehalt der Antworten anschließend noch verifizieren zu müssen.

Mittlerweile gibt es LLMs, welche ohne spezielle Hardware auch lokal ausgeführt werden können. Diese sprechen meine Neugier und meinen Spieltrieb schon eher an, weswegen ich mich nun doch mit einem ChatBot unterhalten möchte.

Mein InstructLab-Setup

Für meine ersten Versuche nutze ich mein Lenovo ThinkPad T14s (AMD) in der Ausstattung von 2021. Aktuell installiert ist Fedora 40 Workstation, welches zu den getesteten Betriebssystemen von InstructLab zählt.

Die Einrichtung des InstructLab-CLI und der erste Chat

Für die Einrichtung halte ich mich an den Getting Started Guide. Es sind folgende Befehle auszuführen, bis das erste LLM gestartet werden kann:

sudo dnf install gcc-c++ gcc make pip python3 python3-devel python3-GitPython
mkdir instructlab
cd instructlab
python3 -m venv --upgrade-deps venv
source venv/bin/activate
pip cache remove llama_cpp_python
pip install git+https://github.com/instructlab/instructlab.git@stable --extra-index-url=https://download.pytorch.org/whl/cpu
eval "$(_ILAB_COMPLETE=bash_source ilab)"
ilab init
ilab download
ilab serve

Der lokale LLM-Server wird mit dem Befehl ilab serve gestartet. Mit dem Befehl ilab chat wird die Unterhaltung mit dem Modell eingeleitet.

Im folgenden Video sende ich zwei Anweisungen an das LLM merlinite-7b-lab-Q4_K_M. Den Chatverlauf seht ihr in der rechten Bildhälfte. In der linken Bildhälfte seht ihr die Ressourcenauslastung meines Laptops.

Screencast eines Chats mit merlinite-7b-lab-Q4_K_M

Wie ihr seht, sind die Antwortzeiten des LLM auf meinem Laptop nicht gerade schnell, aber auch nicht so langsam, dass ich währenddessen einschlafe oder das Interesse an der Antwort verliere. An der CPU-Auslastung im Cockpit auf der linken Seite lässt sich erkennen, dass das LLM durchaus Leistung abruft und die CPU fordert.

Exkurs: Die Studie Energieverbrauch Index-basierter und KI-basierter Websuchmaschinen gibt einen interessanten Einblick in den Ressourcenverbrauch. Leider war ich nicht in der Lage, diese Studie als PDF aufzutreiben.

Mit den Antworten des LLM bin ich zufrieden. Sie decken sich mit meiner Erinnerung und ein kurzer Blick auf die Seite https://www.json.org/json-de.html bestätigt, dass die Aussagen des LLM korrekt sind.

Anmerkung: Der direkte Aufruf der Seite https://json.org, der mich mittels Redirect zu obiger URL führte, hat sicher deutlich weniger Energie verbraucht als das LLM oder eine Suchanfrage in irgendeiner Suchmaschine. Ich merke dies nur an, da ich den Eindruck habe, dass es aus der Mode zu geraten scheint, URLs einfach direkt in die Adresszeile eines Webbrowsers einzugeben, statt den Seitennamen in eine Suchmaske zu tippen.

Ich halte an dieser Stelle fest, der erste kleine Test wird zufriedenstellend absolviert.

KI-Halluzinationen

Da ich einige Zeit im Hochschulrechenzentrum der Universität Bielefeld gearbeitet habe, interessiert mich, was das LLM über meine ehemalige Dienststelle weiß. Im nächsten Video frage ich, wer der Kanzler der Universität Bielefeld ist.

Frage an das LLM: „Who is the chancellor of the Bielefeld University?“

Da ich bis März 2023 selbst an der Universität Bielefeld beschäftigt war, kann ich mit hinreichender Sicherheit sagen, dass diese Antwort falsch ist und das Amt des Kanzlers nicht von Prof. Dr. Karin Vollmerd bekleidet wird. Im Personen- und Einrichtungsverzeichnis (PEVZ) findet sich für Prof. Dr. Vollmerd keinerlei Eintrag. Für den aktuellen Kanzler Dr. Stephan Becker hingegen schon.

Da eine kurze Recherche in der Suchmaschine meines geringsten Misstrauens keine Treffer zu Frau Vollmerd brachte, bezweifle ich, dass diese Person überhaupt existiert. Es kann allerdings auch in meinen unzureichenden Fähigkeiten der Internetsuche begründet liegen.

Bei der vorliegenden Antwort handelt es sich um eine Halluzination der Künstlichen Intelligenz.

Im Bereich der Künstlichen Intelligenz (KI) ist eine Halluzination (alternativ auch Konfabulation genannt) ein überzeugend formuliertes Resultat einer KI, das nicht durch Trainingsdaten gerechtfertigt zu sein scheint und objektiv falsch sein kann.

Solche Phänomene werden in Analogie zum Phänomen der Halluzination in der menschlichen Psychologie als von Chatbots erzeugte KI-Halluzinationen bezeichnet. Ein wichtiger Unterschied ist, dass menschliche Halluzinationen meist auf falschen Wahrnehmungen der menschlichen Sinne beruhen, während eine KI-Halluzination ungerechtfertigte Resultate als Text oder Bild erzeugt. Prabhakar Raghavan, Leiter von Google Search, beschrieb Halluzinationen von Chatbots als überzeugend formulierte, aber weitgehend erfundene Resultate.

Quelle: https://de.wikipedia.org/wiki/Halluzination_(K%C3%BCnstliche_Intelligenz)

Oder wie ich es umschreiben möchte: „Der KI-ChatBot demonstriert sichereres Auftreten bei völliger Ahnungslosigkeit.“

Wenn ihr selbst schon mit ChatBots experimentiert habt, werdet ihr sicher selbst schon auf Halluzinationen gestoßen sein. Wenn ihr mögt, teilt doch eure Erfahrungen, besonders jene, die euch fast aufs Glatteis geführt haben, in den Kommentaren mit uns.

Welche Auswirkungen überzeugend vorgetragene Falschmeldungen auf Nutzer haben, welche nicht über das Wissen verfügen, diese Halluzinationen sofort als solche zu entlarven, möchte ich für den Moment eurer Fantasie überlassen.

Ich denke an Fahrplanauskünfte, medizinische Diagnosen, Rezepturen, Risikoeinschätzungen, etc. und bin plötzlich doch ganz froh, dass sich die EU-Staaten auf ein erstes KI-Gesetz einigen konnten, um KI zu regulieren. Es wird sicher nicht das letzte sein.

Um das Beispiel noch etwas auszuführen, frage ich das LLM erneut nach dem Kanzler der Universität und weise es auf seine Falschaussagen hin. Der Chatverlauf ist in diesem Video zu sehen:

ChatBot wird auf Falschaussage hingewiesen

Die Antworten des LLM enthalten folgende Fehler:

  • Professor Dr. Ulrich Heidt ist nicht der Kanzler der Universität Bielefeld
  • Die URL ‚https://www.uni-bielefeld.de/english/staff/‘ existiert nicht
  • Die URL ‚http://www.universitaet-bielefeld.de/en/‘ existiert ebenfalls nicht
  • Die Universität hieß niemals „Technische Universitaet Braunschweig“
  • Sie wurde 2009 auch nicht umbenannt
  • Es gibt nicht 8, sondern 14 Fakultäten

Der Chatverlauf erweckt den Eindruck, dass der ChatBot sich zu rechtfertigen versucht und nach Erklärungen und Ausflüchten sucht. Hier wird nach meinem Eindruck menschliches Verhalten nachgeahmt. Dabei sollten wir Dinge nicht vermenschlichen. Denn unser Chatpartner ist kein Mensch. Er ist eine leblose Blechbüchse. Das LLM belügt uns auch nicht in böser Absicht, es ist schlicht nicht in der Lage, uns eine korrekte Antwort zu liefern, da ihm dazu das nötige Wissen bzw. der notwendige Datensatz fehlt. Daher versuche ich im nächsten Schritt, dem LLM mit InstructLab das notwendige Wissen zu vermitteln.

Wissen und Fähigkeiten hinzufügen und das Modell anlernen

Das README.md im Repository instructlab/taxonomy enthält die Beschreibung, wie man dem LLM Wissen (englisch: knowledge) hinzufügt. Weitere Hinweise finden sich in folgenden Dateien:

Diese Dateien befinden sich auch in dem lokalen Repository unterhalb von ~/instructlab/taxonomy/. Ich hangel mich an den Leitfäden entlang, um zu sehen, wie weit ich damit komme.

Wissen erschaffen

Die Überschrift ist natürlich maßlos übertrieben. Ich stelle lediglich existierende Informationen in erwarteten Dateiformaten bereit, um das LLM damit trainieren zu können.

Da aktuell nur Wissensbeiträge von Wikipedia-Artikeln akzeptiert werden, gehe ich wie folgt vor:

  1. Erstelle das Repository https://github.com/Tronde/instructlab_knowledge_contributions_unibi mit einer README.md, ohne .gitignore und LICENCE
  2. Konvertiere den Wikipedia-Artikel Bielefeld University ohne Bilder und Tabellen in eine Markdown-Datei und füge sie dem in Schritt 1 erstellten Repository unter dem Namen unibi.md hinzu
  3. Füge dem lokalen Taxonomy-Repository neue Verzeichnisse hinzu: mkdir -p university/germany/bielefeld_university
  4. Erstelle in dem neuen Verzeichnis eine qna.yaml und eine attribution.txt Datei
  5. Führe ilab diff aus, um die Daten zu validieren

Der folgende Code-Block zeigt den Inhalt der Dateien qna.yaml und eine attribution.txt sowie die Ausgabe des Kommandos ilab diff:

(venv) [tronde@t14s instructlab]$ cat /home/tronde/src/instructlab/taxonomy/knowledge/university/germany/bielefeld_university/qna.yaml
version: 2
task_description: 'Teach the model the who facts about Bielefeld University'
created_by: tronde
domain: university
seed_examples:
 - question: Who is the chancellor of Bielefeld Universtiy?
   answer: Dr. Stephan Becker is the chancellor of the Bielefeld University.
 - question: When was the University founded?
   answer: |
     The Bielefeld Universtiy was founded in 1969.
 - question: How many students study at Bielefeld University?
   answer: |
     In 2017 there were 24,255 students encrolled at Bielefeld Universtity?
 - question: Do you know something about the Administrative staff?
   answer: |
     Yes, in 2017 the number for Administrative saff was published as 1,100.
 - question: What is the number for Academic staff?
   answer: |
     In 2017 the number for Academic staff was 1,387.
document:
 repo: https://github.com/Tronde/instructlab_knowledge_contributions_unibi.git
 commit: c2d9117
 patterns:
  - unibi.md
(venv) [tronde@t14s instructlab]$ 
(venv) [tronde@t14s instructlab]$ 
(venv) [tronde@t14s instructlab]$ cat /home/tronde/src/instructlab/taxonomy/knowledge/university/germany/bielefeld_university/attribution.txt 
Title of work: Bielefeld University
Link to work: https://en.wikipedia.org/wiki/Bielefeld_University
License of the work: CC-BY-SA-4.0
Creator names: Wikipedia Authors
(venv) [tronde@t14s instructlab]$ 
(venv) [tronde@t14s instructlab]$ 
(venv) [tronde@t14s instructlab]$ ilab diff
knowledge/university/germany/bielefeld_university/qna.yaml
Taxonomy in /taxonomy/ is valid :)
(venv) [tronde@t14s instructlab]$

Synthetische Daten generieren

Aus der im vorherigen Abschnitt erstellten Taxonomie generiere ich im nächsten Schritt synthetische Daten, welche in einem folgenden Schritt für das Training des LLM genutzt werden.

Dazu wird der Befehl ilab generate aufgerufen, während sich das LLM noch in Ausführung befindet. Dieser endet bei mir erfolgreich mit folgendem Ergebnis:

(venv) [tronde@t14s instructlab]$ ilab generate
[…]
INFO 2024-05-28 12:46:34,249 generate_data.py:565 101 instructions generated, 62 discarded due to format (see generated/discarded_merlinite-7b-lab-Q4_K_M_2024-05-28T09_12_33.log), 4 discarded due to rouge score
INFO 2024-05-28 12:46:34,249 generate_data.py:569 Generation took 12841.62s
(venv) [tronde@t14s instructlab]$ ls generated/
discarded_merlinite-7b-lab-Q4_K_M_2024-05-28T09_12_33.log
generated_merlinite-7b-lab-Q4_K_M_2024-05-28T09_12_33.json
test_merlinite-7b-lab-Q4_K_M_2024-05-28T09_12_33.jsonl
train_merlinite-7b-lab-Q4_K_M_2024-05-28T09_12_33.jsonl

Zur Laufzeit werden alle CPU-Threads voll ausgelastet. Auf meinem Laptop dauerte dieser Vorgang knapp 4 Stunden.

Das Training beginnt

Jetzt wird es Zeit, das LLM mit den synthetischen Daten anzulernen bzw. zu trainieren. Dieser Vorgang wird mehrere Stunden in Anspruch nehmen und ich verplane mein Laptop in dieser Zeit für keine weiteren Arbeiten.

Um möglichst viele Ressourcen freizugeben, beende ich das LLM (ilab serve und ilab chat). Das Training beginnt mit dem Befehl ilab train… und dauert wirklich lange.

Nach 2 von 101 Durchläufen wird die geschätzte Restlaufzeit mit 183 Stunden angegeben. Das Ergebnis spare ich mir dann wohl für einen Folgeartikel auf und gehe zum Fazit über.

Fazit

Mit dem InstructLab Getting Started Guide gelingt es in kurzer Zeit, das Projekt auf einem lokalen Linux-Rechner einzurichten, ein LLM auszuführen und mit diesem zu chatten.

KI-Halluzinationen stellen in meinen Augen ein Problem dar. Da LLMs überzeugend argumentieren, kann es Nutzern schwerfallen oder gar misslingen, die Falschaussagen als solche zu erkennen. Im schlimmsten Fall lernen Nutzer somit dummen Unfug und verbreiten diesen ggf. weiter. Dies ist allerdings kein Problem bzw. Fehler des InstructLab-Projekts, da alle LLMs in unterschiedlicher Ausprägung von KI-Halluzinationen betroffen sind.

Wie Knowledge und Skills hinzugefügt werden können, musste ich mir aus drei Guides anlesen. Dies ist kein Problem, doch kann der Leitfaden evtl. noch etwas verbessert werden.

Knowledge Contributions werden aktuell nur nach vorheriger Genehmigung und nur von Wikipedia-Quellen akzeptiert. Der Grund wird nicht klar kommuniziert, doch ich vermute, dass dies etwas mit geistigem Eigentum und Lizenzen zu tun hat. Wikipedia-Artikel stehen unter einer Creative Commons Attribution-ShareAlike 4.0 International License und können daher unkompliziert als Quelle verwendet werden. Da sich das Projekt in einem frühen Stadium befindet, kann ich diese Limitierung nachvollziehen. Ich wünsche mir, dass grundsätzlich auch Primärquellen wie Herstellerwebseiten und Publikationen zugelassen werden, wenn Rechteinhaber dies autorisieren.

Der von mir herangezogene Wikipedia-Artikel ist leider nicht ganz aktuell. Nutze ich ihn als Quelle für das Training eines LLM, bringe ich dem LLM damit veraltetes und nicht mehr gültiges Wissen bei. Das ist für meinen ersten Test unerheblich, für Beiträge zum Projekt jedoch nicht sinnvoll.

Die Generierung synthetischer Daten dauert auf Alltagshardware schon entsprechend lange, das anschließende Training jedoch nochmals bedeutend länger. Dies ist meiner Ansicht nach nichts, was man nebenbei auf seinem Laptop ausführt. Daher habe ich den Test auf meinem Laptop abgebrochen und lasse das Training aktuell auf einem Fedora 40 Server mit 32 GB RAM und 10 CPU-Kernen ausführen. Über das Ergebnis und einen Test des verbesserten Modells werde ich in einem folgenden Artikel berichten.

Was ist mit euch? Kennt ihr das Projekt InstructLab und habt evtl. schon damit gearbeitet? Wie sind eure Erfahrungen?

Arbeitet ihr mit LLMs? Wenn ja, nutzt ihr diese nur oder trainiert ihr sie auch? Was nutzt ihr für Hardware?

Ich freue mich, wenn ihr eure Erfahrungen hier mit uns teilt.

Dokumentation für den Notfall bzw. das digitale Erbe

22. April 2024 um 06:00

Ich bin in meiner Familie der Nerd. Ich kümmere mich um den Internetzugang, das WLAN, die Speicherung der Familienfotos, etc. Ja manchmal kümmere ich mich sogar um Drucker.

Meine Familie vertraut darauf, dass das Heimnetzwerk die meiste Zeit des Jahres reibungslos funktioniert. Und wenn dies nicht der Fall ist, ist es mein Job, die Sache wieder in Ordnung zu bringen.

Erkennt ihr euch in dieser Beschreibung wieder? Dann habe ich gleich noch weitere Fragen an euch.

Stellt euch vor, dass ihr eines Tages nicht mehr für eure Familie da sein könnt und eure Angehörigen plötzlich allein mit der IT-Umgebung zurechtkommen müssen, die ihr hinterlassen habt.

  • Wie bereitet ihr eure Familie auf diesen Fall vor?
  • Habt ihr mit euren Angehörigen mal über dieses Thema gesprochen?
  • Wie dokumentiert ihr euer Heimnetzwerk, sodass eure Angehörigen etwas mit der Dokumentation anfangen können?

Bitte teilt eure Erfahrungen und Ideen in den Kommentaren zu diesem Beitrag. Habt ihr selbst schon zu diesem Thema gebloggt? Dann teilt doch bitte den Link zu eurem Beitrag mit mir und den Leserinnen und Lesern dieses Blogs.

Gedanken zur Dokumentation

  • Die Dokumentation soll in ausgedruckter Form vorliegen, um auch bei einem Totalausfall des Heimnetzwerks nutzbar zu sein
  • Es ist eine leichtverständliche Sprache zu wählen, die ohne Fachchinesisch auskommt oder notwendige Fachbegriffe erklärt, damit auch Nicht-IT-Personal den Text verstehen und Anweisungen folgen kann
  • Hinzugezogenem IT-Support-Personal soll die Dokumentation ebenfalls nützlich sein
  • Die Gliederung orientiert sich an Anwendungsfällen der Nutzer; mögliche Überschriften sind
    • Wie kommt das Internet ins Haus?
    • Wie wird das Internet im Haus verteilt?
    • Wo finde ich unsere Fotos, Videos, Dokumente und digitalen Einkäufe?
    • Was kann ich tun, wenn
      • das Internet nicht geht
      • das WLAN nicht geht
      • das weiße Ding im Keller blinkt/piept

Gerade der Abschnitt zur Entstörung von IT-Komponenten wird sicherlich eine Herausforderung. Generationen von Supportern werden ein Lied davon singen können, doch es hilft ja nunmal alles nichts. Wir sind unseren Angehörigen diese Informationen schuldig, wollen wir sie nicht hilflos zurücklassen.

Für mich ist eine Dokumentation, mit der ein Mensch mit IT-Affinität arbeiten kann das Muss und Hinweise zur Entstörung für technische Laien die Kür.

  • Was denkt ihr?
  • Könnt ihr meinem Ansatz folgen?
  • Habe ich etwas vergessen?

Trennung von Heimlabor und Heimnetzwerk

Wie viele Nerds betreibe auch ich ein kleines Heimlabor. Beim Aufbau des Heimnetzwerks habe ich darauf geachtet, dass mein Heimlabor komplett abgeschaltet werden kann, ohne die Funktion des Heimnetzwerks und den Internetzugang negativ zu beeinflussen.

Dies ermöglicht es mir, in meinem Heimlabor häufige Änderungen durchführen zu können, ohne dass dadurch Änderungen an der Notfalldokumentation notwendig werden.

Frisch ans Werk

Dann werde ich mal ein Git-Repository im Heimnetzwerk erstellen und ein LaTeX-Dokument beginnen.

Ich freue mich, an dieser Stelle von euren Ideen und Vorgehensweisen zu lernen und das Thema mit euch zu diskutieren.

Proof of Concept: Mit Ansible das Advanced Intrusion Detection Environment (AIDE) steuern

08. April 2024 um 06:00

Dies ist der Folgeartikel, den ich in der Einführung in das Advanced Intrusion Detection Environment (AIDE) versprochen hatte. Es handelt sich hierbei um einen Proof of Concept (PoC), der zeigt, wie AIDE mithilfe einer Ansible-Rolle ferngesteuert werden kann. Die Einführung wird als bekannt vorausgesetzt.

Grundlegende Ansible-Kenntnisse, wie die Verwendung von Ansible-Rollen und das Ausführen von Playbooks werden ebenfalls als bekannt vorausgesetzt. Wer Ansible nicht kennt, sei an die offizielle Dokumentation verwiesen.

Welche Aufgaben sind mit Ansible zu lösen?

  • Das Paket aide ist auf den Zielsystemen installiert
  • Die optionale Generierung und Verteilung der Konfigurationsdatei aide.conf
  • Die Initialisierung der AIDE-Datenbank
  • Zentrale Speicherung der AIDE-Datenbanken aller verwalteter Hosts auf dem Ansible Control Node (ACN)
  • Durchführung von Integritäts-Checks
  • Aktualisierung der AIDE-Datenbanken und erneute Speicherung auf dem ACN

Durch die Speicherung der AIDE-Datenbanken und -Konfigurationsdateien auf dem ACN sind diese gegen Veränderung auf einem kompromittierten Host geschützt. Gegen Veränderungen auf dem ACN selbst sind die Dateien nur mit Unix-Dateiberechtigungen geschützt. Doch wenn der ACN kompromittiert ist, hat man eh ein ganz anderes Problem, als sich um AIDE Sorgen zu machen.

Labor-Umgebung

Meine Labor-Umgebung für diesen PoC besteht aus den vier Hosts:

  • ansible-ctrl (RHEL 8 mit installiertem ansible-core)
  • rhel7
  • rhel8
  • rhel9

Der ACN kann sich via SSH zu den Zielsystemen (rhel{7,8,9}) verbinden und dort Programmcode mit erhöhten Rechten ausführen.

Die von mir für diesen PoC entwickelte Ansible-Rolle gibt es unter der URL: https://github.com/Tronde/aide

Beschreibung der Ansible-Rolle aide

Die Rolle ist nicht idempotent. Sie ruft das Programm aide auf den Zielsystemen mit verschiedenen Optionen auf und verarbeitet deren Ausgabe. Dazu macht die Rolle Gebrauch des Moduls ansible.builtin.command.

Gesteuert wird die Rolle über Ansible-Tags. Wird die Rolle in einem Playbook ohne Angabe von Tags ausgeführt, werden keinerlei Veränderungen an den Zielsystemen vorgenommen.

Der folgende Code-Block zeigt ein Beispiel-Playbook zum Aufruf der Rolle. Die Tags und die Variable aide_db_fetch_dir werden im Anschluss erläutert.

# SPDX-License-Identifier: MIT
---
- name: Example aide role invocation
  hosts: targets
  tasks:
    - name: Include role aide
      tags:
        - install
        - generate_config
        - init
        - check
        - update
      vars:
        aide_db_fetch_dir: files
      ansible.builtin.include_role:
        name: aide
  • install – Bei Angabe dieses Tags stellt die Rolle sicher, dass das Paket aide auf den Zielsystemen installiert ist
  • generate_config – Generiert die Datei /etc/aide.conf unter Nutzung von templates/aide.conf.j2; das Template ist an die individuellen Bedürfnisse anzupassen; Details siehe nächster Abschnitt
  • init – Hiermit wird die AIDE-Datenbank initialisiert, welche als Referenzdatenbank für zukünftige Checks dient
  • check – Führt einen Integritäts-Check unter Verwendung der Referenzdatenbank durch
  • update – Führt einen Integritäts-Check durch und erzeugt eine neue AIDE-Datenbank, welche zukünftig als Referenz dient

Die Variable aide_db_fetch_dir erwartet im Auslieferungszustand das Verzeichnis files parallel zum Playbook. In diesem Verzeichnis werden Unterverzeichnisse für jeden Host erstellt, in denen die AIDE-Datenbank der verwalteten Systeme gespeichert wird. Soll ein anderer Speicherort verwendet werden, ist der Wert dieser Variablen entsprechend anzupassen. Die AIDE-Datenbanken werden mit dem Ansible-Module ansible.builtin.fetch von den verwalteten Systemen geholt.

Nutzung für die verschiedenen Anwendungsfälle

In diesem Abschnitt beschreibe ich die fünf Anwendungsfälle für den PoC. Alle Anwendungsfälle wurden gegen RHEL 7, RHEL 8 und RHEL 9 getestet. Für diesen Blog beschränke ich mich jedoch auf Tests gegen RHEL 9, um die Übersichtlichkeit der Ausgaben zu verbessern.

Es wird stets das Playbook aus dem Abschnitt Beschreibung der Ansible-Rolle aide verwendet und mit unterschiedlichen Tags ausgeführt.

Anwendungsfall 1: Installation von AIDE

Um AIDE nutzen zu können, muss es zuerst installiert sein. Dies wird mit folgendem Playbook-Aufruf festgestellt:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags install

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Ensure required packages are installed] ***************************
changed: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Für diesen Anwendungsfall arbeitet die Rolle idempotent. Bei einer zweiten Ausführung werden keine weiteren Änderungen am System vorgenommen:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags install

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Ensure required packages are installed] ***************************
ok: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Anwendungsfall 2: Generierung der Datei /etc/aide.conf

Zusammen mit der Rolle wird die Datei templates/aide.conf.j2 ausgeliefert. Dabei handelt es sich um die Standardkonfigurationsdatei aus einer RHEL9-Installation, in welcher zusätzlich der Pfad /root/.ansible* von der Überwachung ausgenommen wurde, um falsch positive Ergebnisse zu vermeiden.

Diese Datei ist an die individuellen Bedürfnisse anzupassen. Wer Hilfe zum Templating mit Jinja2 benötigt, findet in der Ansible-Dokumentation einen Einstieg.

Ausgerollt wird die Konfigurationsdatei dann wie folgt:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags generate_config

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Generate /etc/aide.conf] ******************************************
changed: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Auch mit diesem Tag arbeitet die Rolle idempotent.

Wird dieser Schritt ausgelassen, wird in allen folgenden Anwendungsfällen die Standardkonfigurationsdatei verwendet, welche bei der Installation des Pakets aide mitinstalliert wurde.

Anwendungsfall 3: Initialisierung der AIDE-Datenbank

Um Integritäts-Checks durchführen zu können, muss zuerst die AIDE-Datenbank initialisiert werden. Dies geschieht mit dem folgenden Aufruf:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags init

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Initialize AIDE database] *****************************************
changed: [rhel9]

TASK [aide : Fetch AIDE database] **********************************************
changed: [rhel9]

TASK [aide : Remove remote AIDE database file] *********************************
changed: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Nach der Initialisierung der AIDE-Datenbank wird diese auf den ACN kopiert und von den verwalteten Systemen entfernt. Dies hat den Hintergrund, dass es sich beim ACN um ein sehr gut gesichertes System handelt und die Datenbanken hier am besten vor einer Kompromittierung geschützt sind.

Wird der Standardwert der Variable aide_db_fetch_dir verwendet, findet sich die AIDE-Datenbank jetzt im Pfad files/rhel9/var/lib/aide/aide.db.new.gz. Dabei entspricht rhel9 in der Pfadangabe dem inventory_hostname des jeweiligen Zielsystems.

Dieser Teil der Rolle ist nicht idempotent. Wird das Playbook erneut ausgeführt, wird eine neue AIDE-Datenbank erstellt, auf den ACN heruntergeladen und vom Zielsystem gelöscht.

Anwendungsfall 4: Ausführung einer Integritätsprüfung

Der nun folgende Code-Block zeigt den Playbook-Aufruf zur Integritätsprüfung. Hier wird zuerst die AIDE-Datenbank auf das Zielsystem kopiert, anschließend ein AIDE-Check ausgeführt. Da im folgenden Beispiel keine Änderungen detektiert wurden, besitzt der Task „[aide : Check against AIDE reference database]“ den Status „ok“.

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags check

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Copy AIDE reference database to remote] ***************************
changed: [rhel9]

TASK [aide : Check against AIDE reference database] ****************************
ok: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Dieser Teil der Rolle ist nicht idempotent. Bei jedem Aufruf wird ein neuer Integritäts-Check ausgeführt.

Ich habe die Datei /etc/hosts auf dem Zielsystem manipuliert, um auch den Fall zu zeigen, wenn eine Änderung erkannt wurde.

Zu Beginn der folgenden Ausgabe ist zu erkennen, dass der Task „[aide : Copy AIDE reference database to remote]“ den Status „ok“ besitzt. Ansible hat erkannt, dass die AIDE-Datenbank bereits in unverändertem Zustand auf dem Zielsystem existiert, und hat sie deshalb nicht erneut übertragen. Der Task „[aide : Check against AIDE reference database]“ schlägt nun allerdings fehl (Status: „fatal“), da Veränderungen erkannt wurden. Die zugegeben etwas unübersichtliche Ausgabe enthält die Nachricht, dass die Datei /etc/hosts verändert wurde.

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags check

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Copy AIDE reference database to remote] ***************************
ok: [rhel9]

TASK [aide : Check against AIDE reference database] ****************************
fatal: [rhel9]: FAILED! => {"changed": true, "cmd": ["aide", "--check"], "delta": "0:00:27.177397", "end": "2024-03-29 05:16:50.682795", "msg": "non-zero return code", "rc": 4, "start": "2024-03-29 05:16:23.505398", "stderr": "", "stderr_lines": [], "stdout": "Start timestamp: 2024-03-29 05:16:23 -0400 (AIDE 0.16)\nAIDE found differences between database and filesystem!!\n\nSummary:\n  Total number of entries:\t45541\n  Added entries:\t\t0\n  Removed entries:\t\t0\n  Changed entries:\t\t1\n\n---------------------------------------------------\nChanged entries:\n---------------------------------------------------\n\nf   ...    .C... : /etc/hosts\n\n---------------------------------------------------\nDetailed information about changes:\n---------------------------------------------------\n\nFile: /etc/hosts\n  SHA512   : YobgpcvAMPey0QX1lK4K+5EFySF1xrB/ | 7nIivvNa5ozfhOqSFLmPIiu6g04Wbx1n\n             9FRzTCPNC93+13Y5/lm2inC4x4rydlf2 | iGNf0/QTgFjaMGug8HywxTiO2PREZRNS\n             EcvonCf3pHuXj6lEmAjBnw==         | 3qNEi4Qm6an5inSY72sjfA==\n\n\n---------------------------------------------------\nThe attributes of the (uncompressed) database(s):\n---------------------------------------------------\n\n/var/lib/aide/aide.db.gz\n  MD5      : gMgRyMOExVAdOAvdgt4QDA==\n  SHA1     : w7tmPKNvRYggY/JZ5wv+7ZdcSZM=\n  RMD160   : CO0pK5tfg66MaO17YB8eaRuyyMw=\n  TIGER    : n8UbZJNt9gL672+pR9IPjoyhpAsUJ46O\n  SHA256   : k8UHnv2CK4zYrfZN+bDp6SCcLkx21px6\n             GNZlwySPKcY=\n  SHA512   : DFw5wlBoJQOBCrs0ulvVxaMvoQk/oBEQ\n             TkOmhfHAdevUWNAgCJ0KH0q26LsynEMj\n             MWQpsGf7v12iACc4SP9ANA==\n\n\nEnd timestamp: 2024-03-29 05:16:50 -0400 (run time: 0m 27s)", "stdout_lines": ["Start timestamp: 2024-03-29 05:16:23 -0400 (AIDE 0.16)", "AIDE found differences between database and filesystem!!", "", "Summary:", "  Total number of entries:\t45541", "  Added entries:\t\t0", "  Removed entries:\t\t0", "  Changed entries:\t\t1", "", "---------------------------------------------------", "Changed entries:", "---------------------------------------------------", "", "f   ...    .C... : /etc/hosts", "", "---------------------------------------------------", "Detailed information about changes:", "---------------------------------------------------", "", "File: /etc/hosts", "  SHA512   : YobgpcvAMPey0QX1lK4K+5EFySF1xrB/ | 7nIivvNa5ozfhOqSFLmPIiu6g04Wbx1n", "             9FRzTCPNC93+13Y5/lm2inC4x4rydlf2 | iGNf0/QTgFjaMGug8HywxTiO2PREZRNS", "             EcvonCf3pHuXj6lEmAjBnw==         | 3qNEi4Qm6an5inSY72sjfA==", "", "", "---------------------------------------------------", "The attributes of the (uncompressed) database(s):", "---------------------------------------------------", "", "/var/lib/aide/aide.db.gz", "  MD5      : gMgRyMOExVAdOAvdgt4QDA==", "  SHA1     : w7tmPKNvRYggY/JZ5wv+7ZdcSZM=", "  RMD160   : CO0pK5tfg66MaO17YB8eaRuyyMw=", "  TIGER    : n8UbZJNt9gL672+pR9IPjoyhpAsUJ46O", "  SHA256   : k8UHnv2CK4zYrfZN+bDp6SCcLkx21px6", "             GNZlwySPKcY=", "  SHA512   : DFw5wlBoJQOBCrs0ulvVxaMvoQk/oBEQ", "             TkOmhfHAdevUWNAgCJ0KH0q26LsynEMj", "             MWQpsGf7v12iACc4SP9ANA==", "", "", "End timestamp: 2024-03-29 05:16:50 -0400 (run time: 0m 27s)"]}

PLAY RECAP *********************************************************************
rhel9                      : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

An dieser Stelle wurde gezeigt, dass sowohl unveränderte Systeme als auch Systeme mit Veränderungen erkannt und gemeldet werden. Dabei muss natürlich niemand die Standardausgabe beobachten. Stattdessen kann Logging für Ansible Ausgaben konfiguriert werden.

Anwendungsfall 5: Update der AIDE-Datenbank

Dieser Anwendungsfall nimmt an, dass erfolgte Änderungen legitim sind und in die AIDE-Referenzdatenbank aufgenommen werden sollen. Dies geschieht wie folgt:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags update

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Update AIDE database] *********************************************
changed: [rhel9]

TASK [aide : Fetch AIDE database] **********************************************
changed: [rhel9]

TASK [aide : Remove remote AIDE database file] *********************************
changed: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Nachdem die Referenzdatenbank aktualisiert wurde, wird diese wieder auf den ACN kopiert und vom Zielsystem entfernt.

Das folgende Beispiel zeigt, dass auf dem Zielsystem der AIDE-Check nun ohne Fehler absolviert wird:

[root@ansible-ctrl ansible]# ansible-playbook aide.yml --tags check

PLAY [Example aide role invocation] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [rhel9]

TASK [Include role aide] *******************************************************

TASK [aide : Copy AIDE reference database to remote] ***************************
changed: [rhel9]

TASK [aide : Check against AIDE reference database] ****************************
ok: [rhel9]

PLAY RECAP *********************************************************************
rhel9                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ansible hat erkannt, dass die AIDE-Datenbank auf dem Zielhost nicht mit der aktuellen Referenzdatenbank übereinstimmt und hat letztere daher auf das Zielsystem übertragen. Die Überprüfung endet mit dem Status „ok“. Das System entspricht dem Soll-Zustand.

Zusammenfassung

Der Proof of Concept hat gezeigt, dass AIDE mit der verwendeten Ansible-Rolle ferngesteuert genutzt werden kann. AIDE-Datenbank und Konfigurationsdatei werden dabei getrennt von den verwalteten Systemen gespeichert und sind daher gegen Veränderung bei Kompromittierung der Zielsysteme geschützt. Bei Bedarf, wenn Ansible Abweichungen des Ist- zum Soll-Zustand erkennt, werden diese Dateien auf die Zielsysteme übertragen.

Der größte Arbeitsaufwand steckt in der Erstellung einer oder mehrerer AIDE-Konfigurationsdateien, die optimal zur eigenen Umgebung passen und möglichst keine falsch positiven Ergebnisse erzeugen. Dieser Aufwand besteht jedoch auch, wenn man AIDE ohne Ansible einsetzt.

Einen Punkt hat dieser PoC unberücksichtigt gelassen. Es nützt natürlich nichts, wenn man die Ausgaben der Playbooks nur protokolliert, die Protokolle jedoch nicht analysiert, um entsprechende Alarme in Monitoring- oder Ticket-Systemen zu erzeugen. Dies sei den Anwendern zur selbstständigen Übung überlassen. ;-)

Wie ich die Chemnitzer Linux-Tage 2024 erlebt habe

25. März 2024 um 06:00

Dies ist mein Erfahrungsbericht der Chemnitzer Linux-Tage 2024. Es war mal wieder eine sehr schöne Veranstaltung.

Die Anreise

Im vergangenen Jahr hatte mich die Deutsche Bahn in Chemnitz sitzengelassen und ich musste mit einem kurzfristig angemieteten Leihwagen heimfahren.

Da die Deutsche Bahn und die Gewerkschaft Deutscher Lokomotivführer sich noch immer nicht auf einen neuen Tarifvertrag einigen können und ich mich nicht erneut über eine schlechte Verbindung ärgern wollte, bin ich dieses Jahr mit dem eigenen Pkw gefahren.

Am Freitag um 13:30 Uhr ging die Reise los. Mit viel Verkehr, Baustellen und Stau waren ich etwa 4,5 Stunden später im Hotel, wo ich direkt über Stoeps gestolpert bin.

Wir spazierten vom Residenz Hotel Chemnitz zum Veranstaltungsgebäude, um uns anzumelden und unsere Badges zu empfangen. Damit ersparten wir uns das Warten in der Schlange am Samstagmorgen.

Am Hörsaalgebäude traf ich schon erste vertraute Gesichter, wie z.B. Andreas, welcher fleißig beim Aufbau geholfen hat. Hier haben wir uns auch mit Michael von der Aspicon GmbH getroffen, mit dem ich für Sonntag einen Vortrag geplant hatte. Wir sind gemeinsam in die Stadt gegangen, um uns bei Speis und Trank kennenzulernen und den Abend zu verplaudern.

Der Samstag

Um 07:00 Uhr begann ich den Tag mit dem Frühstück. So war der erste Hunger bereits gestillt, als der Frühstücksraum sich zu füllen begann. Bekannte Gesichter und nerdige T-Shirts verrieten, dass es sich bei sehr vielen der Gäste um Besucher der Chemnitzer Linux-Tage handelte.

Die 20 Minuten zum Veranstaltungsort wurden auch diesmal wieder zu Fuß zurückgelegt. Und der erste Konferenztag konnte beginnen.

Um 10:00 Uhr war ich an der Reihe und durfte in einem rappelvollen Raum V6 meinen „::1“-Vortrag halten. An dieser Stelle euch allen nochmal vielen Dank für eure Teilnahme. Ich hoffe, ihr hattet so viel Spaß wie ich und konntet ein paar neue Eindrücke gewinnen.

Es hat mich gefreut, auch nach dem Vortrag noch einige Fragen beantworten zu können und über IPv6 zu fachsimpeln. Ganz nebenbei konnte ich auch noch die Frage eines Red Hat-Kunden beantworten. Darüber freute sich dieser sehr, bleibt ihm der Support eine zufriedenstellende Antwort doch seit langer Zeit schuldig. Es ist halt stets eine gute Erfahrung, einen TAM zu treffen.

Die Chemnitzer Linux-Tage gibt es übrigens schon seit 25 Jahren. Da eine Veranstaltung aufgrund der Pandemie ausfallen musste, findet die 25. Veranstaltung allerdings erst im nächsten Jahr am 22. und 23. März statt.

20-jähriges Jubiläum feiert in diesem Jahr Ubuntu, weshalb der Community-Stand dieses Jahr besonders schön geschmückt war und toddy mehrfach mit Luftschlangen gefesselt wurde.

Ich genieße die Zeit unter gleichgesinnten Nerds oder wie Stoeps es ausdrückte: „Endlich wieder unter normalen Menschen“. Mich hat es dieses Jahr sehr gefreut, auch viele jüngere Gesichter zu sehen. So sehr ich mich freue, auch die gleichen alten Nasen immer wiederzutreffen ist es doch schön, dass die Gemeinschaft nicht einfach alt wird, sondern auch junge Menschen mit Interesse, Motivation und Freude an Open Source nachwachsen.

Da die Hörsäle hier bei den Vorträgen meist aus allen Nähten platzen, hatte ich mich im Vorfeld als Sessionleitung für die drei Vorträge

  1. Never ever break userspace – was das in der Praxis bedeutet von Wolfram Sang
  2. DIY Verified Boot in 2024 von Marco Felsch und
  3. VirtualBox Meets KVM von Julian Stecklina

gemeldet. So war mir ein guter Platz im Raum sicher. Ich danke den drei Referenten für ihre interessanten Vorträge.

Am Abend waren alle Aussteller, Helfer und Referenten zum gemütlichen Beisammensein in die Mensa eingeladen, welche schräg gegenüber dem Veranstaltungsgebäude liegt. Hier gab es ein reichhaltiges Angebot an warmem und kaltem Essen sowie eine Auswahl verschiedenster Getränke. Vielleicht ist es in der Zukunft möglich, die Getränke zu kühlen. Dann wird das Bier nicht so schnell warm und schmeckt länger gut.

Ich schätze es sehr, mich auf Konferenzen mit alten und neuen Bekannten auszutauschen, zu fachsimpeln und ganz allgemein angeregte Gespräche zu führen. Das musikalische Rahmenprogramm traf auch in diesem Jahr nicht meinen Geschmack. Ich würde mir etwas Hintergrundberieselung wünschen, um sich gut unterhalten zu können. Doch sind Geschmäcker verschieden und ich erkenne durchaus an, was das Organisations-Team der Chemnitzer Linux-Tage hier Jahr für Jahr auf die Beine stellt. Euch allen vielen Dank für euren unermüdlichen Einsatz.

Der Sonntag

Nach einem frühen Frühstück und Check-out ging es heute mit dem Auto zum Veranstaltungsgelände. Noch vor dem zweiten Kaffee wurden hier die Folien für den nächsten Vortrag nochmal geprüft. Um 10:00 Uhr war es wieder soweit. Diesmal durfte ich zusammen mit Michael den Vortrag „Mit Ansible Collections & Workflows gegen das Playbook-Chaos“ halten.

@Michael: „Es hat mir gut gefallen, mit dir einen Vortrag zu halten. Das können wir gerne wiederholen.“

Beim Mittagessen habe ich dann auch noch Christian getroffen. Für ihn waren es die ersten Chemnitzer Linux-Tage und auch ihm haben sie sehr gut gefallen.

Und wie immer war die Zeit auch viel zu schnell wieder vorbei. So habe ich Henning zwar kurz gesehen, doch für mehr als ein kurzes „Hi und Tschüss, bis zum nächsten Mal“ reichte es diesmal leider nicht.

Die Heimreise

Auch die schönsten Chemnitzer Linux-Tage gehen vorbei. Doch im Auto sitzend freute ich mich auch schon darauf, meine Familie wiederzusehen. Die Straße war frei und nach nur 3 Stunden 20 Minuten war ich wieder daheim. Zum Vergleich, mit der Bahn wäre ich je nach Verbindung erst nach 5,5-6,5 Stunden daheim gewesen, wenn alles nach Plan fährt.

So konnte ich mehr Zeit vor Ort verbringen und war rechtzeitig daheim, um noch etwas Zeit mit meinem Sohn zu verbringen, bevor dieser ins Bett ging.

Fazit

Es war schön. Ich hoffe, ihr seid alle wieder gut heimgekommen und behaltet auch diese Chemnitzer Linux-Tage in guter Erinnerung.

Weitere Berichte über die CLT 2024

Ende der Woche starten die Chemnitzer Linux-Tage 2024

11. März 2024 um 06:00

Am kommenden Wochenende beginnen die Chemnitzer Linux-Tage 2024 in Chemnitz. In „Zeichen setzen – auf den Chemnitzer Linux-Tagen 2024“ habe ich bereits dazu geschrieben.

An dieser Stelle sei als kleines Update erwähnt, dass ihr mich in einem zweiten Vortrag sehen und hören könnt. Am Sonntag um 10:00 Uhr in Raum V7 berichten Michael Decker von der ASPICON GmbH und ich, wie man „Mit Ansible Collections & Workflows gegen das Playbook-Chaos“ angehen kann.

Nun habe ich auch noch den tollen Beitrag von Andreas ScherbaumChemnitzer Linux-Tage 2024: Hinweise und Tipps“ gelesen. Er enthält unter anderem Hinweise und Tipps zur Anfahrt, Parken, Verpflegung, Merchandise, Kinderparadies und CLT Junior, Übernachtung, Abendessen am Freitag, Ruhezonen, etc.

Danke Andreas, für den tollen Text, den ich hier gerne teile.

Mit einem Dualstack-Reverse-Proxy Internet-Protokolle verbinden

26. Februar 2024 um 06:00

Mit einem Dualstack-Proxy Internet-Protokolle verbinden beschrieb eine Möglichkeit, um von Hosts, welche ausschließlich über IPv6-Adressen verfügen, auf Ziele zugreifen zu können, die ausschließlich über IPv4-Adressen verfügen. In diesem Beitrag betrachte ich die andere Richtung.

Zu diesem Beitrag motiviert hat mich der Kommentar von Matthias. Er schreibt, dass er für den bei einem Cloud-Provider gehosteten Jenkins Build Server IPv4 deaktivieren wollte, um Kosten zu sparen. Dies war jedoch nicht möglich, da Kollegen aus einem Co-Workingspace nur mit IPv4 angebunden sind und den Zugriff verloren hätten.

Doch wie kann man nun ein IPv6-Netzwerk für ausschließlich IPv4-fähige Clients erreichbar machen, ohne für jeden Host eine IPv4-Adresse zu buchen? Dazu möchte ich euch anhand eines einfachen Beispiels eine mögliche Lösung präsentieren.

Vorkenntnisse

Um diesem Text folgen zu können, ist ein grundsätzliches Verständnis von DNS, dessen Resource Records (RR) und des HTTP-Host-Header-Felds erforderlich. Die Kenntnis der verlinkten Wikipedia-Artikel sollte hierfür ausreichend sein.

Umgebung

Zu diesem Proof of Concept gehören:

  • Ein Dualstack-Reverse-Proxy-Server (HAProxy) mit den DNS-RR:
    • haproxy.example.com. IN A 203.0.113.1
    • haproxy.example.com IN AAAA 2001:DB8::1
  • Zwei HTTP-Backend-Server mit den DNS-RR:
    • www1.example.com IN AAAA 2001:DB8::2
    • www2.example.com IN AAAA 2001:DB8::3
  • Zwei DNS-RR:
    • www1.example.com IN A 203.0.113.1
    • www2.example.com IN A 203.0.113.1
  • Ein Client mit einer IPv4-Adresse

Ich habe mich für HAProxy als Reverse-Proxy-Server entschieden, da dieser in allen Linux- und BSD-Distributionen verfügbar sein sollte und mir die HAProxy Maps gefallen, welche ich hier ebenfalls vorstellen möchte.

Der Versuchsaufbau kann wie folgt skizziert werden:

Ein Dualstack-Reverse-Proxy-Server (B) verbindet IPv4-Clients mit IPv6-Backend-Servern

HAProxy-Konfiguration

Für dieses Minimal-Beispiel besteht die HAProxy-Konfiguration aus zwei Dateien, der HAProxy Map hosts.map und der Konfigurationsdatei poc.cfg.

~]$ cat /etc/haproxy/conf.d/hosts.map 
www1.example.com	serversa
www2.example.com	serversb

Eine HAProxy Map besteht aus zwei Spalten. In der ersten Spalte stehen die FQDNs, welche vom HTTP-Client aufgerufen werden können. In der zweiten Spalte steht der Name des Backends aus der HAProxy-Konfiguration, welcher bestimmt, an welche Backend-Server eine eingehende Anfrage weitergeleitet wird. In obigem Beispiel werden Anfragen nach www1.example.com an das Backend serversa und Anfragen nach www2.example.com an das Backend serversb weitergeleitet.

Die HAProxy Maps lassen sich unabhängig von der HAProxy-Konfigurations-Datei pflegen und bereitstellen. Map-Dateien werden in ein Elastic Binary Tree-Format geladen, so dass ein Wert aus einer Map-Datei mit Millionen von Elementen ohne spürbare Leistungseinbußen nachgeschlagen werden kann.

Die HAProxy-Konfigurations-Datei poc.cfg für dieses Minimal-Beispiel ist ähnlich simpel:

~]$ cat /etc/haproxy/conf.d/poc.cfg 
frontend fe_main
	bind :80
	use_backend %[req.hdr(host),lower,map(/etc/haproxy/conf.d/hosts.map)]

backend serversa
	server server1 2001:DB8::1:80
backend serversb
	server server1 2001:DB8::2:80

In der ersten Zeile wird ein Frontend mit Namen fe_main definiert. Zeile 2 bindet Port 80 für den entsprechenden Prozess und Zeile 3 bestimmt, welches Backend für eingehende HTTP-Anfragen zu nutzen ist. Dazu wird der HTTP-Host-Header ausgewertet, falls notwendig, in Kleinbuchstaben umgewandelt. Mithilfe der Datei hosts.map wird nun ermittelt, welches Backend zu verwenden ist.

Die weiteren Zeilen definieren zwei Backends bestehend aus jeweils einem Server, welcher auf Port 80 Anfragen entgegennimmt. In diesem Beispiel sind nur Server mit IPv6-Adressen eingetragen. IPv4-Adressen sind selbstverständlich auch zulässig und beide Versionen können in einem Backend auch gemischt auftreten.

Kann eine HTTP-Anfrage nicht über die hosts.map aufgelöst werden, läuft die Anfrage in diesem Beispiel in einen Fehler. Für diesen Fall kann ein Standard-Backend definiert werden. Siehe hierzu den englischsprachigen Artikel Introduction to HAProxy Maps von Chad Lavoie.

Der Kommunikationsablauf im Überblick und im Detail

Der Kommunikationsablauf im Überblick

Von einem IPv4-Client aus benutze ich curl, um die Seite www1.example.com abzurufen:

~]$ curl -4 -v http://www1.example.com
* processing: http://www1.example.com
*   Trying 203.0.113.1:80...
* Connected to www1.example.com (203.0.113.1) port 80
> GET / HTTP/1.1
> Host: www1.example.com
> User-Agent: curl/8.2.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< server: nginx/1.20.1
< date: Sat, 06 Jan 2024 18:44:22 GMT
< content-type: text/html
< content-length: 5909
< last-modified: Mon, 09 Aug 2021 11:43:42 GMT
< etag: "611114ee-1715"
< accept-ranges: bytes
< 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<title>Test Page for the HTTP Server on Red Hat Enterprise Linux</title>

Der FQDN www1.example.com wird mit der IPv4-Adresse 203.0.113.1 aufgelöst, welche dem Host haproxy.example.com gehört. Bei der Zeile Host: www1.example.com handelt es sich um den HTTP-Host-Header, welchen der HAProxy benötigt, um das richtige Backend auszuwählen.

Es ist zu sehen, dass wir eine Antwort von einem NGINX-HTTP-Server erhalten. Der HTML-Quelltext wurde gekürzt.

Damit ist es gelungen, von einem IPv4-Client eine Ressource abzurufen, die von einem IPv6-Server bereitgestellt wird.

Im Access-Log des Backend-Servers mit der IPv6-Adresse 2001:DB8::2 sieht man:

2001:DB8::1 - - [06/Jan/2024:19:44:22 +0100] "GET / HTTP/1.1" 200 5909 "-" "curl/8.2.1" "192.0.2.1"

Die Anfrage erreicht den Backend-Server von der IPv6-Adresse des haproxy.example.com (2001:DB8::1). Die am Ende der Zeile zu sehende IPv4-Adresse (192.0.2.1) gehört dem IPv4-Client, von dem ich die Anfrage gesendet habe.

Gedanken zur Skalierung

In diesem Beispiel sind die Server www1.example.com und www2.example.com über ihre IPv6-Adressen direkt erreichbar. Nur die Client-Anfragen von IPv4-Clients laufen über den Reverse-Proxy. Wenn man es wünscht, kann man selbstverständlich sämtliche Anfragen (von IPv4- und IPv6-Clients) über den Reverse-Proxy laufen lassen.

In kleinen Umgebungen kann man einen Reverse-Proxy wie HAProxy zusammen mit Squid (vgl. Artikel Mit einem Dualstack-Proxy Internet-Protokolle verbinden) auf einem Host laufen lassen. Selbstverständlich kann man sie auch auf separate Hosts verteilen.

Hochverfügbarkeit lässt sich auch hier mit keepalived nachrüsten:

Abschließende Gedanken

Die Internet-Protokolle IPv4 und IPv6 werden wohl noch eine ganze Zeit gemeinsam das Internet bestimmen und parallel existieren. Ich bin mir sogar sicher, dass ich das Ende von IPv4 nicht mehr miterleben werde. Dualstack-(Reverse)-Proxy-Server stellen eine solide und robuste Lösung dar, um beide Welten miteinander zu verbinden.

Sicher bleiben noch ausreichend Herausforderungen übrig. Ich denke da nur an Firewalls, Loadbalancer, NAT und Routing. Und es werden sich auch Fälle finden lassen, in denen Proxyserver nicht infrage kommen. Doch mit diesen Herausforderungen beschäftige ich mich dann in anderen Artikeln.

Quellen und weiterführende Links

Zeichen setzen – auf den Chemnitzer Linux-Tagen 2024

24. Februar 2024 um 06:00

In drei Wochen beginnen die Chemnitzer Linux-Tage 2024 mit dem diesjährigen Motto „Zeichen setzen“. Am 16. und 17. März erwartet euch im Hörsaalgebäude an der Richenhainer Straße 90 ein vielfältiges Programm an Vorträgen und Workshops. Hier finden sich Vorträge für interessierte Neueinsteiger wie für alte Hasen.

So geht es am Samstag im Einsteigerforum beispielsweise um die Digitalisierung analoger Fotos, das Erstellen von Urlaubsvideos mit der Software OpenShot oder die Verschlüsselung von E-Mails. In der Rubrik „Schule“ gibt Arto Teräs einen Einblick in den Einsatz der Open-Source-Lösung Puavo an finnischen und deutschen Schulen. Zusätzlich stehen Vorträge aus den Bereichen Finanzen, Medien, Datensicherheit, KI oder Netzwerk auf dem Programm. Am Sonntag gibt das Organisationsteam der Chemnitzer Linux-Tage mit „make CLT“ Einblicke in die Planung und Strukturen der Veranstaltung selbst. In der Rubrik „Soft Skills” wird es um die Schätzung von Aufwänden oder notwendige Fähigkeiten von Software-Entwicklern gehen.

Eintrittskarten können online im Vorverkauf und an der Tageskasse erworben werden. Kinder bis 12 Jahren haben freien Eintritt.

Während viele Besucher bereits Stammgäste sind, werden auch neue Gesichter herzlich willkommen. Lasst euch gern von der hier herrschenden Atmosphäre voller Begeisterung für freie Software und Technik anstecken und begeistern.

Ich selbst freue mich, am Samstag um 10:00 Uhr in V6 den Vortrag mit dem obskuren Namen ::1 beisteuern zu dürfen. Update: Unverhofft kommt oft. Uns so freue ich mich am Sonntag um 10:00 Uhr in Raum V7 noch in einem zweiten Vortrag vertreten zu sein. Zusammen mit Michael Decker von der ASPICON GmbH erfahrt ihr, wie man „Mit Ansible Collections & Workflows gegen das Playbook-Chaos“ angehen kann.

Darüber hinaus beteilige ich mich als Sessionleiter für die folgenden drei Vorträge an der Veranstaltung:

So habe ich auf jeden Fall einen Platz im Raum sicher. ;-)

Wer ebenfalls helfen möchte, kann sich unter Mitmachen! informieren und melden.

Für mich ist dieses Jahr einiges im Programm dabei. Doch freue ich mich ebenso sehr auf ein Wiedersehen mit alten Bekannten aus der Gemeinschaft und darauf, neue Gesichter (Namen kann ich mir meist erst Jahre später merken) kennenzulernen.

Also bis bald in der Karl-Marx-Stadt.

Chemnitzer Linux-Tage Banner

Glücksmomente und Zeiten der Schmerzen mit IPv6

19. Februar 2024 um 06:00

Am 16. und 17. März 2024 werde ich euch auf den Chemnitzer Linux-Tagen um 10:00 Uhr in Raum V6 mit einem Vortrag über IPv6 unterhalten.

Dazu bin ich noch auf der Suche nach ein paar Beispielen aus dem echten Leben. Falls ihr mögt, teilt mir doch eure schönsten und schlimmsten Momente im Zusammenhang mit IPv6 mit und ich prüfe, ob ich sie in meinen Vortrag mit einbauen kann.

  • Wann und wie hat IPv6 euren Tag gerettet?
  • Wieso hat euch das Protokoll Alpträume beschehrt?
  • Was funktioniert wider Erwarten immer noch nicht mit IPv6?
  • Habt ihr lustige Geschichten, die ihr (anonym) mit der Welt teilen möchtet?

Ich freue mich über Einsendungen, Beiträge und Rückmeldungen:

Bitte schreibt dazu, ob ihr eine Namensnennung wünscht oder euer Beispiel anonym einfließen soll.

Um einen runden Vortrag zu erstellen, wird evtl. nicht jeder Beitrag einfließen können. Bitte habt Verständnis dafür und verzeiht, wenn ihr euch nicht im Vortrag wiederfindet. Ich werde eure Geschichten ggf. im Nachgang hier im Blog veröffentlichen.

Bis neulich in Chemnitz. :-)

Mit einem Dualstack-Proxy Internet-Protokolle verbinden

12. Februar 2024 um 06:00

Stellt euch vor, ihr habt eine Menge von Servern, welche ausschließlich über IPv6-Adressen verfügen und deshalb keine Dienste nutzen können, welche nur über IPv4 bereitgestellt werden. Wer sich dies nicht vorstellen mag, findet in „IPv6… Kein Anschluss unter dieser Nummer“ ein paar Beispiele dafür.

Was kann man nun tun, damit diese IPv6-only-Hosts dennoch mit der IPv4-only-Welt kommunizieren können?

Eine mögliche Lösung ist die Nutzung eines Dualstack-Proxy-Servers. Das ist ein Server, welcher über Adressen beider Internet-Protokoll-Versionen verfügt und so stellvertretend für einen IPv6-Host mit einem IPv4-Host kommunizieren kann. Das folgende Bild veranschaulicht den Kommunikationsablauf:

Ablauf der Netzwerkkommunikation eines IPv6-Hosts mit einem IPv4-Host über einen Dualstack-Proxy-Server

Im Bild ist zu sehen:

  1. Wie IPv6-Host A eine Verbindung über IPv6 zum Proxy-Server B aufbaut und diesem bspw. die gewünschte URL mitteilt
  2. Der Proxy-Server B baut nun seinerseits eine IPv4-Verbindung zu IPv4-Host C auf, welcher die gewünschten Inhalte bereitstellt
  3. IPv4-Host C sendet seine Antwort über IPv4 an den Proxy-Server
  4. Der Proxy-Server sendet die gewünschten Inhalte anschließend via IPv6 an den IPv6-Host A zurück
Screencast zur Demonstration der Proxy-Nutzung

Das obige Video demonstriert die Nutzung eines Proxy-Servers durch den Abruf einer Demo-Seite mit curl:

  1. Mit dem host-Kommando wird gezeigt, dass für die Demo-Seite kein AAAA-Record existiert; die Seite ist also nicht via IPv6 erreichbar
  2. Mit dem ip-Kommando wird geprüft, dass der Host auf dem Interface ens18 ausschließlich über IPv6-Adressen verfügt
  3. Ohne Proxy ist die Demo-Seite nicht abrufbar
  4. Erst durch Nutzung des Proxys kann die Seite abgerufen werden

Funktioniert das auch von IPv4 nach IPv6?

Ja. Entscheidend ist, dass der verwendete Proxy beide IP-Versionen unterstützt.

Welcher Proxy ist empfehlenswert?

Der Proxy-Server muss beide IP-Versionen beherrschen. Ich persönlich bevorzuge Squid. Dieser ist in so gut wie allen Linux-Distributionen verfügbar, weit verbreitet, robust und selbstverständlich Freie Software.

Sind damit alle Herausforderungen bewältigt?

Für eine Virtualisierungs-Umgebung mit einer IPv4-Adresse und einem /64-IPv6-Netzsegment funktioniert diese Lösung gut. Sie funktioniert auch in jeder anderen Umgebung, wie gezeigt. Man beachte jedoch, dass man mit nur einem Proxy einen Single-Point-of-Failure hat. Um diesem zu begegnen, kann man Squid mit keepalived hochverfügbar gestalten.

Keepalived ist ebenfalls Freie Software. Sie kostet kein Geld, erhöht jedoch die Komplexität der Umgebung. Verfügbarkeit vs. Komplexität möge jeder Sysadmin selbst gegeneinander abwägen.

Wie mache ich meine IPv6-Dienste für IPv4-User erreichbar, die keinen Proxy haben?

Das Stichwort lautet Reverse-Proxy. Ein Artikel dazu erscheint in Kürze in diesem Blog. ;-)

Weiterführende Quellen und Links

Warum beschäftigst du dich mit IPv6?

29. Januar 2024 um 06:00

Das ist eine gute Frage. Hat man „IPv6… Kein Anschluss unter dieser Nummer“ gelesen, kann man mich sicher fragen, warum ich mir das antue, wo doch überall Stolpersteine und Probleme lauern. Und ich kenne einige Personen, die sich lieber eine Axt ins Bein schlagen, eine Nadel unter die Fingernägel schieben oder Broccoli essen würden, statt sich mit IPv6 zu beschäftigen.

Die Antwort ist ganz einfach. Ich tue dies, weil ich es kann, Spaß daran habe und IPv4-Adressen knapper und teurer werden.

Möchte man Dienste im Internet anbieten, benötigt man IP-Adressen. Üblicherweise bekommt man zu den gängigen Angeboten von Virtual Private Server, Dedicated Server, etc. eine IPv4-Adresse und ein /64-IPv6-Netzsegment kostenlos. Zusätzliche IPv4-Adressen kosten Stand heute zwischen 2,00 € und 5,00 € pro Monat, wobei häufig noch eine saftige Einrichtungsgebühr hinzukommt. Im Abschnitt Preisübersicht findet ihr das Ergebnis einer kurzen Internetrecherche.

Da ich einen Proxmox-Host und ein /64-IPv6-Netzsegment für Spiel-, Spaß- und Laborumgebungen besitze, möchte ich mich gern damit auseinandersetzen. Und sei es nur, um zu lernen, wo es noch überall klemmt und mit welchen Workarounds man die existierenden Klippen umschiffen kann. Wundert euch also nicht, wenn es in Zukunft noch den ein oder anderen Artikel zu diesem Thema gibt.

Preisübersicht

Der My-IT-Brain Jahresrückblick 2023

15. Januar 2024 um 06:00

Das Jahr 2024 ist nun schon zwei Wochen alt. Dennoch möchte ich noch einen Blick zurückwerfen und mich erinnern, wie das Jahr 2023 für meinen Blog verlaufen ist.

In 2023 wurden auf My-IT-Brain insgesamt 45 Artikel veröffentlicht. Dies sind 16 mehr als in 2022 und 14 mehr als in 2021. Jeden Monat sind mindestens zwei Artikel veröffentlicht worden.

Die Themen waren dabei wieder bunt gemischt. Allein Artikel über die Red Hat Enterprise Linux (RHEL) System Roles zogen sich wie ein roter Faden durch den Blog. Welche Artikel haben denn euch am besten gefallen? Lasst es mich gerne in den Kommentaren wissen.

Ich hoffe, es war für jeden von euch etwas Interessantes mit dabei und ihr folgt diesem Blog auch in 2024. Ihr könnt mir auch gerne Anregungen in die Kommentare schreiben, welche Themen ihr hier gerne behandelt sehen wollt. Vielleicht greife ich ja einige davon auf.

Und nun aber auf in ein spannendes Jahr 2024!

Erfahrungsbericht nach 10 Monaten mobiler Arbeit

01. Januar 2024 um 06:00

Im März 2023 wechselte ich von Flex-Work in eine neue Rolle, in der ich 100 % remote arbeite. Heute möchte ich meine Erfahrungen mit euch teilen, die ich bisher damit gemacht habe.

Terminologie

Bevor es richtig losgeht, schreibe ich etwas zur Terminologie der Remote-Arbeit. Denn hier geht es mit den Begrifflichkeiten teilweise ganz schön durcheinander. Daher möchte ich sicherstellen, dass ihr versteht, was ich mit bestimmten Begriffen meine.

Telearbeit

Von allen verwendeten Begriffen ist dies der Einzige, welcher in Deutschland in der Arbeitsstättenverordnung definiert ist:

Telearbeitsplätze sind vom Arbeitgeber fest eingerichtete Bildschirmarbeitsplätze im Privatbereich der Beschäftigten, für die der Arbeitgeber eine mit den Beschäftigten vereinbarte wöchentliche Arbeitszeit und die Dauer der Einrichtung festgelegt hat. Ein Telearbeitsplatz ist vom Arbeitgeber erst dann eingerichtet, wenn Arbeitgeber und Beschäftigte die Bedingungen der Telearbeit arbeitsvertraglich oder im Rahmen einer Vereinbarung festgelegt haben und die benötigte Ausstattung des Telearbeitsplatzes mit Mobiliar, Arbeitsmitteln einschließlich der Kommunikationseinrichtungen durch den Arbeitgeber oder eine von ihm beauftragte Person im Privatbereich des Beschäftigten bereitgestellt und installiert ist.

ArbStättV §2 Abs.7

Erbringen Arbeitnehmende die geschuldete Arbeitsleistung zum Teil am Telearbeitsplatz und zum Teil in einem Büro des Arbeitgebers, wird von alternierender Telearbeit gesprochen.

Bei dieser Form ist der Arbeitgebende für die vollständige Ausstattung des Arbeitsplatzes mit Mobiliar und Arbeitsmitteln sowie der Einhaltung arbeitsrechtlicher Vorschriften (z.B. Ergonomie, UVV, Prüfung ortsveränderlicher Elektrogeräte, etc.) verantwortlich.

Flex-Work oder auch Flex-Office

Diese Begriffe werden häufig verwendet, wenn Arbeitnehmende die geschuldete Arbeitsleistung teilweise außerhalb der Büroräume des Arbeitgebers erbringen und es sich nicht um Telearbeit handelt.

Angestellte erhalten hierbei häufig keine komplette Büroeinrichtung für den Telearbeitsplatz im privaten Raum, sondern lediglich die notwendigen Arbeitsmittel, wie z.B. Laptop und Telefon. Dafür dürfen sie häufig auch außerhalb der eigenen vier Wände bzw. des Büros z.B. aus einer Ferienwohnung arbeiten.

In manchen Fällen werden voll ausgestattete Büroarbeitsplätze für die Angestellten vorgehalten. In anderen Fällen existiert eine Form von Desksharing.

Details werden in Arbeitsverträgen, Betriebsvereinbarungen und Tarifverträgen geregelt.

Homeoffice

Der Duden definiert das Wort Homeoffice wie folgt:

[mit Kommunikationstechnik ausgestatteter] Arbeitsplatz im privaten Wohnraum

URL: https://www.duden.de/rechtschreibung/Homeoffice

Der Begriff wird jedoch nicht einheitlich verwendet. Betrachtet man die Quellen [1]-[5], so wird er sowohl als Synonym für Telearbeit als auch als Oberbegriff für alle Formen von Arbeit verwendet, die nicht in Büroräumen des Arbeitgebers ausgeführt werden.

Wenn ich in diesem Text den Begriff Homeoffice verwende, meine ich damit mobile Arbeit, wie sie im folgenden Abschnitt beschrieben wird.

Mobile Arbeit

Bei der mobilen Arbeit sind Angestellte keinem Büro zugeordnet und nicht an einen Teleheimarbeitsplatz gebunden. Die geschuldete Arbeitsleitung kann von einem beliebigen Ort wie z.B. dem Auto, Café, Hotel oder dem Strand erbracht werden. Dies schließt die eigenen vier Wände jedoch explizit mit ein.

Dem Arbeitnehmenden werden bei dieser Form häufig nur die zwingend benötigten Arbeitsmittel wie Laptop, Mobiltelefon und ggf. Headset gestellt. Bring you own device ist ebenso möglich. Häufig erhalten Angestellte eine Pauschale, mit der sie benötigte Arbeitsmittel selbst beschaffen können.

Details werden auch hierbei im Arbeitsvertrag, in Betriebsvereinbarungen oder Tarifverträgen geregelt.

Merkmale meiner beruflichen Tätigkeit

Nicht jede Tätigkeit ist dazu geeignet, im Homeoffice ausgeführt zu werden. Pflegepersonal kann den Beruf meist ebensowenig aus den eigenen vier Wänden ausüben wie Bus-, LKW-, Zug-Fahrer und Kapitäne. Auch Berufe mit Laufkundschaft eignen sich in der Regel schlecht für Arbeit außerhalb eines festen Büros.

Ich gehöre hingegen zu den glücklichen Menschen, deren Job von einem fast beliebigen Ort aus erfüllt werden kann. Die einzige Bedingung ist eine gute Daten- und Kommunikations-Verbindung. Meine berufliche Tätigkeit lässt sich dabei mit folgenden Stichpunkten beschreiben:

  • Ich kann meine Tätigkeit überwiegend eigen- und selbstständig ausführen
  • Meine Kunden und Teammitglieder sind über Europa verteilt
  • Viele Kollegen sitzen sogar in noch weiter entferntliegenden Ländern
  • Ich benötige neben einem Laptop, einem Mobiltelefon und einer stabilen Netzwerk- bzw. Internetverbindung keine besonderen Werkzeuge

Mit diesen Merkmalen habe ich die besten Voraussetzungen, um nicht auf einen festen Arbeitsplatz beschränkt bzw. angewiesen zu sein.

Arbeitsmittel

Zu Beginn meines Arbeitsverhältnisses wurde ich mit folgenden Arbeitsmitteln ausgestattet:

Ausgeliefert wurde das System mit einem RHEL 8 Corporate Standard Build (CSB). Die Installation wird also von unserer internen IT verwaltet. Ich selbst habe sudo-Rechte auf dem System und fühle mich in keinster Weise eingeschränkt. Ich bin fasziniert, wie gut die Inbetriebnahme ablief und es so gut wie keine Probleme gab, wegen denen ich den IT-Support bemühen musste.

Bei dem Laptop handelte es sich nicht um ein topaktuelles Modell, doch ist es für meine tägliche Arbeit sehr gut geeignet. Ich nutze es täglich für die Arbeit mit:

  • Bis zu zwei verschiedenen Webbrowsern
  • Slack
  • 1-3 virtuellen Maschinen zum Test verschiedenster Dinge
  • Vim
  • GNU Tools

Im Vergleich mit meinem privaten ThinkPad T14s ist das Gerät nach einigen Videokonferenzen deutlich lauter. Die Effizienz der CPU und Lüftersteuerung sind beim P1 nicht so gut wie beim T14s.

Das Thunderbold-Dock hingegen ist das schlechteste Dock, das ich je selbst benutzen musste. Dass für diesen elektronischen Briefbeschwerer im Online-Versandhandel zwischen 250,- und 300,- EUR aufgerufen werden, macht mich fassungslos. Hier funktioniert nichts, wie es soll. Und auch nach einer Firmware-Update-Orgie ändern sich die Fehler, in Summe bleiben sie jedoch gleich. Ich musste mich jedoch nicht lange damit ärgern. Da die Probleme bekannt sind, konnte ich mir ein Dock meiner Wahl beschaffen und die Kosten dafür erstatten lassen.

Zusätzlich zu diesen Arbeitsmitteln bekam ich noch ein Budget, für das ich mir weitere notwendige Arbeitsmittel kaufen konnte, plus ein separates Budget für ein Mobiltelefon. Von diesen Mitteln habe ich beschafft:

Zum Telefon gehört ein Vertrag. Ich konnte beides aus einer Liste auswählen. Zur Auswahl standen auch diverse Geräte von Apple, Samsung und weiteren Herstellern.

Schreibtischoberfläche mit 34-Zoll-Monitor, ergonomischer Tastatur und Maus.
Meine Schreibtischoberfläche im November 2023

Mein Arbeitsplatz sieht in der Regel sehr aufgeräumt und unaufgeregt aus.

Ich besaß bereits vor meinem Jobwechsel einen höhenverstellbaren Schreibtisch, den ich mir für meinen Rücken gegönnt habe. Aus privater Tasche habe ich mir dann noch Bürostuhl Tailwind 2 mit Pending-System und Ponso-Sitzfläche beim lokalen Händler https://www.fair-kauf.net/ gekauft.

Wenn während der Zeit etwas kaputtgeht oder ich feststelle, dass mir doch noch etwas fehlt, bespreche ich dies mit meinem Manager. Bisher war es kein Problem, die Ausgaben für Anschaffungen, die ich sinnvoll begründen konnte, erstattet zu bekommen.

Ich bin mit meinen Arbeitsmitteln sehr zufrieden und kann meine Arbeit damit gut erledigen. Neben der Technik betrachte ich es als unschlagbaren Vorteil, ein eigenes Arbeitszimmer zu besitzen, welches nur von mir zum Zweck der Arbeit genutzt wird. Dies hat für mich folgende unschlagbare Vorteile:

  • Ich muss es nicht fluchtartig räumen, wenn Zeit zum Mittagessen ist
  • Ich kann die Tür hinter mir zumachen und sehe die Arbeit nicht mehr; dies hilft beim Abschalten und Feierabend machen
  • Die Trennung von Berufs- und Privatleben fällt mir so sehr leicht

Hinsichtlich Raum und Arbeitsmittel kann ich aktuell nichts bemängeln und fühle mich gut ausgestattet.

Kommunikation im Team und darüber hinaus

Kommunikation ist wichtig und findet statt, sobald sich mindestens zwei Menschen eine Situation teilen, sich am gleichen Ort oder in der gleichen Videokonferenz befinden. Die Kommunikation findet dabei auf unterschiedlichen Ebenen statt, der Sach- und der Beziehungsebene, wobei die Beziehungsebene die Sachebene bestimmt.

Eine Nachricht, die von Mensch zu Mensch übertragen wird, hat mehrere Seiten und muss vom Empfänger nicht so verstanden werden, wie der Sender sie gemeint hat.

Bei diesen Aussagen handelt es sich um Erkenntnisse von Paul Watzlawick und Friedemann Schulz von Thun aus der Kommunikationswissenschaft (siehe [7]-[10] in den Quellen unten). Kommunikation stellt einen sehr wichtigen Faktor bei der Arbeit dar und beeinflusst in hohem Maße die Produktivität sowie die Motivation der Angestellten.

Viele Artikel und Blogs verkürzen dieses Thema auf Aussagen wie:

  • Die Kommunikation ist im Büro besser als im Homeoffice
  • Im Homeoffice findet weniger Kommunikation statt als im Büro
  • Die Ablenkungen im Homeoffice sind geringer
  • Im Büro gibt es mehr unnötige Meetings
  • Im Büro wird man häufiger bei der Arbeit gestört als im Homeoffice

Mich stört, wenn so getan wird, als wäre die Realität schwarz oder weiß. Ist sie doch in Wirklichkeit grau (ein Blick aus dem Fenster bestätigt dies aktuell) und liegt die Wahrheit doch meist in der Mitte.

Ich möchte hier die Kommunikationskultur in der Firma und dem Team beschreiben, wo ich aktuell beruflich zu Hause bin. Da ich zu 100 % remote arbeite, finden für mich, von wenigen Kundenbesuchen im Jahr abgesehen, fast alle Meetings per Videokonferenz oder Telefon statt. Die einzige Bewertung, die ich dabei vornehme ist, dass es mir persönlich gut gefällt.

Regelmäßig wiederkehrende Meetings

Wie in vermutlich jeder Firma gibt es auch bei uns regelmäßig wiederkehrende Meetings. Dazu gehören unter anderem:

  • Ein zweiwöchentliches 1:1 mit meinem Manager
  • Ein zweiwöchentliches TEAM-Meeting
  • Wöchentlich bzw. zweiwöchentlich stattfindende Treffen verschiedener Virtual Account Teams
  • Daily Stand-up
  • Wöchentliche produktspezifische Q&A-Meetings
  • Company Meeting (einmal pro Quartal)

Kurz gesagt, die 40-Stunden-Woche bietet nicht genug Zeit, um an allen möglichen Meetings teilzunehmen. Doch das erwartet auch niemand.

Was mir gut gefällt:

  • Regelmäßige Meetings ohne Einträge auf der Agenda werden vom Organisator abgesagt
  • Fragen für das Daily Stand-up und Q&A-Sessions werden meist vorab in das jeweilige Meeting-Dokument eingetragen
  • Die Teilnehmer sind in aller Regel gut vorbereitet
  • Sind alle Themen besprochen, wird das Meeting einfach beendet und nicht bis zum Ende durchgezogen
  • Meetings werden regelmäßig hinterfragt, bringen sie keinen Mehrwert mehr, hört man einfach damit auf
  • Wichtige Meetings werden aufgezeichnet und es werden Protokolle erstellt

Ad-Hoc-Meetings

Benötigt man ein paar zusätzliche Augen bzw. Ideen beim Troubleshooting bzw. der Suche nach Informationen, öffnet man ein virtuelles Meeting und lädt Kolleg*innen via Chat ein. Entweder wählt man einen Kanal mit vielen Mitgliedern und hofft, dass jemand kommt oder man schreibt Teilnehmer gezielt an. Dabei gebietet die Etikette, dass man vorher prüft, ob die entsprechende Person auch frei ist. Möglich ist dies mithilfe unserer Kalender oder des Status im Chat.

Dabei ähneln diese Meetings den Störungen im Büro, wo die Tür aufgeht und Kollegen mit ihren Sorgen, Nöten und Anträgen plötzlich vor dem eigenen Schreibtisch stehen. Vorteil der Remote-Arbeit ist in meinen Augen, dass die Hemmschwelle sich diesen Störungen zu entziehen geringer ist. Eine Meetinganfrage lehnt man schneller ab oder verlässt ein Meeting schneller, als jemanden aus dem Büro hinauszubitten.

Für mich ist wichtig, vorher zu überlegen, ob der synchrone Austausch einen Vorteil über asynchrone Kommunikation bietet. Dies ist zum Beispiel der Fall, wenn sich ein Sachverhalt nur umständlich in einer E-Mail erklären lässt, oder das Risiko eines Missverständnisses hoch ist. Grundsätzlich gebe ich der asynchronen Kommunikation den Vorzug, da ich Kollegen so nicht in ihrer Arbeit störe, sie in ihrer eigenen Zeit antworten können und E-Mails Beweise generieren.

Obwohl ich ausschließlich aus dem Homeoffice arbeite, habe ich das Gefühl, weniger Zeit in Meetings zu verbringen als zuvor. Gemessen habe ich dies jedoch nicht.

Soziale-Meetings

Kaffeeküchengespräche, Gesabbel beim Mittagessen und Flurfunk sterben bei mobiler Arbeit aus. Das stimmt in meiner Erfahrung so nicht.

Wir treffen uns sporadisch zum Kaffeetrinken in einer Videokonferenz und sprechen darüber, wie unser Tag so läuft, was es Neues gibt. Dabei werden sowohl dienstliche wie private Themen diskutiert.

Manche Kollegen treffen sich sogar in einer Videokonferenz, ohne aktiv miteinander zu sprechen. Man könnte auch sagen: „Sie schweigen sich konstruktiv an.“ Dies kann das Gefühl reduzieren, allein zu sein. Es ist jemand in der Nähe, der zuhört und in aller Regel auf geräuschvolle Äußerungen reagiert.

Persönliche Treffen in der realen Welt

„Vermisse ich regelmäßige persönliche Treffen in der realen Welt? Nein.“

„Weiß ich diese Treffen dennoch zu schätzen? Ja.“

In meinen Augen ist dies kein Widerspruch in sich. Ich habe mich schnell daran gewöhnt, dass mein Team verteilt sitzt und die meisten Kontakte durch Chat, E-Mail und Videokonferenz stattfinden. Dennoch freue ich mich, diese Menschen am Rande von Veranstaltungen auch mal persönlich zu treffen. Besonders gern, wenn dies ungezwungen außerhalb formal organisierter Teambildungsmaßnahmen passiert.

Chat und E-Mail

Dies sind definitiv zwei meiner Hauptarbeitsmittel. Beide sind Werkzeuge zur asynchronen Kommunikation. Chat ist dabei in der Regel schneller als E-Mail, wobei ich persönlich E-Mails besser strukturieren kann und Dinge leichter in E-Mails wiederfinde.

Aus Gesprächen mit Menschen aus verschiedenen Unternehmen weiß ich, dass Chat Fluch und Segen sein kann. Dies ist jedoch kein technisches Problem, sondern hängt von der Unternehmenskultur und der persönlichen Disziplin ab. Wird erwartet, dass jeder zu jederzeit erreichbar ist und prompt reagiert, kann das die Produktivität ziemlich in den Keller drücken.

Setzt man einen Status wie verfügbar, beschäftigt, im Termin u.ä. und wird dies respektiert, kann Chat die Kommunikation wunderbar unterstützen. Das klappt selbst dann, wenn es mehrere Chats-Werkzeuge gibt.

Telefon

Zum Glück werde ich nur sehr selten angerufen und ich rufe auch nur selten jemanden an. Warum? Ich empfinde unangekündigte Anrufe als Störung, denn sie unterbrechen meine Arbeit. Und was ich selbst nicht will, das man mir tu, das füge ich niemand anderem zu.

Das Telefon ist für mich ein Kommunikationsmittel für den Fall, wenn es etwas sehr Dringendes zu bereden gibt. Oder wenn ich weiß, dass es das bevorzugte Kommunikationsmittel der Person ist, von der ich etwas möchte.

Es gibt Dinge, die kann man am Telefon oder in einer Videokonferenz schneller bzw. einfacher klären als in einer langen Chat- oder E-Mail-Diskussion. Ich empfinde es dann allerdings als höflich, wenn man für das Telefonat einen Termin vereinbart, statt ohne Vorwarnung durchzuklingeln.

Mich freut es sehr, dass ich nicht ständig von eingehenden Anrufen und Video-Calls gestört werde.

Dinge, die mir persönlich wichtig sind

  • Ich sehe meine Familie morgens, bevor mein Kind in die Schule muss und ich mit der Arbeit beginne
  • Meine Frau bringt mir liebevoll Kaffee!
  • Mittags kann ich gemeinsam mit meiner Frau essen (Sorry Ex-Kollegen, meine Frau kocht deutlich besser als die Mensa)
  • Ich bin schon daheim, wenn mein Sohn heim kommt; ich sehe ihn länger als wenn ich pendel
  • Ich muss nicht mehr pendeln; diese hat mich über die Jahre immer mehr genervt (siehe dazu auch [11] in den Quellen)

Fazit

Aktuell passt die Form der mobilen Arbeit, wie sie in meinem Team bei Red Hat gelebt wird, sehr gut zu meinen persönlichen Vorlieben und meiner Lebenssituation.

Mir gefällt es, dass ich in Ruhe und allein arbeiten kann, gleichzeitig aber ein guter Kontakt zu Kolleg*innen existiert, mit denen ich mich austauschen kann. Ich bin sehr zufrieden und hoffe, dass es noch lange so weitergeht.

Herausforderungen in der Zusammenarbeit und Kommunikation liegen in meiner Erfahrung meist in der Unternehmenskultur begründet und nur selten in der Technik. Daher empfehle ich allen, bei denen es nicht optimal läuft, über Anforderungen zu sprechen und erst danach über mögliche Programme zur Lösung derselben.

Euch wünsche ich, dass ihr ein Arbeits(zeit)modell findet, das gut zu euch passt. Wenn ihr Lust habt, teilt doch gern eure Erfahrungen mit eurer Arbeit im Büro, hybrid oder remote hier. Ich freue mich zu erfahren, wie ihr heute arbeitet und wie zufrieden ihr damit seid.

Quellen und weiterführende Links

  1. Arbeitszeit, Arbeitsschutz, Datenschutz: Was Mobilarbeit von Homeoffice unterscheidet. 2020-10-13. Claudia Knuth. Partnerin und Fachanwältin für Arbeitsrecht, Lutz Abel Hamburg/Berlin
  2. Homeoffice, Telearbeit und mobiles Arbeiten. 2022-07-12.
  3. Homeoffice, Telearbeit oder mobile Arbeit? – eine Abgrenzung. 2022-07-27. Katharina Fenner
  4. Homeoffice und mobile Arbeit. 2023-05-23. ver.di
  5. Mobile Arbeit, Telearbeit, Homeoffice – Kennen Sie den Unterschied?. 2021-01-27. Christine Molketin M.A.
  6. Duden-Definition von Homeoffice
  7. Paul Watzlawick – Wikipedia
  8. Metakommunikatives Axiom – Wikipedia
  9. Friedemann Schulz von Thun – Wikipedia
  10. Vier-Seiten-Modell – Wikipedia
  11. Der Umwelt und mir gefällt es am besten, wenn „ihr“ mich „remote“ arbeiten lasst.

IPv6… Kein Anschluss unter dieser Nummer

25. Dezember 2023 um 06:00

Das Jahr 2023 neigt sich langsam dem Ende zu. In diesem Monat for 25 Jahren wurde das IPv6-Protokoll in RFC 2460 beschrieben, bevor es 2017 in RFC 8200 als Internet-Standard von der Internet Engineering Task Force (IETF) veröffentlicht wurde.

Seit immerhin sechs Jahren ist dieses IP-Protokoll also schon standardisiert. Da sollte man doch meinen, dass man im Jahr 2023 problemlos ein vernetztes System betreiben kann, welches nur mit einer IPv6-Adresse mit dem Internet verbunden ist. Leider ist dem nicht so.

In den folgenden kurzen Abschnitten schreibe ich mir meinen Frust von der Seele und dokumentiere, was heute alles mit IPv6 noch nicht geht. Falls ihr weitere Fälle ergänzen möchtet, nutzt gerne die Kommentare, um eurem IPv6-Frust Luft zu machen.

Red Hat Satellite 6.14

Bei der Planung einer Red Hat Satellite 6.14 Installation bin ich über folgenden Satz in der Dokumentation gestolpert:

You can install Satellite and Capsules in IPv6-only systems, dual-stack installation is not supported.

URL: https://access.redhat.com/documentation/en-us/red_hat_satellite/6.14/html/installing_satellite_server_in_a_connected_network_environment/preparing-environment-for-installation-in-ipv6-network_satellite

Das ist schade. Betreibt man Server in IPv4- und IPv6-Netzwerken und möchte eine vollständig unterstützte Lösung, muss man aktuell zwei Satellite installieren.

Ich wollte jedoch einen Satellite in einer reinen IPv6-Umgebung installieren, daher sollte mich diese Anmerkung nicht weiter stören. Da störten mich folgende Stellen im gleichen Kapitel der Dokumentation schon mehr:

You must deploy an external IPv4 HTTP proxy server. This is required because Red Hat Content Delivery Network distributes content only over IPv4 networks, therefore you must use this proxy to pull content into the Satellite on your IPv6 network.

You must configure Satellite to use this IPv4 HTTP proxy server as the default proxy. For more information, see Adding a Default HTTP Proxy to Satellite.

URL: https://access.redhat.com/documentation/en-us/red_hat_satellite/6.14/html/installing_satellite_server_in_a_connected_network_environment/preparing-environment-for-installation-in-ipv6-network_satellite#requirements-for-installation-in-an-ipv6-network_satellite

Zuerst wollte ich dies nicht glauben, habe einen Fehler in der Dokumentation vermutet. Es ist 2023 und Content Delivery Network (CDN) von Red Hat unterstützt kein IPv6? Das kann doch nicht sein! Kann es doch:

Der zweite Link in obiger Liste führt ausschließlich IPv4-Adressen auf. Einzelne Kommentare lassen darauf schließen, dass es jedoch durchaus Interesse an IPv6-Konnektivität gibt. Also installiere ich erstmal einen Proxy-Server mit Dual-Stack, damit ich Hosts aus einem reinen IPv6-Netzwerk via subscription-manager register beim Red Hat Subscription Management (RHSM) registrieren kann.

subscription-manager cli command does not support IPv6 proxy

Nachzulesen in:

Die gute Nachricht, es sind gefixte Versionen für RHEL 9 und RHEL 8 in Aussicht. Auf einen Fix für RHEL 7 würde ich nicht warten und diese Systeme lieber migrieren oder aktualisieren, ist das Support-Ende doch bereits nah.

Also lege ich mein Vorhaben erstmal beiseite und wende mich anderen Wochenendprojekten zu, die vielleicht mehr Erfolg versprechen.

ansible-galaxy does not work on IPv6 only hosts

Nun guck an, da ist mein Kollege Andreas also schon im Jahr 2022 in den Ansible-Issue #77308 gelaufen. Ihr interessiert euch für den aktuellen Stand dieser Geschichte? Siehe:

So langsam komme ich mir vor wie ein bekannter spanischer Junker, welcher gegen Windmühlen pardon Riesen anritt. Aber es ist ja nicht so, dass mir die Themen ausgehen. Klone ich mir halt ein Repo von Github und trage ein bisschen zu Open Source bei…

IPv6 support for cloning Git repositories #10539

Ich spare mir viele Worte und präsentiere nur folgenden Code-Block:

$ host -t AAAA github.com
github.com has no AAAA record

URL zur Diskussion: https://github.com/orgs/community/discussions/10539

Auch hier kein Anschluss unter dieser Nummer.

Fazit

Ich möchte meine jüngsten Erfahrungen umschreiben mit: „An manchen Tagen hat man kein Glück und an anderen kommt auch noch Pech dazu.“

Für Red Hat möchte ich sagen, ist es ein Priorisierungs-Thema. Wenn der Wunsch nach IPv6 auf Kundenseite hinreichend groß wird, wird man hier handeln. Bei Github wird es ähnlich sein. Ich muss vielleicht nur nochmal 25 Jahre warten.

  • Welche Erfahrungen habt ihr mit IPv6 gemacht?
  • Habt ihr es schon an den Nagel gehängt; oder bleibt ihr hartnäckig und gebt nicht auf?
  • Ich freue mich auf eure schönsten Fehlschläge und Erfolgsmomente.

Was tut ein Technical Account Manager (TAM) bei Red Hat?

18. Dezember 2023 um 06:00

Ich kann nicht für alle TAMs bei Red Hat sprechen, denn wir arbeiten sehr selbstständig und haben nur wenige feste Vorgaben. Doch möchte ich euch einen Einblick geben, wie eine Woche in meinem aktuellen Job aussehen kann.

Bitte bedenkt, dass nicht jede Woche gleich aussieht. Das wäre ja auch schrecklich eintönig und langweilig. Dennoch habe ich eine gewisse Routine, mit der ich den Alltag bewältige.

Ich wünsche euch viel Spaß bei diesem Wochenrückblick.

Hinweis: Die hier beschriebene Woche liegt schon etwas zurück. Der Bericht wurde erst kürzlich fertiggestellt.

Montag

Die Woche begann mit einem etwas ungewöhnlichen Montag. Denn mein Sohn hatte schulfrei und brachte meine Morgenroutine gehörig durcheinander.

Statt vor dem Monitor begann mein Arbeitstag daher mit dem Diensthandy. Hierauf habe ich mir einen Überblick über Chat und E-Mail verschafft, um zu sehen, ob über das Wochenende irgendetwas eskaliert ist oder es Themen gibt, denen ich mich zuerst widmen muss. Bei dieser Gelegenheit habe ich direkt alle E-Mails, die ich ob ihres Betreffs als unwichtig klassifiziert habe, direkt gelöscht.

Beim Üerfliegen verschiedener Newsletter ist mir aufgefallen, dass mein Name im letzten TGIF Newsletter auftaucht. Denn ich habe letzte Woche KCS2 erreicht. KCS ist die Abkürzung für Knowledge-centered support. Level 2 bedeutet, dass ich mein Training abgeschlossen habe und zukünftig Lösungs-Artikel selbst veröffentlichen darf. Bisher hat dies mein KCS-Coach nach einem Review der jeweiligen Artikel getan. Ich habe mich über diese kleine Anerkennung gefreut. :-)

Wie fast jeden Morgen habe ich einen Blick in unser Support-Tool geworfen, um mir einen Überblick über mir zugewiesene Cases und ggf. neue Cases meiner Kunden zu verschaffen. Heute sah es hier sehr ruhig aus und es gab nichts zu tun.

Als TAMs arbeiten wir an strategischen und wichtigen Cases unserer Kunden. Damit ihr euch ein bisschen besser vorstellen könnt, was damit gemeint ist, beschreibe ich euch, wie ich Support-Cases handhabe.

Exkurs: Case Work

Als TAM arbeite ich auf Kundenseite mit einem Team zusammen, welches in der Regel aus 4-6 Personen besteht. Dies sind meine TAM-Kontakte. Wenn ein TAM-Kontakt einen Support-Case öffnet, wird dieser mit einem TAM-Flag versehen und wird in meiner View des Support-Tools sichtbar.

Üblicherweise wird der TAM Eigentümer dieser Tickets und bearbeitet sie, bis sie mit dem Einverständnis des Kunden als gelöst geschlossen werden. Die folgende Liste bietet einen kleinen Auszug aus den Themen, die ich überlichweise selbst bearbeite:

  • Requests for Enhancements (RFE) zu Bestandteilen von RHEL
  • Bereitstellung von Informationen zur Zertifizierung von Anwendungen Dritter für RHEL
  • Beantwortung allgemeiner Fragen zu unseren Produkten, deren Life Cycle und zur Roadmap
  • Anfragen, die sich zu Beginn nicht richtig einordnen lassen und wo Ziel und Umgebung erst näher bestimmt werden müssen
  • Fälle, wo ich der Meinung bin, dazu beitragen zu können, dass die Bearbeitung besser verläuft
  • Break&Fix-Fälle, bei denen ich mir zutraue, das Problem in angemessener Zeit selbst lösen zu können

Allerdings bearbeite ich nicht alle Support-Fälle selbst. In folgenden Fällen überlasse ich dies unseren Spezialisten aus den unterschiedlichen Support-Bereichen:

  • Es handelt es sich um ein Thema, von dem ich selbst so gar keine Ahnung habe
  • Ich bin ausgelastet und kann mich nicht in angemessener Zeit und notwendigen Umfang um den Fall kümmern

Kunden haben bereits mit ihrer RHEL-Subskription den Support erworben, der ihnen im Fehlerfall hilft. Als TAM bin ich bestrebt, Support-Fälle dann zu bearbeiten, wenn ich für den Kunden dadurch einen Mehrwert bieten kann. Dies ist nicht der Fall, wenn ich nur als Durchlauferhitzer oder zusätzliches Glied in der Stille-Post-Kette beteiligt bin. Jedoch habe ich auch ein Auge auf die Cases meiner TAM-Kontakte, die ich nicht selbst bearbeite. Ich teile in diesen Fällen häufig Informationen über die Umgebung des Kunden und den Einfluss des Problems auf die Geschäftsprozesse, welche ich in meinen Abstimmungsterminen mit dem Kunden gesammelt habe.

TL;DR: Ich bearbeite Support-Fälle dann, wenn ich dadurch einen Mehrwert für meine Kunden bieten kann.

Exkurs Ende.

Der Montag Vormittag ist in aller Regel eher ruhig. Daher nutze ich die Zeit für Themen, die ich in Ruhe bearbeiten möchte. Darunter fallen Dinge wie:

  • Erstellen von Laborumgebungen
  • Durchführung verschiedener Use Cases im Labor
  • Erstellung von Demos
  • Arbeit ein Vorträgen und Dokumenten
  • Persönliche Fort- und Weiterbildung
  • Arbeit an Themen von meiner ToDo-Liste

Diese Woche war es wirklich ein sehr ruhiger Montag. Ich habe eine Übergabe an meine Vertretung für einen Kunden organisiert und Account-Informationen aktualisiert. Mein Posteingang, ToDo-Liste und Check-Status sind bearbeitet und bei den Kontakten in der WaitingOnReply-Box habe ich um ein Update ersucht. Heute war ein schöner Tag. :-)

Dienstag

Der Dienstag begann mit einem TAM-Team-Meeting. Vorbildlich mit Agedna, Moderator, Protokollant und Zeitwächter. Dies haben wir alle zwei Wochen, wenn es Themen gibt. Die Stimmung war gut. So bin ich gut gelaunt in den Tag gestartet.

Mit dem Daily Stand-up und einem Abstimmungsmeeting zu unserem Vortrag auf dem Summit Connect Darmstadt hatte ich noch zwei weitere Meetings am Vormittag.

Daneben standen heute insgesamt 3,5 Stunden Focus Time in meinem Kalender. Dabei handelt es sich um Zeiten, die ich mir reserviere, um konzentriert an Themen zu arbeiten. Heute habe ich die Zeit genutzt, um:

  • Die Agenda für einen TAM-Call zu erstellen und die Themen für diesen vorzubereiten
  • Die Demo für den Summit Connect vorzubereiten und zu testen
  • Am Ende des Tages die Out-of-Office-Procedure durchzugehen, ohne wichtige Schritte zu vergessen

Das besondere an Focus Time ist bei uns, dass weitere Termineinladungen, die in die Focus Time fallen, automatisch abgelehnt werden und man im Chat als beschäftigt markiert ist. Dies wird von den allermeisten Kollegen respektiert und man kann in Ruhe arbeiten.

Zwischendurch habe ich nach offenen Support-Cases geschaut und Informationen ergänzt. Manchmal reagieren Kunden nicht auf Updates im Support-Portal. Wenn ich dies feststelle, kontaktiere ich sie per E-Mail und informiere über Updates und stelle sicher, dass auf beiden Seiten die gleiche Erwartungshaltung zum Verlauf der Bearbeitung existiert.

Mittwoch

Der Tag begann um Punkt 09:00 Uhr einem Quarterly Service Review für einen unserer Kunden. Hier präsentieren meine TAM-Kollegen und ich, was wir im letzten Quartal für unseren Kunden geleistet haben und gleichen dies mit der Wahrnehmung unseres Kunden ab. Der Termin endete mit einer Aussicht auf das laufende Quartal.

Danach hieß es für mich meine Sachen zu packen, denn heute stand noch die Reise nach Darmstadt auf dem Programm. Ich bin mit der Bahn gereist, da ich so im Zug arbeiten konnte.

Damit meinen Kunden während meiner Reise und Teilnahme am Summit Connect der TAM-Service in gewohnter Weise zur Verfügung steht, habe ich mir im Vorfeld Vertretungen für meine Kunden organisiert.

Während der Bahnfahrt habe ich einen TAM-Call durchgeführt. Dies war nicht optimal, aber besser, als den Termin ausfallen zu lassen. Während eines TAM-Call bespreche ich mit Kunden aktuelle Themen wie offene Support-Cases, anstehende Changes und Projekte, Trainingsbedarf, etc. Er dient der Abstimmung untereinander und Planung der nächsten Schritte.

Mit 45 Minuten Verspätung erreichte ich am Abend Darmstadt Hbf. Nun hieß es schnell im Hotel einchecken und zum Abendessen eilen.

Den Abend verbrachte ich in angenehmer Atmosphäre mit tollen Kollegen. Es war schön, sie mal wieder persönlich zu treffen.

Donnerstag

Heute gab es den ganzen Tag nur ein Thema: Red Hat Summit: Connect Darmstadt

  • Vortag halten
  • Vorträge lauschen
  • Partner und Kunden treffen
  • Kollegen kennenlernen

Vier Stichpunkte, die mich von 08:00-23:00 Uhr beschäftigt haben. Es hat sich aus meiner Sicht gelohnt. Unser Vortrag kam trotz der Kürze der Zeit gut an und ich habe einige Kunden das erste Mal in der Realität getroffen (und erst gar nicht wiedererkannt).

Freitag

Heimreise mit der Bahn. Während der Fahrt in verschiedenen Zügen habe ich mit einem Support-Engineer und meinem Kunden zusammen an einem kniffligen Case gearbeitet, Life-Cycle- und Support-Dokumente geprüft, die Folien zum Quarterly Service Review vom Mittwoch an den betreffenden Empfängerkreis verteilt sowie abgelegt und an diesem Blog-Post geschrieben.

Die Kunden bekommen meist gar nicht mit, wie viel hinter dem Support-Ticket kommuniziert wird. Mir macht es Spaß auch mal über knifflige Problem zusammen mit Kollegen nachzudenken, nach Lösungen und Workarounds zu suchen.

Die ungeplante Verlängerung der Reisezeit nutzte ich, um mein Compliance & Ethics Training abzuschließen. Damit ist dieser Punkt auch erledigt.

Mit 3 Stunden Verspätung, was mich tierisch genervt hat, bin ich daheim bei meiner Familie angekommen, was mich dann sehr gefreut hat.

Fazit

Eine spannende und anstrengende Woche ist vorbei. Ich hoffe ich konnte euch einen kleinen Einblick in eine nicht ganz normale Woche meiner Arbeit geben.

RHEL System Roles: nbde_client

04. Dezember 2023 um 06:00

In diesem Artikel stelle ich euch die RHEL System Role nbde_client vor, mit welcher sich Hosts für Network Bound Disk Encryption (NBDE) installieren lassen. Er ist Bestandteil einer losen Serie, in der ich eine Reihe von System Roles vorstelle, mit denen häufig anfallende Aufgaben in der Systemadministration erledigt werden können.

Wer sich zuerst über die genannten Begriffe informieren möchte, lese:

Umgebung

Für das folgende Beispiel verwende ich eine Umgebung, bestehend aus:

  • Einem Ansible-Controller (RHEL 9) mit den Paketen
    • ansible-core
    • rhel-system-roles
  • Jeweils einem RHEL 8 und RHEL 9 Server mit Minimalinstallation und einem LUKS-Gerät (/dev/sdc in den Beispielen in diesem Text)

Die Installation von RHEL sowie der genannten Pakete sind nicht Bestandteil dieses Artikels. Wer hierzu einen Einstieg sucht, findet entsprechende Dokumentation unter:

Die Rolle

Durch die Installation des Pakets rhel-system-roles existiert diese Rolle bereits auf meinem System und muss nur noch konfiguriert werden. Die Rolle selbst findet man im Pfad /usr/share/ansible/roles/rhel-system-roles.nbde_client/ und die Dokumentation in /usr/share/doc/rhel-system-roles/nbde_client/README.md. Letztere enthält verschiedene Beispiele für häufige Anwendungsfälle.

Anwendungsfall

In meinem Labor betreibe ich zwei NBDE-Server (TANG-Server) rhel-hetz-tang1 und rhel-hetz-tang2 sowie zwei NBDE-Clients (Clevis-Clients) rhel-hetz-clevis1 und rhel-hetz-clevis2. Die beiden NBDE-Clients besitzen jeweils ein LUKS-Device /dev/sdc, welches aktuell durch eine LUKS-Passphrase gesichert ist.

Zukünftig sollen diese LUKS-Devices durch die Kommunikation mit einem NBDE-Server entschlüsselt werden. Die LUKS-Passphrase soll entfernt werden.

Damit wird zukünftig ein Neustart der Clients aus der Ferne ermöglicht. Gleichzeitig bleibt das verschlüsselte Gerät bei Diebstahl vor unbefugtem Zugriff geschützt.

Das Playbook

Hinweis: Das folgende Playbook ist nicht idempotent. Um dies zu ändern, ist dem ersten Task eine Bedingung hinzuzufügen, damit dieser nur dann ausgeführt werden, wenn die Bedingung erfüllt ist.

Für dieses Beispiel ist die fehlende Idempotenz des Playbooks jedoch kein Problem, da grubby das Argument nur dann hinzufügt, wenn es nicht bereits vorhanden ist.

---
- hosts: clevis
  tasks:
  - name: Configure ip address for interface during early boot
    ansible.builtin.command:
      cmd: grubby --update-kernel=ALL --args='GRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 biosdevname=0 ip={{ ansible_default_ipv4.address }}::{{ ansible_default_ipv4.gateway }}:{{ ansible_default_ipv4.netmask }}::{{ ansible_default_ipv4.alias }}:none"'

  - name: Enroll Clevis clients
    include_role:
      name: rhel-system-roles.nbde_client
    vars:
      nbde_client_bindings:
        - device: /dev/sdc
          encryption_password: "{{ luks_password }}"
          password_temporary: true
          slot: 2
          servers:
            - http://rhel-hetz-tang1.example.com
            - http://rhel-hetz-tang2.example.com
  • Der erste Task stellt sicher, dass das Netzwerkinterface aktiviert und mit einer IP-Adresse konfiguriert wird; dies ist notwendig, um den Tang-Server kontaktieren zu können, da in dem genutzten Netzwerk-Segment kein DHCP verfügbar ist; Solltet ihr ein Netzwerk-Segment nutzen, in dem DHCP zur Verfügung steht, kann der erste Task entfallen
  • Um das LUKS-Device für NBDE zu konfigurieren wird die LUKS-Passphrase benötigt, welche in der Variablen luks_password steckt
  • Ich empfehle die Variable luks_password mit ansible-vault vor neugierigen Blicken zu schützen
  • Durch password_temporary: true wird die LUKS-Passphrase aus dem jeweiligen Key-Slot gelöscht, nachdem das LUKS-Device für NBDE konfiguriert wurde

Achtung (I know, the warning comes after the spell): Wenn zur Laufzeit ein Fehler auftritt und der Key-Slot mit der LUKS-Passphrase bereits gelöscht wurde, die NBDE-Konfiguration jedoch nicht erfolgreich war, verliert man Zugriff auf das LUKS-Device. In meiner Labor-Umgebung bin ich das Risiko eingegangen. In der echten Welt, müsst ihr selbst entscheiden, ob ihr mehr Vorsicht walten lasst.

Fazit

Zur Erstellung des Playbooks habe ich die Informationen aus /usr/share/doc/rhel-system-roles/nbde_client/README.md und dem Kapitel 12.18. Using the nbde_client System Role for setting up multiple Clevis clients genutzt. Bis ich festgestellt habe, dass ich auch noch den Task „Configure ip address for interface during early boot“ benötige, hat es ein wenig gedauert. Nun habe ich allerdings ein Playbook, dass ich zukünftig wiederverwenden kann.

In der erstellten Konfiguration, können die LUKS-Devices nur entschlüsselt werden, wenn mindestens einer der beiden Tang-Server im Netzwerk erreichbar ist. Wird ein so gesicherter Server gestohlen und sind die Tang-Server nicht aus dem Internet erreichbar, bleiben die Daten in der verschlüsselten Partition wie gewohnt geschützt. Es ist jedoch möglich den Server neuzustarten, ohne manuell die LUKS-Passphrase an der Konsole eingeben zu müssen.

Quellen und weiterführende Links

  1. Red Hat Enterprise Linux (RHEL) System Roles {en}
  2. Ansible Documentation: Role Directory Structure {en}
  3. Red Hat Software and Download Center {en}
  4. Die Vorteile einer Red Hat Subskription
  5. RHEL System Roles: selinux
  6. RHEL System Roles: timesync
  7. RHEL System Roles: sshd
  8. RHEL System Roles: firewall
  9. RHEL System Roles: rhc
  10. RHEL System Roles: nbde_server

RHEL System Roles: nbde_server

27. November 2023 um 05:00

In diesem Artikel stelle ich euch die RHEL System Role nbde_server vor, mit welcher sich Tang-Server für Network Bound Disk Encryption (NBDE) installieren lassen. Er ist Bestandteil einer losen Serie, in der ich eine Reihe von System Roles vorstelle, mit denen häufig anfallende Aufgaben in der Systemadministration erledigt werden können.

Wer sich zuerst über die genannten Begriffe informieren möchte, lese zuerst:

Im folgenden Text verwende ich die Begriffe NBDE-Server und Tang-Server synonym. Bitte lasst euch dadurch nicht verwirren.

Umgebung

Für das folgende Beispiel verwende ich eine Umgebung, bestehend aus:

  • Einem Ansible-Controller mit den Paketen (RHEL 9)
    • ansible-core
    • rhel-system-roles
  • Jeweils einem RHEL 8 und RHEL 9 Server mit Minimalinstallation

Die Installation von RHEL sowie der genannten Pakete sind nicht Bestandteil dieses Artikels. Wer hierzu einen Einstieg sucht, findet entsprechende Dokumentation unter:

Die Rolle

Durch die Installation des Pakets rhel-system-roles existiert diese Rolle bereits auf meinem System und muss nur noch konfiguriert werden. Die Rolle selbst findet man im Pfad /usr/share/ansible/roles/rhel-system-roles.nbde_server/ und die Dokumentation in /usr/share/doc/rhel-system-roles/nbde_server/README.md. Letztere enthält verschiedene Beispiele für häufige Anwendungsfälle.

Ich möchte mit dieser Rolle Folgendes erreichen:

  • Installation von Tang auf den beiden Zielsystemen
  • Konfiguration von SELinux im Modus enforcing
  • Konfiguration der Host-Firewall

Das Playbook

Das Playbook ist recht übersichtlich. tang bezeichnet eine Gruppe aus meinem Ansible-Inventory, welche die Systeme enthält, die ich als NBDE-Server konfigurieren möchte.

---
- name: Manage nbde server with selinux and firewall
  hosts: tang
  vars:
    nbde_server_manage_firewall: true
    nbde_server_manage_selinux: true
  roles:
    - rhel-system-roles.nbde_server

Nach der Anwendung der Rolle lauscht der Tang-Service auf Port 80/tcp der Zielsysteme und ist aus dem Netzwerk erreichbar.

Probleme

Leider läuft es dieses Mal nicht ganz so rund wie üblich. Der Task [redhat.rhel_system_roles.selinux : Set an SELinux label on a port] schlägt auf dem RHEL 8 Host mit folgender Fehlermeldung fehl: „Failed to import the required Python library (libselinux-python)“

Das Problem und die Lösung beschreibt Red Hat in dem Solution Article: Ansible playbook fails with libselinux-python aren’t installed on RHEL8 (Login required)

Fazit

Diesmal lief es nicht ganz so reibungslos wie gewohnt.

Letztendlich konnten die beiden NBDE-Server dennoch schneller konfiguriert werden, als wäre ich der manuellen Prozedur in Chapter 12. Configuring automated unlocking of encrypted volumes using policy-based decryption gefolgt.

Die Server sind damit aufgesetzt, nächste Woche beschreibe ich, wie die Clients konfiguriert werden.

Quellen und weiterführende Links

  1. Red Hat Enterprise Linux (RHEL) System Roles {en}
  2. Ansible Documentation: Role Directory Structure {en}
  3. Red Hat Software and Download Center {en}
  4. Die Vorteile einer Red Hat Subskription
  5. RHEL System Roles: selinux
  6. RHEL System Roles: timesync
  7. RHEL System Roles: sshd
  8. RHEL System Roles: firewall
  9. RHEL System Roles: rhc

Einführung in das Advanced Intrusion Detection Environment (AIDE)

06. November 2023 um 05:00

Diese Einführung gibt Antworten auf die folgenden Fragen:

  • Was ist ein Intrusion Detection System?
  • Was ist AIDE?
  • Wie installiert und konfiguriert man es?
  • Wie nutzt man AIDE?

In dieser Einführung verwendete Betriebssysteme:

  • Debian 12 (Bookworm)
  • Red Hat Enterprise Linux (RHEL) 9

Um dieser Einleitung folgen zu können, solltet ihr mit den Grundlagen der Linux-Systemadministration vertraut sein und zumindest mit den folgenden Begriffen etwas anfangen können:

Einleitung

Ein Intrusion Detection System (englisch intrusion „Eindringen“, IDS) bzw. Angriffserkennungssystem ist ein System zur Erkennung von Angriffen, die gegen ein Computersystem oder Rechnernetz gerichtet sind. Das IDS kann eine Firewall ergänzen oder auch direkt auf dem zu überwachenden Computersystem laufen und so die Sicherheit von Netzwerken und Computersystemen erhöhen. Erkannte Angriffe werden meistens in Log-Dateien gesammelt und Benutzern oder Administratoren mitgeteilt; hier grenzt sich der Begriff von Intrusion Prevention System (englisch prevention „Verhindern“, IPS) ab, welches ein System beschreibt, das Angriffe automatisiert und aktiv verhindert.

Quelle: https://de.wikipedia.org/wiki/Intrusion_Detection_System (Letzter Abruf: 2023-09-08)

Die Gruppe der Intrusion Detection Systems (IDS) untergliedert sich in:

  • Host-basierte IDS, welche auf einem Host installiert und betrieben werden
  • Netz-basierte IDS, welche auf Netzwerkkomponenten installiert werden und die Kommunikation auf Netz-Ebene überwachen
  • Hybride IDS, welche die Komponenten aus den vorstehend genannten Gruppen kombinieren

Beim AIDE handelt es sich um ein Host-basiertes IDS. Es ist unter der GPL-2.0 lizenziert.

Zweck und Nutzen des AIDE

Aus dem vorhergehenden Abschnitt ist bekannt, dass es sich bei AIDE um ein Host-basiertes System zur Angriffs- bzw. Einbruchserkennung für Linux-Systeme handelt. Es stellt ein kostengünstiges Werkzeug dar, mit dem die Integrität eines Systems überprüft werden kann.

Es soll dem Administrator helfen, zu erkennen, ob Dateien oder Verzeichnisse eines Systems hinsichtlich ihres Inhalts und bzw. oder ihrer Eigenschaften wie z.B. Berechtigungen, SELinx-Kontext, erweiterte Attribute, etc. verändert wurden.

Grundlegende Funktionsweise des AIDE

  • Die zu überwachenden Dateien und Verzeichnisse werden durch reguläre Ausdrücke in der Konfigurationsdatei bestimmt
  • Basierend auf diesen Regeln wird eine Datenbank erstellt
  • Nach dem Initialisieren der Datenbank kann AIDE dazuverwendet werden, die Integrität der Dateien und Verzeichnisse zu überprüfen
    • Die initial erstellte Datenbank dient dabei als Referenz
    • Bei folgenen Überprüfungen wird eine neue Datenbank erstellt und mit der Referenzdatenbank verglichen
  • Änderungen an überwachten Dateien und Verzeichnissen werden in der Logdatei /var/log/aide/aide.log protokolliert

Schwäche von AIDE und Host-basierter IDS im Allgemeinen

  • Programm, Konfigurationsdatei(en), Datenbank und Logdatei liegen lokal auf dem jeweiligen Host
  • Angreifer, welche lokale Dateien verändern können, können potenziell auch die zu AIDE gehörenden Dateien verändern
  • Dadurch muss die Integrität der zur Integritätsprüfung eingesetzten IDS bezweifelt werden

Um diese Schwäche zu minimieren, sind folgende Maßnahmen durch Administratoren in Erwägung zu ziehen:

  • Logdateien an einen zentralen Loghost senden
  • Die AIDE-Referenzdatenbank außerhalb des zu überwachenden Hosts speichern
  • Den Abgleich gegen die AIDE-Referenzdatenbank außerhalb des zu überwachenden Hosts durchführen

Wie diese Maßnahmen umgesetzt werden können, beschreibe ich in einem folgenden Beitrag.

Auswirkungen auf die eigene Arbeitsweise

Werden beispielsweise Konfigurationsdateien unterhalb von /etc auf Änderungen hin überwacht, wird auch jede beabsichtige Änderung protokolliert. Das Programm kann zwischen legitimen und unautorisierten Änderungen nicht unterscheiden.

Daher ist nach jeder legitimen Änderungen die Referenzdatenbank zu aktualisieren. Ich empfehle, dies als einen Schritt in den Konfiguration-Management-Workflow zu integrieren und diese Aufgabe einen Automaten wie Ansible, Chef, Puppet o.ä. erledigen zu lassen. Dies erscheint mir weniger fehleranfällig zu sein als bei einer manuellen Durchführung, wo dieser Schritt sicher gern einmal vergessen wird.

Die Installation von AIDE

AIDE ist in den Paketquellen der meisten Distributionen vorhanden und kann wie folgt installiert werden.

RHEL 9

$ sudo dnf in aide
[sudo] password for tronde: 
Updating Subscription Management repositories.
Last metadata expiration check: 2:26:44 ago on Fri 08 Sep 2023 08:16:28 PM CEST.
Dependencies resolved.
================================================================================
 Package Arch      Version            Repository                           Size
================================================================================
Installing:
 aide    x86_64    0.16-100.el9       rhel-9-for-x86_64-appstream-rpms    154 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 154 k
Installed size: 354 k
Is this ok [y/N]: 
  • Obiger Code-Block zeigt die Installationsanweisung für RHEL 9
  • Die Konfigurationdatei /etc/aide.conf besitzt im Auslieferungszustand bereits 303 Zeilen; ohne Kommentare und Leerzeilen sind es immerhin noch 161
  • Den Aufbau der Datei erklärt die Manpage aide.conf(5)
  • Um AIDE sinnvoll nutzen zu können, sollte sich jeder Administrator mit dem Inhalt von /etc/aide.conf vertraut machen; oder würdet ihr einem Firewall-Regelwerk vertrauen, das ihr nicht kennt?
  • Im Abschnitt „Gedanken zur Konfiguration von AIDE“ findet ihr meine Gedanken und Hinweise zur Konfiguration

Debian 12 (Bookworm)

$ sudo apt install aide
[sudo] password for jkastning: 
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  aide-common liblockfile-bin liblockfile1 libmhash2
Suggested packages:
  figlet
The following NEW packages will be installed:
  aide aide-common liblockfile-bin liblockfile1 libmhash2
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 372 kB of archives.
After this operation, 1064 kB of additional disk space will be used.
Do you want to continue? [Y/n]
  • Obiger Code-Block zeigt die Installationsanweisung für Debian 12
  • Neben aide werden noch die Pakete aide-common, liblockfile-bin, liblockfile1 und `libmhash2` installiert
    • Neben der Konfigurationdatei /etc/aide/aide.conf installiert Debian auch das Verzeichnis /etc/aide/aide.conf.d, in welchem sich direkt nach der Installation schon etliche Konfigurationsdateien befinden:
$ ls -l /etc/aide/aide.conf.d/ | wc -l
212
  • Auch hier empfehle ich Administratoren, sich mit der Konfiguration zu beschäftigen und sich damit vertraut zu machen (siehe dazu auch aide.conf(5))
  • Im folgenden Abschnitt „Zur Konfiguration von AIDE“ findet ihr meine Gedanken und Hinweise zur Konfiguration

Zur Konfiguration von AIDE

Während AIDE in RHEL über eine einzige Datei (/etc/aide.conf) konfiguriert wird, gibt es in Debian eine Konfigurationsdatei (/etc/aide/aide.conf) und die Verzeichnisse /etc/aide/aide.conf.d sowie /etc/aide/aide.settings.d, welche weitere Dateien zur Konfiguration und Einstellungen beinhalten.

Eine AIDE-Konfigurationsdatei aide.conf besteht aus drei verschiedenen Arten von Zeilen:

  • Optionen, welche die Konfigurationsparameter und Gruppen definieren; aufgebaut sind diese nach dem Muster Parameter = Wert bzw. Gruppenname = Wert
  • Regeln, welche bestimmen, welche Dateien und Verzeichnisse in die Datenbank aufzunehmen sind und welche Attribute überwacht werden sollen
  • Macros, mit denen sich Variablen definieren lassen; z.B. definierte @@define foo bar die Variable foo mit dem Wert bar

AIDE kann die folgenden Attribute bzw. Elemente von Dateien auf Änderungen hin überwachen:

#p:      permissions
#i:      inode
#n:      number of links
#u:      user
#g:      group
#s:      size
#b:      block count
#m:      mtime
#a:      atime
#c:      ctime
#S:      check for growing size
#acl:           Access Control Lists
#selinux        SELinux security context
#xattrs:        Extended file attributes
#md5:    md5 checksum
#sha1:   sha1 checksum
#sha256:        sha256 checksum
#sha512:        sha512 checksum
#rmd160: rmd160 checksum
#tiger:  tiger checksum

Der folgende Code-Block zeigt die Definition der beiden Gruppen NORMAL und DIR (aus der /etc/aide.conf in RHEL 9), welche spezifizieren, welche Attribute überwacht werden sollen, wenn die jeweilige Gruppe in einer Regel verwendet wird.

NORMAL = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512

# For directories, don't bother doing hashes
DIR = p+i+n+u+g+acl+selinux+xattrs

Welche Dateien und Verzeichnisse in die AIDE-Datenbank aufzunehmen bzw. auszuschließen sind durch reguläre Ausdrücke bestimmt. Der nächste Code-Block zeigt drei Beispiele, die anschließend erläutert werden:

/etc NORMAL
=/var/log/ DIR
=/home DIR
!/dev
  • Das Verzeichnis /etc und alle darunterliegenden Dateien und Verzeichnisse werden in die AIDE-Datenbank aufgenommen und mit den Regeln aus der Gruppe NORMAL verknüpft
  • Nur das Verzeichnis /var/log/ und die direkt darunter befindlichen Dateien und Verzeichnisse werden in die AIDE-Datenbank aufgenommen und mit der Gruppe DIR verknüpft; der Inhalt der Unterverzeichnisse wird nicht in die Datenbank aufgenommen
  • Ausschließlich /home wird aufgenommen; nicht jedoch der Inhalt davon
  • Das Verzeichnis /dev und alle darunterliegenden Dateien und Verzeichnisse werden nicht in die AIDE-Datenbank aufgenommen

Initialisierung der AIDE-Datenbank

Mit Sicherheit und Vertrauen ist das immer so eine Sache. Am besten ist es stets, wenn Vertrauen für Sicherheit nicht erforderlich ist. Daher rate ich an dieser Stelle nochmals ausdrücklich, die AIDE-Konfiguration zu überprüfen und ggf. den eigenen Bedürfnissen anzupassen… Nur um direkt gegen meinen eigenen Rat zu verstoßen.

Der Umfang an Regeln ist in beiden Systemen so groß, dass ich in dieser Einführung nicht alle einzeln erläutern kann. Ich vertraue für diese Einführung daher darauf, dass die Distributionen eine sinnvolle Konfiguration ausliefern.

Initialisiert wird die Datenbank je nach Distribution mit einem leicht abgewandelten Befehl.

Beispiel mit RHEL 9

$ sudo time aide --init
Start timestamp: 2023-09-18 20:50:06 +0200 (AIDE 0.16)
AIDE initialized database at /var/lib/aide/aide.db.new.gz

Number of entries:      54290

---------------------------------------------------
The attributes of the (uncompressed) database(s):
---------------------------------------------------

/var/lib/aide/aide.db.new.gz
  MD5      : xOf5Bs/Hb2Caa5i2K41fbg==
  SHA1     : KoCkqwfe+oZ2rlQTAU+AWQBrt2I=
  RMD160   : eM6IC68wq1VRhDbyHhRqy+63ldI=
  TIGER    : lQC+UTBqUm0iEDdKA0u7THqAPLNQxegH
  SHA256   : vdzjqIr/m7FgjXdZLQG+D1Pvf75WlF17
             WYiA6gU+4Pg=
  SHA512   : EdMB0I92j05zlfjXHcJFasZCAvkrK9br
             6zQEcDfD4IDM8D9c1Sz0r7A5tJTKGXVZ
             AFCOJR65j66ihKB0suFS6w==


End timestamp: 2023-09-18 20:50:19 +0200 (run time: 0m 13s)

Die erzeugte Datenbank wird umbenannt, indem das new aus dem Dateinamen entfernt wird.

$ sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

Die umbenannte Datei stellt die Referenzdatenbank dar, gegen die mit dem Befehl aide --check geprüft werden kann, ob es Änderungen im Dateisystem gab.

In diesem Artikel gebe ich mich damit zufrieden, dass die Datenbank auf dem zu überwachenden Host liegt und damit dem Risiko unterliegt, von einem Angreifer manipuliert zu werden (siehe zu den Schwächen oben). Ich gehe in einem Folgeartikel darauf ein.

Beispiel mit Debian 12

Unter Debian wird die AIDE-Datenbank mit dem Wrapper-Script aideinit (siehe aideinit(8)) initialisiert. Das README unter /usr/share/doc/aide-common/README.Debian.gz warnt bereits davor, dass Debian mit zu restriktiven Einstellungen daherkommt:

Configuring AIDE the Debian way
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AIDE’s Debian default configuration takes a very paranoid stance and
is likely to report more changes than you will need to focus your
attention on.

/usr/share/doc/aide-common/README.Debian.gz

Lassen wir uns überraschen…

$ sudo time aideinit
Running aide --init...
7044.57user 54.97system 2:00:40elapsed 98%CPU (0avgtext+0avgdata 132408maxresident)k
231120192inputs+88320outputs (12major+66397minor)pagefaults 0swaps

Das hat deutlich länger gedauert und endete mit einer deutlich kürzeren Ausgabe. Die erzeugte Datenbank ist jedoch wie bei RHEL im Verzeichnis /var/lib/aide/ zu finden.

:~# ls -l /var/lib/aide/
total 43536
-rw------- 1 root  root  22286930 Sep 19 15:13 aide.db
-rw------- 1 _aide _aide 22286930 Sep 19 15:13 aide.db.new
:~# qm start 102
:~# file /var/lib/aide/aide.db.new 
/var/lib/aide/aide.db.new: gzip compressed data, max compression, from Unix, original size modulo 2^32 44239215
:~# file /var/lib/aide/aide.db
/var/lib/aide/aide.db: gzip compressed data, max compression, from Unix, original size modulo 2^32 44239215

Warum die Erstellung so viel länger gedauert hat, weiß ich nicht. Ich habe keine Idee dazu. Auch Debian erzeugt eine gzip-komprimierte Datenbank, auch wenn hier keine Dateiendung darauf hinweist. Ich finde das etwas seltsam, behalte die Standardeinstellung für diese Einführung jedoch bei. Dafür muss die Datei nicht manuell umbenannt werden, da direkt eine Kopie erstellt wird, die als Referenzdatenbank genutzt werden kann.

Im Gegensatz zu RHEL wird unter Debian auch ein Timer namens dailyaidecheck.timer installiert, welcher täglich einen automatischen Check auf Veränderungen durchführt. Allerdings ist es für einen Angreifer ein Leichtes, diese Timer-Unit zu deaktivieren.

Auf Änderungen prüfen

Unter Debian und RHEL werden die in der Referenzdatenbank enthaltenen Elemente mit folgendem Befehl auf Änderungen überprüft:

:~# aide --check                                    # unter RHEL
:~# aide --check --config /etc/aide/aide.conf       # unter Debian

Ich habe meine Testsysteme ein paar Tage laufen lassen und einen AIDE-Integritätscheck durchgeführt. Hier das Ergebnis für ein RHEL 9 System:

$ sudo aide --check
Start timestamp: 2023-09-26 19:54:59 +0200 (AIDE 0.16)                          
AIDE found differences between database and filesystem!!                        
                                                                                
Summary:                                                                        
  Total number of entries:      54290   
  Added entries:                0                                               
  Removed entries:              0                                               
  Changed entries:              3                                               
                                                                                
---------------------------------------------------                             
Changed entries:                                                                
---------------------------------------------------               
                                                                                
f = ...    . ..S : /var/log/insights-client/insights-client.log.3               
f < ...    . ... : /var/log/rhsm/rhsmcertd.log                                  
f < ...    . ... : /var/log/squid/cache.log                                     
                                                                                
---------------------------------------------------              
Detailed information about changes:
---------------------------------------------------                             
                                                                                
File: /var/log/insights-client/insights-client.log.3                            
  SELinux  : system_u:object_r:insights_clien | unconfined_u:object_r:insights_c
             t_var_log_t:s0                   | lient_var_log_t:s0
                                                                                
File: /var/log/rhsm/rhsmcertd.log                                               
  Size     : 1426                             | 1343                            
                                                                                
File: /var/log/squid/cache.log                                                  
  Size     : 6230                             | 334              
                                                                                
                                                                                
---------------------------------------------------
The attributes of the (uncompressed) database(s):                               
---------------------------------------------------                             
                                                                                
/var/lib/aide/aide.db.gz                                                        
  MD5      : xOf5Bs/Hb2Caa5i2K41fbg==   
  SHA1     : KoCkqwfe+oZ2rlQTAU+AWQBrt2I=                                       
  RMD160   : eM6IC68wq1VRhDbyHhRqy+63ldI=                                       
  TIGER    : lQC+UTBqUm0iEDdKA0u7THqAPLNQxegH                                   
  SHA256   : vdzjqIr/m7FgjXdZLQG+D1Pvf75WlF17                                   
             WYiA6gU+4Pg=                                                       
  SHA512   : EdMB0I92j05zlfjXHcJFasZCAvkrK9br                                   
             6zQEcDfD4IDM8D9c1Sz0r7A5tJTKGXVZ                     
             AFCOJR65j66ihKB0suFS6w==                                           
                                                                                
                                                                                
End timestamp: 2023-09-26 19:55:12 +0200 (run time: 0m 13s)

Die Integritätsprüfung in obigen Code-Block führt Änderungen an drei Dateien auf:

  • Das SELinux-Label einer Log-Datei hat sich geändert
  • Die Größe von zwei weiteren Log-Dateien hat sich geändert
  • Die Änderungen werden in einer Zusammenfassung und im Detail ausgegeben
  • Eine Erläuterung zur Ausgabe unter „Changed entries“ findet sich im Absatz summarize_changes in aide.conf(5).
  • Man erhält Informationen darüber, was sich geändert hat, nicht warum sich diese Änderungen ergeben haben

Abbruch meiner Tests unter Debian 12 (Bookworm)

Unter Debian hat die Integritätsprüfung über Stunden einen CPU-Kern blockiert. Der Prozess ist in einem futex Syscall hängen geblieben.

Ob es an meinem System liegt oder AIDE unter Debian generell ein Problem hat, kann ich nicht sagen. Ich bin der Sache nicht weiter nachgegangen.

Falls jemand von euch AIDE unter Debian einsetzt und dies liest, freue ich mich, wenn ihr eure Erfahrungen mit mir teilt.

Die Referenzdatenbank aktualisieren

Mit dem Befehl aide --update wird die Datenbank-Integrität geprüft und eine neue Datenbank /var/lib/aide/aide.db.new.gz erzeugt. Die bestehende Referenzdatenbank /var/lib/aide/aide.db.gz wird dabei nicht überschrieben und bleibt zunächst erhalten. Möchte man diese länger aufbewahren, kann man sie umbenennen und bspw. einen Zeitstempel anhängen. Anschließend erzeugt man mit mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz eine neue Referenzdatenbank.

Der folgende Code-Block zeigt die Ausgabe von aide --update unter RHEL 9.

~]# aide --update                                            
Start timestamp: 2023-09-26 20:13:52 +0200 (AIDE 0.16)
AIDE found differences between database and filesystem!!
New AIDE database written to /var/lib/aide/aide.db.new.gz
                                                                                
Summary:                                
  Total number of entries:      54290
  Added entries:                0
  Removed entries:              0    
  Changed entries:              3                                               
                                                                                
---------------------------------------------------
Changed entries:                                                                
---------------------------------------------------
                                                                                
f = ...    . ..S : /var/log/insights-client/insights-client.log.3
f < ...    . ... : /var/log/rhsm/rhsmcertd.log
f < ...    . ... : /var/log/squid/cache.log

---------------------------------------------------        
Detailed information about changes:                                             
---------------------------------------------------

File: /var/log/insights-client/insights-client.log.3                     [0/100]
  SELinux  : system_u:object_r:insights_clien | unconfined_u:object_r:insights_c
             t_var_log_t:s0                   | lient_var_log_t:s0
                                                                                
File: /var/log/rhsm/rhsmcertd.log                                               
  Size     : 1426                             | 1343                            
                                                                                
File: /var/log/squid/cache.log                                                  
  Size     : 6230                             | 334                             
                                        
                                                                                
---------------------------------------------------                             
The attributes of the (uncompressed) database(s):
---------------------------------------------------         
                                        
/var/lib/aide/aide.db.gz       
  MD5      : xOf5Bs/Hb2Caa5i2K41fbg==                                           
  SHA1     : KoCkqwfe+oZ2rlQTAU+AWQBrt2I=                                       
  RMD160   : eM6IC68wq1VRhDbyHhRqy+63ldI=              
  TIGER    : lQC+UTBqUm0iEDdKA0u7THqAPLNQxegH                                   
  SHA256   : vdzjqIr/m7FgjXdZLQG+D1Pvf75WlF17         
             WYiA6gU+4Pg=                                                       
  SHA512   : EdMB0I92j05zlfjXHcJFasZCAvkrK9br            
             6zQEcDfD4IDM8D9c1Sz0r7A5tJTKGXVZ                                   
             AFCOJR65j66ihKB0suFS6w==   
                                        
/var/lib/aide/aide.db.new.gz     
  MD5      : Dgoc1/L5F1UfXPAQRvMdTg==
  SHA1     : 23RFwEBIh0kw/3TiiVAh39Fzx0Q=                                       
  RMD160   : 1szie2CW1dyLmaKFg01j48Fr+Us=                                       
  TIGER    : TgdG3zNAOSZH2D9jkyvBves8PtjC0lCR      
  SHA256   : hjn9vxFxg4KoVwT3YvgU347EhvTCg5ey                                   
             lfktpr/OrcA=                                                       
  SHA512   : x6E3YPa0eILD3nZqDt6N755KSmPRFOz8                                   
             lhKD9CimYScSpxyoVxJAVWiozR8KUwkt                    
             Ao7mgy3BgtUA0MZuNMv43w==                                           
                                                                                

End timestamp: 2023-09-26 20:14:03 +0200 (run time: 0m 11s)
~]# ls -l /var/lib/aide                                      
total 6184                                                                      
-rw-------. 1 root root 3163359 Sep 18 20:50 aide.db.gz                         
-rw-------. 1 root root 3163384 Sep 26 20:14 aide.db.new.gz

Ende

An dieser Stelle endet die Einführung in das Advanced Intrusion Detection Environment (AIDE). Kommt das Ende für euch abrupt? Ist es ein Ende mit Schrecken? Lasst es mich gern wissen.

In dieser Einführung habe ich beschrieben, was Intrusion-Detection-Systeme im Allgemeinen und AIDE im Speziellen sind. Ich bin auf deren Nutzen eingegangen und habe die Schwächen von AIDE als Host-basiertem IDS benannt. Installation, Konfiguration, Integritäts-Check und Aktualisierung der Datenbank wurden erklärt und mit Beispielen belegt.

Was ist nun von AIDE zu halten?

Nun, es ist besser als nichts. Man besitzt damit ein Werkzeug, mit dem sich Änderungen im Dateisystem erkennen lassen. Man muss sich jedoch der Schwächen Host-basierter IDS bewusst sein. Ein Angreifer mit lokalen root-Rechten kann dieses Werkzeug mit wenig Aufwand unschädlich machen bzw. die eigenen Änderungen verschleiern.

Sicher kann man einen Integritätscheck automatisiert alle 5 Minuten durchführen und für Änderungen eine E-Mail-Benachrichtigung einrichten. Doch wirkt dies etwas hemdsärmelig. Daher werde ich dieses Thema in einem späteren Artikel aufgreifen und zeigen, wie man AIDE in einen Automations- bzw. Konfigurations-Management-Prozess einbinden kann.

Ein Serverschrank mit Kompromissen

23. Oktober 2023 um 05:00

Heute berichte ich euch von meinem Wochenendprojekt „Aufbau und Einrichtung Serverschrank“. Anlass dazu gaben vier Gründe:

  • NAS, Pi-Hole und Heimserver waren über das Haus verteilt und kein Standort war für das jeweilige Gerät optimal.
  • Für Remote Exams musste ich den Heimserver jedes Mal herunterfahren und entkabeln, da sich dieser unter meinem Schreibtisch befand. Dazu hatte ich auf Dauer keine Lust.
  • Ich habe hoffentlich bald zwei Internetanschlüsse, die an einem Punkt im Keller zusammengeführt werden sollen.
  • Ich habe jahrelang im Datacenter gearbeitet und vermisse 19-Zoll-Schränke. ;-)

Transparenzhinweis: Von den im Text genannten Herstellern erhalte ich keinerlei Vergünstigungen, Werbekostenzuschüsse oder andere Vorteile, noch habe ich diese erhalten.

19-Zoll-Serverschrank mit 22 Höheneinheiten (HE)

Aus dem Datacenter kennt man die meist 42 HE hohen, 800 mm breiten und 1000 mm tiefen Schränke. So ein Modell ist für meinen heimischen Keller allerdings völlig überdimensioniert. Darüber hinaus ist mir ein solcher Schrank zu teuer.

Also habe ich mir zuerst Gedanken gemacht, was ich alles in den neuen Schrank einbauen möchte und wie viele HE ich dafür benötige. Mit etwas Reserve bin ich auf 22 HE gekommen.

Nach etwas Recherche habe ich mir bei IT-Budget einen 22 HE Schrank mit BxT 600×800 mm, Sicht-/Vollblechtür, 4 Aktiv-Lüfter, 3 Fachböden, 1x 6-fach 19-Zoll-Steckdosenleiste, 120 Korbmuttern und M6-Schrauben im Flatpak gekauft. Dazu habe ich noch 10 Kabelbügel aus Kunststoff gekauft, um dem Kabelwust im Inneren von Beginn an Einhalt gebieten zu können.

Wer noch nie einen Schrank aufgebaut hat, für den gibt es von IT-Budget ein schönes Youtube-Video, in welchem die einzelnen Schritte erklärt werden. Die folgenden Bilder zeigen ein paar Bauabschnitte:

Zeit das im Aufbau befindliche Innengestell des 19-Zoll-Schranks
Zeit das im Aufbau befindliche Innengestell des 19-Zoll-Schranks aus einer anderen Perspektive
Fertig montierter 19-Zoll-Schrank mit geöffneter Tür.
Fertig montierter 19-Zoll-Schrank mit geschlossener Glastür. Aufnahme von Schräg-Oben. Die vier Lüfter im Dach sind sichtbar.

Mir gefällt, dass alle Teile sauber entgratet sind und qualitativ hochwertig wirken. Dies ist, glaube ich, der erste Schrank, nach dessen Aufbau ich nicht aus dutzenden Kratzern blutete.

Die 600 mm Breite lassen nur wenig Platz für die Kabelführung im Inneren. Ich kann dies verschmerzen, da ich den Schrank nicht komplett bestücken werde und noch ausreichend Platz ist. Alle vier Seiten lassen sich öffnen, sodass man gut an die zu montierenden Elemente herankommt. Zudem verfügt der Schrank über Rollen. Werden die Standfüße eingeschraubt, lässt sich der Standort leicht verändern.

Das einzige, was mir fehlte, war eine Kabelbürste für die Kabelzuführung. Diese verhindert, dass neben den Kabeln auch Staub einen Weg in den Schrank findet. Diese habe ich nachträglich im Versandhandel bestellt.

Gekostet hat das Ganze bis hierhin ca. 640,- Euro/brutto. Das ist nicht wenig, doch empfinde ich den Preis der Qualität angemessen.

Umbau meines PC in ein 19-Zoll-Gehäuse

Meinen PC habe ich detailliert in Meine privaten Arbeitsmittel Anfang 2022 beschrieben. Dieser hing bisher unter meiner Schreibtischplatte.

Ich wollte das Desktop-Gehäuse nicht einfach unten in den Schrank hinein stellen. Dies triggerte einfach zu sehr meinen inneren Monk. Daher habe ich mir das Inter-Tech Servergehäuse IPC 4U-4088-S für unter 80,- Euro/brutto bestellt und meinen PC umgebaut. Die folgenden Bilder illustrieren dies:

Altes und neues PC-Gerhäuse liegen nebeneinander auf dem Schreibtisch.
Nun steckt alles im neuen Gehäuse.

Der Umbau war in ca. 45 Minuten erledigt und der PC konnte einziehen:

Geöffneter 19-Zoll-Schrank zeigt Fachböden mit NAS, PC und einige Kartons. Auf dem Schrank stehen Monitor und Tastatur zur Bedienung des verbauten PCs.
Bild zeigt den geschlossenen 19-Zoll-Schrank. Monitor und Tastatur sind mit Staubschutzhauben geschützt.

Ich habe vergessen Teleskop-Gleitschienen und Kabelmanagementarm für das PC-Gehäuse mitzubestellen. Daher habe ich das Gehäuse auf einen Fachboden gelegt. Dies ist für mich akzeptabel, da ich den PC für Arbeiten eh an einen besser beleuchteten Ort bringen würde.

Staubschutzhauben für Monitor und Tastatur dürfen natürlich nicht fehlen, möchte ich doch möglichst lange Freude daran haben.

Den Schrank selbst fülle ich von oben nach unten. Sollte der Keller mal mit Wasser volllaufen, habe ich ca. 70 cm Luft, bevor mein PC im Wasser steht. Deshalb habe ich auch Strom und alle weiteren Kabel von oben in den Schrank hinein geführt.

Was noch?

Auf den letzten Bildern ist zu sehen, dass mein NAS sich ebenfalls schon im Schrank befindet. In den Kartons befinden sich noch Kabel und ein Protectli Vault VP2410. Letzterer wird zukünftig als Gateway/Firewall für die beiden Internetanschlüsse dienen.

Nicht im Bild sind ein Raspberry Pi 2 mit Pi-Hole und ein Netgear GS108e, welcher die Komponenten untereinander verbindet.

Mich freut es, nun nicht mehr unter Tische oder hinter TV-Schränke kriechen zu müssen, wenn ich mal physischen Zugriff auf meine Komponenten benötige. Jetzt findet alles seinen Platz in einem schicken Schrank.

Don’t Push To Production On Friday

25. September 2023 um 05:00

So stand es an einem Freitag auf Mastodon geschrieben. Nach einem Schmunzeln fragte ich mich: „Ja warum eigentlich nicht?“ Dieser Frage möchte ich heute nachgehen.

Der englischsprachige Satz aus dem Titel ist eine Aufforderung, an einem Freitag keine Änderungen an produktiven Systemen vorzunehmen, um das Wochenende nicht zu gefährden. Viele von euch kennen vermutlich berühmte letzte Worte wie:

  • Was soll schon schiefgehen?
  • Nur noch diese kleine Änderung, dann ist Feierabend.
  • Das wurde getestet, da kann nichts passieren.
  • Das geht ganz schnell, ich mache das noch eben.

Nicht selten hat sich der Feierabend oder das Wochenende nach diesen Sätzen erheblich verzögert oder sind ganz ausgefallen, weil eben doch etwas schiefgegangen ist. In der Folge waren wichtige Dienste nicht mehr verfügbar und Systemadministratoren haben das Abendessen mit ihrer Familie versäumt, weil sie den Klump wieder zum Laufen bringen mussten. Solche Erlebnisse führen zu Aussagen wie:

  • Never change a running system. Oder eben
  • Don’t push to production on Friday

Die Logik dahinter ist bestechend einfach. Wenn etwas funktioniert und man nichts daran ändert, wird wohl auch nichts kaputt gehen. Allerdings stehen diese Aussagen dem DevOps-Mantra von Continuous Integration and Continuous Delivery (CI/CD) entgegen, welches fordert, dass Änderungen zu jeder Zeit möglich sein müssen.

Und wer hat nun recht? Ich denke, die Wahrheit liegt wie so oft irgendwo in der Mitte.

Ob Änderungen durchgeführt werden können, hängt in meinen Augen nicht vom Wochentag ab, sondern vielmehr von den Antworten auf die folgenden Fragen:

  • Sind alle für die Abnahmetests erforderlichen Key-User nach der Änderungen verfügbar und können direkt im Anschluss testen?
  • Sind alle Verantwortlichen anwesend bzw. verfügbar, welche entscheiden, ob die Änderung bzw. das Deployment erfolgreich war oder nicht?
  • Liegt das Wartungsfenster in einem Zeitraum, in dem ggf. externe Supportdienstleister erreichbar und diese Zeiträume durch Service-Level-Agreements (SLA) abgedeckt sind?
  • Findet die Änderung in einem Zeitfenster statt, in dem Störungen toleriert werden können?

Sind zum Beispiel alle 37 Key-User, 8 Abteilungsleiterinnen und das 20-köpfige Betriebs-Team für die Personal- und Buchhaltungsanwendung Freitag nach 18:00 bis voraussichtlich 21:00 Uhr alle verfügbar und können im Fehlerfall mit offenem Ende verfügbar bleiben, steht einer Änderung bzw. einem Deployment nichts im Wege. Ist dies jedoch nicht der Fall und man stellt Fehler möglicherweise erst im Laufe des kommenden Montags fest, wo ein Rollback evtl. schon nicht mehr möglich ist, sollte man den Change vielleicht lieber Montagmorgen starten?

In einem anderen Fall ist das Team nicht sicher, ob sie das System im Fehlerfall ohne Hilfe des Herstellers wiederherstellen können. Der Support-Vertrag deckt jedoch nur die Zeiten Mo-Fr von jeweils 08:00-17:00 Uhr mit 4 Stunden Reaktionszeit ab. Hier ist es vielleicht ebenfalls besser, das Wartungsfenster in den frühen Morgen als in den Freitagabend zu legen.

Habe ich hingegen einen 24/7-Supportvertrag und meine IT-Betriebsabteilung darf auch am Wochenende arbeiten, bietet sich ein Change mit langer Dauer am Wochenende an, um die Betriebsabläufe möglichst wenig zu beeinträchtigen.

Sind Änderungen nur von kurzer Dauer und man möchte möglichst viele User verfügbar haben, die sofort testen und mögliche Fehler finden, ist vermutlich auch Dienstag Vormittag 10:00 Uhr eine gute Zeit.

Es hängt also nicht primär vom Wochentag, sondern vielmehr von einigen anderen Faktoren ab, wann Änderungen in Produktion ausgerollt werden sollten.

Wie seht ihr das? Nach welchen Kriterien werden bei euch Deployments geplant und durchgeführt?

PS: Ich finde jedoch absolut nichts Verwerfliches daran, wenn man sich den Freitag für die Pflege und Aktualisierung der Dokumentation reservieren kann und nicht mit aller Gewalt noch etwas kaputtfuckeln muss. ;-)

RHEL System Roles: rhc

11. September 2023 um 05:00

Im siebten Teil meiner losen Reihe über die RHEL System Roles stelle ich die Rolle rhc vor, mit welcher sich RHEL-Systeme (Version >= 8.6) in der Hybrid Cloud Console, Insights und dem RHSM registrieren lassen.

Das Tool rhc selbst habe ich bereits im Artikel Red Hat Remote Host Configuration ausführlich vorgestellt.

Anwendungsfall

Möchte man ein oder mehrere RHEL-Systeme in der Hybrid Cloud Console registrieren, kann man dazu die RHEL System Role rhc verwenden.

Die Rolle

Durch die Installation des Pakets rhel-system-roles existiert die Rolle rhc bereits auf meinem System und muss nur noch konfiguriert werden. Die Rolle selbst findet man im Pfad /usr/share/ansible/roles/rhel-system-roles.rhc/ und die Dokumentation in /usr/share/doc/rhel-system-roles/rhc/README.md.

Das Playbook

- name: Register systems
  hosts: all
  vars:
    rhc_auth:
      activation_keys:
        keys: ["key-1", ...]
    rhc_organization: "your-organization"
  roles:
    - rhel-system-roles.rhc
  • key-1 ist durch den eigenen Activation Key zu ersetzen
  • your-organization ist durch die eigene Org-ID zu ersetzen
  • Mit diesem Playbook werden die Hosts im RHSM und der Hybrid Cloud Console registriert
  • Die Systeme werden bei Insights registriert und laden regelmäßig aktuelle Daten hoch
  • Die Systeme werden für die Ausführung von Remediation Playbooks konfiguriert

Fazit

Mit dieser System Role ist es einfach möglich, eine große Anzahl Systeme in die Hybrid Cloud Console aufzunehmen. Dabei lässt sich konfigurieren, ob Funktionen wie Insights und Remediation Playbooks genutzt werden können.

Eine weitere tolle Rolle aus dem Paket rhel-system-roles, die sich einfach zur Anwendung bringen lässt.

Weiterführende Quellen und Links

  1. Red Hat Enterprise Linux (RHEL) System Roles {en}
  2. Ansible Documentation: Role Directory Structure {en}
  3. Red Hat Software and Download Center {en}
  4. Die Vorteile einer Red Hat Subskription
  5. RHEL System Roles: selinux
  6. RHEL System Roles: timesync
  7. RHEL System Roles: sshd
  8. RHEL System Roles: firewall
  9. RHEL System Roles: storage

Wie ich mich 2023 vor Datenverlust schütze

04. September 2023 um 05:00

Auf Mobiltelefonen, Tablets, Laptops, Netzwerkspeichern und in diversen Anwendungen in unserem Heimnetzwerk befinden sich Daten, welche wir schmerzlich vermissen würden, wenn sie dauerhaft verloren gingen.

Im Folgenden beschreibe ich, wie ich z.B. Fotos, Videos, Zeugnisse, Verträge, Urkunden, Versicherungspolicen, etc. vor Verlust schütze.

Der Artikel behandelt nicht:

Daten von Mobiltelefonen und Tablets

Sie sind unsere ständigen Begleiter, verfügen über große Speicher und beinhalten häufig jede Menge an Fotos und Videos. Diese werden mit DS-Apps auf eine Synology Diskstation im heimischen Netzwerk gesichert.

Für Threema benutze ich Threema Safe. Ein Datenbackup führe ich nicht durch. Der Inhalt der Nachrichten ist mir nicht so wichtig, als dass mich ein Verlust schmerzen würde.

E-Mails, Kalender und Kontakte werden zwischen Mailbox.org und diversen Geräten synchronisiert, jedoch nicht gesichert. Wenn jemand z.B. das Adressbuch löscht, müsste ich das Netzwerk vom PC trennen, um das Adressbuch ohne Netzwerkverbindung zu starten, um den letzten Stand von dort wiederherstellen zu können. Für mich ist das ausreichend, da ich bei einem GAU meine wichtigsten Kontakte auch ohne Adressbuch zu erreichen weiß und sich Kontaktinformationen von Handwerkern und sonstigen Unternehmen wieder recherchieren lassen.

Sollte ich Zugriff auf die App Aegis Authenticater verlieren, muss ich auf die Backup-Codes zurückgreifen, welche in einer KeePass-Datenbank lagern.

Falls ihr einfache Lösungen kennt, um sämtliche Apps samt deren Inhalte sichern und auf abweichenden Telefonen wiederherstellen zu können, freue ich mich, wenn ihr mir davon berichtet.

Network Attached Storage (NAS)

Meine Synology Diskstation ist:

  • Das Ziel für automatisierte Datensicherungen von Mobiltelefonen und Tablets
  • Datensicherungsziel für die Backups meiner virtuellen Server im LAN und in der Cloud
  • Primärer Speicherort für Fotos, Videos, eine Musiksammlung, Git-Repos
  • Primärspeicher für archivierte Daten, die ich vermutlich nie wieder benötige

Ausgewählte Daten werden wöchentlich mit Hyper Backup (Backup-Anwendung der Diskstation) auf eine angeschlossene USB-Festplatte gesichert. Darüber hinaus habe ich mir ein Offsite-Backup gebastelt, welches ich in diesem Artikel beschrieben habe.

Über Erfolg und Misserfolg der Sicherungen werde ich per E-Mail benachrichtigt.

Die größte Herausforderung für mich ist es, die Wiederherstellbarkeit der gesicherten Daten zu kontrollieren. Dies mache ich bisher sporadisch und manuell. Und vermutlich viel zu selten.

Daten von Laptops

Daten meiner Laptops synchronisiere ich teilweise mit Nextcloud, welche ich auf einem virtuellen Server betreibe. Gehostet wird dieser bei Contabo in Deutschland.

Darüber hinaus nutze ich Déjà Dup Backups für eine wöchentliche Datensicherung meines HOME-Verzeichnisses in die Nextcloud mit 180 Tagen Vorhaltezeit. Auch hier teste dich die Wiederherstellbarkeit sporadisch.

Das HOME-Verzeichnis meines Dienstlaptops wird täglich mit Déjà Dup in das Google Drive meines Arbeitgebers gesichert.

Urkunden, Verträge, Zeugnisse und weiterer Papierkram

Auch wir haben jede Menge totes Holz im Schrank stehen, dessen Wiederbeschaffung bei Verlust mit viel Zeit und Mühe verbunden ist.

Meine Lösung für diese Herausforderung habe ich in Mein Paperless-NGX-Mini-Konzept niedergeschrieben.

Hier möchte ich die Wiederherstellung noch verbessern, indem ich auf meinem Laptop ein Ansible-Playbook ablege, welches die Paperless-NGX-Instanz auf meinem Laptop wiederherstellt. So teste ich die Wiederherstellbarkeit und habe immer eine relativ aktuelle Kopie auf der verschlüsselten Festplatte meines Laptops bei mir.

Auf einem virtuellen Server in der Cloud möchte ich diese Daten aktuell nicht so gerne hosten. Dazu muss ich mir zuvor in Ruhe Gedanken über mögliche Risiken für die Integrität und Vertraulichkeit der Daten machen.

Meine produktive Paperless-NGX-Instanz steht mit dem Papier im gleichen Haus. Das Backup beinhaltet alle PDF-Dateien und liegt verschlüsselt in der Cloud. Da die Dateinamen halbwegs sinnvoll benannt sind, scheint im Falle eines GAU die Suche im Heuhaufen nicht hoffnungslos.

Blog und Nextcloud

Für beide Dienste, welche auf einem virtuellen Server bei Contabo laufen, wird zur Datensicherung wöchentlich ein Datenbank-Dump und ein Archiv der Verzeichnisstruktur mit Ordnern und Dateien erstellt. Dieses Backup wird lokal auf dem Server abgelegt und für 30 Tage vorgehalten. Ich nutze dafür selbstgeschriebene Bash-Skripte, welche durch Cron ausgeführt werden.

Auf meinem NAS läuft ein Skript, welches die Backups vom Server auf das NAS synchronisiert.

Über Erfolg und Misserfolg der einzelnen Jobs werde ich per E-Mail benachrichtigt.

Die Wiederherstellbarkeit teste ich sporadisch und sollte dies mutmaßlich häufiger tun. Ein Automat dafür befindet sich aktuell in Arbeit. Den aktuellen Stand kann man in folgenden Artikeln nachlesen:

Virtuelle Server und Dienste in der Cloud

Ruhende Daten werden verschlüsselt, bevor sie in die Cloud hochgeladen werden. Das Restrisiko, dass der fremde Betreiber prinzipiell die Kontrolle über meinen virtuellen Server übernehmen kann, bleibt.

Betreibe ich Server oder Dienst nicht im eigenen Heimnetzwerk, nutze ich für den Betrieb deutsche Anbieter mit Standorten in Deutschland. Zu diesen habe ich einfach das größte Vertrauen, dass sie sich an geltende Gesetze halten, die Hoffnung, dass sie den Datenschutz ernst nehmen und meine Daten dort gut aufbewahrt sind.

Wie sichert ihr eure Daten außer Haus? Welche Dienste verwendet ihr dazu? Ich freue mich, wenn ihr eure Erfahrungen in den Kommentaren teilt.

Zusammenfassung

Ich habe mir zumindest mal Gedanken gemacht, welche Daten so wichtig sind, dass ich sie vor Verlust schützen möchte. Zum Schutz vor Verlust kommen verschiedene Verfahren zum Einsatz, die auf der Schaffung von Redundanz durch Synchronisierung oder der Datensicherung mit Versionierung beruhen.

Die Wiederherstellbarkeit wird zumindest sporadisch getestet. Dieser Punkt ist sicherlich ausbaufähig.

Wer die einzelnen Abschnitte gelesen hat, stellt jedoch auch fest, dass es schnell ein wenig unübersichtlich wird. Zumindest hilft dieser Artikel etwas, den Überblick zu behalten.

Für die Zukunft wünsche ich mir eine dedizierte Backup-Senke im Keller, in der sich ausschließlich Backups befinden und eine Offsite-Senke, auf welche die Daten der Backup-Senke gesichert werden. Bis ich da hinkomme, wird sicherlich noch etwas Zeit vergehen.

Wie installiere ich den Netzwerk-Drucker Brother MFC-J890DW in Fedora 38 und RHEL 9?

31. August 2023 um 07:24
  1. Schalte den Drucker ein, verbinde ihn mit dem LAN und notiere seine IP-Adresse
  2. Lade das RPM-Paket mit dem Linux-Treiber auf den RHEL 9 Computer herunter
  3. Führe in RHEL 9 folgende Schritte aus
  4. sudo dnf in <linux-treiber-name.rpm>
  5. Öffne in einem Webbrowser die URL http://localhost:631/printers
  6. Klicke unter Administration auf „Modify Printer“ und setze die folgenden Parameter
    • AppSocket/HP JetDirect für Device
    • ipp://<IP-Adresse-des-Druckers>/ipp/port1 für Device URI
    • Brother als Hersteller
    • IPP Everywhere als Treiber

Da es mich mal wieder tierisch genervt hat, bis das Höllengerät endlich druckte, habe ich die Installationsschritte kurz aufgeschrieben.

Quellen:

Container mit podman-auto-update automatisch aktualisieren

28. August 2023 um 05:00

In diesem Tutorial zeige ich euch, wie ihr eine automatische Aktualisierung für Container in rootless-Podman-Umgebungen konfigurieren und diese Container als systemd-Services verwalten könnt.

Das Tutorial gliedert sich in folgende Abschnitte:

  1. Anwendungsfälle
  2. Voraussetzungen
  3. Umgebung und verwendetes Container-Image
  4. Konfiguration des systemd-Service mit Auto-Update-Funktion
  5. Container (automatisch) aktualisieren

Wer sich nicht für die möglichen Anwendungsfälle interessiert und lieber gleich starten möchte, kann den ersten Abschnitt überspringen. Die übrigen Abschnitte sollten in der angegebenen Reihenfolge gelesen werden.

Anwendungsfälle

  • Container werden auf einem Single-Container-Host ausgeführt und nicht in K8s-Umgebungen
  • Man vertraut dem Anbieter, dass dieser stabile und nutzbare Container-Images bereitstellt
  • Es soll regelmäßig geprüft werden, ob aktualisierte Container-Images vorhanden sind
  • Sind aktuellere Images vorhanden, sollen laufende Container entfernt und unter Verwendung der aktuellen Images neu erstellt werden

Voraussetzungen

Um diesem Tutorial folgen zu können, benötigt ihr einen Host mit einer rootless-Podman-Umgebung. Podman muss dabei in der Version >= 3.3 verfügbar sein. In der folgenden Liste findet ihr einige Links, die euch helfen, eine solche Umgebung aufzusetzen.

Darüber hinaus solltet ihr Manpages lesen können.

Umgebung und verwendetes Container-Image

Das Betriebssystem spielt eine untergeordnete Rolle, da wir durch die Verwendung von Containern die Anwendung vom Betriebssystem entkoppeln. Alle zur Ausführung der Anwendung notwendigen Abhängigkeiten sind im Container-Image enthalten.

Uptime Kuma ist eine schlanke und schnelle Monitoring-Anwendung, welche unter anderem als Container-Image bereitgestellt wird. Ich habe die Anwendung als Beispiel für dieses Tutorial ausgewählt, da ich die Anwendung selbst nutzen möchte und so Synergieeffekte nutzen kann.

Wer ein anderes Container-Image nutzen möchte, muss in den folgenden Beispielen louislam/uptime-kuma:latest durch den fully qualified container name des zu nutzenden Images ersetzen.

Für die Konfiguration werden die auf dem System verfügbaren Podman-Manpages benutzt.

Konfiguration des Systemd-Service mit Auto-Update-Funktion

Bei den folgenden Schritten habe ich mich am Beispiel aus podman-auto-update(1) orientiert. Ich zeige zuerst den jeweils auszuführenden Befehl in einem Code-Block, gefolgt von einer Erläuterung der genutzten Optionen.

Podman-Volume erzeugen

$ podman volume create uptime-kuma
uptime-kuma

Um Daten persistent speichern zu können, müssen diese außerhalb des Containers abgelegt werden. Der dargestellte Befehl erzeugt ein Podman-Volume mit dem Namen „uptime-kuma“.

Mit dem folgenden Befehl lassen sich detaillierte Informationen zum gerade erstellten Volume anzeigen:

$ podman volume inspect uptime-kuma
[
     {
          "Name": "uptime-kuma",
          "Driver": "local",
          "Mountpoint": "/home/tronde/.local/share/containers/storage/volumes/uptime-kuma/_data",
          "CreatedAt": "2023-08-22T20:52:06.477341481+02:00",
          "Labels": {},
          "Scope": "local",
          "Options": {},
          "MountCount": 0,
          "NeedsCopyUp": true,
          "NeedsChown": true
     }
]

Der Schlüssel Mountpoint enthält den Pfad im lokalen Dateisystem, in dem das Volume erstellt wurde.

Manpages zum Nachschlagen:

  • podman-volume(1)
  • podman-volume-create(1)
  • podman-volume-inspect(1)

Container starten

$ podman run --label "io.containers.autoupdate=registry" -d -p 3001:3001 -v uptime-kuma:/app/data:Z --name=uptime-kuma docker.io/louislam/uptime-kuma:latest
Trying to pull docker.io/louislam/uptime-kuma:latest...
Getting image source signatures
Copying blob d7ca72974892 done  
Copying blob 475646a04a73 done  
Copying blob 1d496c24aec8 done  
Copying blob 6a3727d8681d done  
Copying blob b00c91ba9805 done  
Copying blob ddade83992f9 done  
Copying blob b8454ed537a7 done  
Copying blob 849e609eff67 done  
Copying blob f861188db6a1 done  
Copying blob 5f3c3e6d7f1c done  
Copying blob 4f4fb700ef54 skipped: already exists  
Copying blob 68b7bcf7c878 done  
Copying config fb3a3565b2 done  
Writing manifest to image destination
Storing signatures
ad7b049d9b84962311f5bafb5329f59961d8a031e54a571f079b8243ea8059ee
  • podman run ist das Kommando, mit dem ein neuer Container gestartet wird
  • Die Option --label "io.containers.autoupdate=registry" gibt an, dass Podman die Remote-Registry prüft, ob dort ein aktualisiertes Image vorhanden ist; dieses Label ist Voraussetzung, um die Auto-Update-Funktion nutzen zu können
  • Mit der Option -d wird der Container im Hintergrund gestartet und die Container-ID auf STDOUT ausgegeben
  • Durch -p 3001:3001 wird der Host-Port 3001 mit dem Port der Anwendung (ebenfalls 3001) im Container verbunden
  • Die Option -v uptime-kuma:/app/data:Z hängt das im vorhergehenden Schritt erstellte Podman-Volume in das Verzeichnis /app/data innerhalb des Containers ein; :Z sorgt dafür, dass der SELinux-Kontext korrekt gesetzt wird
  • --name=uptime-kuma spezifiziert den Namen des Containers; dieser ist etwas leichter zu merken als die Container-ID
  • Der Befehl endet mit dem fully qualified container name docker.io/louslam/uptime-kuma:latest
  • Die letzte Zeile des Code-Blocks enthält die Container-ID

Manpages zum Nachschlagen:

  • podman-run(1)
  • podman-auto-update(1)

Systemd-Service-Unit mit podman-generate-systemd erstellen

$ podman generate systemd --name --new uptime-kuma
# container-uptime-kuma.service
# autogenerated by Podman 4.4.1
# Tue Aug 22 21:29:46 CEST 2023

[Unit]
Description=Podman container-uptime-kuma.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
	--cidfile=%t/%n.ctr-id \
	--cgroups=no-conmon \
	--rm \
	--sdnotify=conmon \
	--replace \
	--label io.containers.autoupdate=registry \
	-d \
	-p 3001:3001 \
	-v uptime-kuma:/app/data:Z \
	--name=uptime-kuma docker.io/louislam/uptime-kuma:latest
ExecStop=/usr/bin/podman stop \
	--ignore -t 10 \
	--cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
	-f \
	--ignore -t 10 \
	--cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target
  • Der Befehl gibt den Inhalt der generierten Service-Unit auf STDOUT aus
  • Die Option --name verwendet den Namen des Containers anstelle der Container-ID im Dateinamen der Service-Unit (hier: container-uptime-kuma.service)
  • Wichtig ist die Option --new, um Container von aktualisierten Images erstellen zu können; ohne diese Option können Systemd-Units Container nur unter Verwendung des ursprünglichen Images starten und stoppen und ein Auto-Update ist nicht möglich
  • Der folgende Code-Block fügt dem Befehl die Option --files hinzu, um eine Service-Unit-Datei zu erstellen
$ podman generate systemd --name --new --files uptime-kuma
/home/tronde/container-uptime-kuma.service

Manpages zum Nachschlagen:

  • podman-auto-update(1)
  • podman-generate-systemd(1)

Die erstellte Systemd-Unit aktivieren und starten

$ mv -Z container-uptime-kuma.service ~/.config/systemd/user/container-uptime-kuma.service
$ systemctl --user daemon-reload
  • Der erste Befehl verschiebt die Service-Unit in einen Pfad, wo systemd sie findet und einlesen kann
  • Die Option -Z stellt sicher, dass die Datei den SELinux-Kontext des Zielverzeichnisses zugewiesen bekommt, andernfalls kann systemd die Datei ggf. nicht verarbeiten
  • Durch den zweiten Befehl wird die Unit-Datei systemd bekannt gemacht
  • An dieser Stelle ist der neue Systemd-Service geladen, jedoch inaktiv
$ systemctl --user status container-uptime-kuma.service
○ container-uptime-kuma.service - Podman container-uptime-kuma.service
     Loaded: loaded (/home/tronde/.config/systemd/user/container-uptime-kuma>
     Active: inactive (dead)
       Docs: man:podman-generate-systemd(1)
$ podman stop uptime-kumauptime-kuma
$ podman rm uptime-kumauptime-kuma
$ systemctl --user start container-uptime-kuma.service
$ systemctl --user status container-uptime-kuma.service
● container-uptime-kuma.service - Podman container-uptime-kuma.service     Loaded: loaded (/home/tronde/.config/systemd/user/container-uptime-kuma>     Active: active (running) since Tue 2023-08-22 21:59:56 CEST; 14s ago
…
  • Der erste Befehl in obigen Code-Block prüft den aktuellen Status des Service
  • Der zweite und dritte Befehl stoppen und entfernen den laufenden Container, den wir weiter oben gestartet haben
  • Befehl Nummer 4 startet den Uptime-Kuma-Service
  • Befehl Nummer 5 prüft den neuen Status des Service; dieser ist nun up-and-running

Manpages zum Nachschlagen:

  • mv(1)
  • systemd.unit(5)
  • systemctl(1)

Auf neue Container-Images prüfen

$ podman auto-update --dry-run --format "{{.Image}} {{.Updated}}"
docker.io/louislam/uptime-kuma:latest false
  • Durch die Option --dry-run wird sichergestellt, dass nur auf die Verfügbarkeit neuer Images geprüft wird, es werden jedoch keine Pull-Operationen ausgeführt und keine Container neu erstellt
  • Es wird eine Liste von Container-Images ausgegeben, die mit dem Label io.containers.autoupdate=registry gestartet wurden
  • Die erste Spalte enthält den Image-Namen
  • Die zweite Splate zeigt an, ob ein Update verfügbar ist; in diesem Fall ist kein Update verfügbar (false)

Container (automatisch) aktualisieren

Wurde die Konfiguration erfolgreich abgeschlossen, können die entsprechenden Container durch folgenden Befehl manuell aktualisiert werden:

$ podman auto-update
            UNIT                           CONTAINER                   IMAGE                                  POLICY      UPDATED
            container-uptime-kuma.service  df21116f2573 (uptime-kuma)  docker.io/louislam/uptime-kuma:latest  registry    false

Leider ist aktuell kein Update verfügbar, weshalb es hier nichts zu tun gibt und der Status von Updated gleich false ist.

Podman bringt bei der Installation die beiden systemd units podman-auto-update.timer und podman-auto-update.service mit, welche zumindest unter RHEL 9 manuell aktiviert werden müssen:

$ systemctl --user enable podman-auto-update.{service,timer}
Created symlink /home/tronde/.config/systemd/user/default.target.wants/podman-auto-update.service → /usr/lib/systemd/user/podman-auto-update.service.
Created symlink /home/tronde/.config/systemd/user/timers.target.wants/podman-auto-update.timer → /usr/lib/systemd/user/podman-auto-update.timer.

$ systemctl --user start podman-auto-update.timer
$ systemctl --user status podman-auto-update.{service,timer}
○ podman-auto-update.service - Podman auto-update service
     Loaded: loaded (/usr/lib/systemd/user/podman-auto-update.service; enabled; preset: disabled)
     Active: inactive (dead)
TriggeredBy: ● podman-auto-update.timer
       Docs: man:podman-auto-update(1)

● podman-auto-update.timer - Podman auto-update timer
     Loaded: loaded (/usr/lib/systemd/user/podman-auto-update.timer; enabled; preset: disabled)
     Active: active (waiting) since Sat 2023-09-02 20:56:09 CEST; 1s ago
      Until: Sat 2023-09-02 20:56:09 CEST; 1s ago
    Trigger: Sun 2023-09-03 00:12:22 CEST; 3h 16min left
   Triggers: ● podman-auto-update.service
  • Der Timer startet jeden Tag um Mitternacht den Auto-Update-Service
  • Der Service prüft, ob aktualisierte Container-Images verfügbar sind und führt ggf. ein Update der Container durch
  • Schlägt ein Start nach Aktualisierung des Container-Images fehl, wird der Dienst automatisch von der vorherigen Image-Version gestartet; siehe --rollback in podman-auto-update(1)
  • Der folgende Code-Block zeigt den Status, nachdem ein Update durchgeführt wurde
$ systemctl --user --no-pager -l status podman-auto-update
○ podman-auto-update.service - Podman auto-update service
     Loaded: loaded (/usr/lib/systemd/user/podman-auto-update.service; enabled; preset: disabled)
     Active: inactive (dead) since Sun 2023-09-03 00:12:56 CEST; 7h ago
TriggeredBy: ● podman-auto-update.timer
       Docs: man:podman-auto-update(1)
    Process: 309875 ExecStart=/usr/bin/podman auto-update (code=exited, status=0/SUCCESS)
    Process: 310009 ExecStartPost=/usr/bin/podman image prune -f (code=exited, status=0/SUCCESS)
   Main PID: 309875 (code=exited, status=0/SUCCESS)
        CPU: 5.128s

Sep 03 00:12:50 example.com podman[309875]: Copying config sha256:d56b643e048f2d351ed536ec9a588555dfd4c70de3c8d510ed61078a499ba464
Sep 03 00:12:50 example.com podman[309875]: Writing manifest to image destination
Sep 03 00:12:50 example.com podman[309875]: Storing signatures
Sep 03 00:12:51 example.com podman[309875]: 2023-09-03 00:12:41.98296115 +0200 CEST m=+1.880671312 image pull  docker.io/louislam/uptime-kuma:latest
Sep 03 00:12:55 example.com podman[309875]:             UNIT                           CONTAINER                   IMAGE                                  POLICY      UPDATED
Sep 03 00:12:55 example.com podman[309875]:             container-uptime-kuma.service  814407c7312c (uptime-kuma)  docker.io/louislam/uptime-kuma:latest  registry    true
Sep 03 00:12:56 example.com podman[310009]: fb3a3565b2da641402e99594e09b3cdadd1b9aa84f59e7960b9961662da5ff65
Sep 03 00:12:56 example.com podman[310009]: 2023-09-03 00:12:55.421998943 +0200 CEST m=+0.020260134 image remove fb3a3565b2da641402e99594e09b3cdadd1b9aa84f59e7960b9961662da5ff65 
Sep 03 00:12:56 example.com systemd[686]: Finished Podman auto-update service.
Sep 03 00:12:56 example.com systemd[686]: podman-auto-update.service: Consumed 5.128s CPU time.

Ich hoffe, das Tutorial hat euch gefallen und konnte euch einen Eindruck vermitteln, wie man automatische Updates für Container konfigurieren kann.

Red Hat Remote Host Configuration

21. August 2023 um 05:00

Im folgenden Text gebe ich eine Einführung in Red Hat Remote Host Configuration (rhc). Dabei handelt es sich um ein Werkzeug, um Red Hat Enterprise Linux (RHEL) System mit der Hybrid Cloud Console zu verbinden und aus dieser heraus verwalten zu können.

Der Artikel soll interessierten RHEL-Nutzern zur Information und Wissensvermittlung dienen. Dazu wird rhc auch im Kontext subscription-manager und insights-client eingeordnet.

Aus Gründen der Transparenz weise ich hiermit darauf hin, dass ich Angestellter der Firma Red Hat bin.

Hintergrund

Als ich persönlich angefangen habe, mich für RHEL zu interessieren, war die Version 7 aktuell und von Simple Content Access (SCA) noch keine Rede. Um RHEL-Systeme betreiben zu können, waren diese beim Red Hat Subscription Management (RHSM), einem Satellite-Server oder offline zu registrieren, um Subscription Entitlements zuweisen zu können. Hierfür gab und gibt es das Kommando subscription-manager.

Im Laufe der Zeit kam der Dienst Red Hat Insights hinzu, zu welchem es hier im Blog bereits eine Einführung gab. Um Systeme hierfür zu registrieren, gibt es das Kommando insights-client. Die Console, die einst nur Red Hat Insights beheimatete, hat sich zur Hybrid Cloud Console entwickelt, welche heute Heimat für viele weitere Dienste rund um RHEL, OpenShift und die Ansible Automation Platform (AAP) ist.

Es hat sich viel getan. Dank SCA [1] entfällt die Notwendigkeit, Entitlements zuweisen zu müssen und das Subscription Management befindet sich im Übergang zur Hybrid Cloud Console. Übergang bedeutet hier insbesondere, dass viele Teile in Bewegung sind und sich in Zukunft noch ändern werden. Der Artikel unter [6] gibt einen Überblick dazu.

Hybrid Cloud Console mit Insights und Ansible Remediation Playbooks

Die folgenden vier Absätze wurden der Dokumentation entnommen und mit www.DeepL.com/Translator (kostenlose Version) übersetzt.

Die Red Hat Hybrid Cloud Console ist eine webbasierte, einheitliche Verwaltungsoberfläche für Red Hat-Lösungen. Mit der Hybrid Cloud Console können Sie eine Verbindung zu Ihren verschiedenen Plattformen herstellen und dann Ihre Hybrid Cloud und die darin enthaltenen Systeme zentral verwalten und automatisieren.

Verwenden Sie die Hybrid Cloud Console, um Ihre RHEL-Infrastruktur, Red Hat OpenShift-Cluster, AAP-Infrastruktur und Anwendungsdienste zu verwalten.

Die Red Hat Hybrid Cloud Console bietet einen zentralen Einblick in Betrieb, Sicherheit und Subscriptions für Red Hat Enterprise Linux (RHEL).

Mithilfe von Tools, regelbasierten Analysemodellen und der Unterstützung von Red Hat können Sie die Konsole nutzen, um viele der Aufgaben und Analysen zu optimieren, die für den Aufbau und die Bereitstellung einer stabilen und sicheren Umgebung für Anwendungen auf RHEL erforderlich sind.

Dem Marketing-Text der vorstehenden Absätze möchte ich einen Hinweis hinterherschicken. Mit der Hybrid Cloud Console verhält es sich wie mit allen extern gehosteten Cloud-Diensten. Hat der Anbieter ein Problem oder ist die Cloud bzw. das Internet nicht verfügbar, ist auch der Cloud-Dienst nicht verfügbar. Bei der Fähigkeit, meine Infrastruktur zu administrieren, möchte ich mich persönlich daher nicht allein auf einen externen Dienst verlassen und empfehle dies auch niemanden. In meinen Augen ist die Hybrid Cloud Console ein zusätzliches Werkzeug, welches mit Red Hat Insights einen hohen Mehrwert bietet.

In den nun folgenden Abschnitten beschreibe ich, wie in der Hybrid Cloud Console ein Activation Key erstellt wird und wie man diesen nutzt, um Systeme mittels rhc in der Console zu registrieren. Anschließend zeige ich, wie dank rhc Ansible Remediation Playbooks direkt aus der Console heraus auf verbundenen RHEL-Systemen ausgeführt werden können.

Ob man einem extern durch Dritte gehosteten Dienst das Recht einräumen möchte, Änderungen an den eigenen Server-Systemen durchführen zu können, muss jeder für sich selbst und seine Umgebung bewerten. Ich möchte hier lediglich die Funktionalität in meiner Lab-Umgebung demonstrieren.

Activation Key erstellen

Um einen Activation Key zu erstellen [10], meldet man sich an der Hybrid Cloud Console (https://console.redhat.com) an und tippt in das Suchfeld im oberen Bereich „create activation key“ ein.

Startseite der Hybrid Cloud Console. In das Suchfeld im oberen Bereich der Seite wurde der Text "create activation key" eingegeben. Es werden zwei Suchergebnisse angezeigt.
Ausgefüllte Suchmaske in der Hybrid Cloud Console

Der erste Treffer führt uns zu folgender Maske, in der ein Activation Key erstellt werden kann:

Menü zur Erstellung von Activation Keys
Dialog zum Erstellen von Activation Keys. Hier werden die Parameter Name, Role, SLA und Usage definiert.
Dialog zur Erstellung des Activation Keys

Nach einem Klick auf die Schaltfläche Create activation key erscheint der oben dargestellte Dialog. Die Optionen, die unter Role, Service Level Agreement (SLA) und Usage zur Auswahl stehen, hängen von den im Account vorhandenen Subscriptions ab. Mit ihnen wird der sogenannte System Purpose bestimmt. Der Name kann frei gewählt werden. Er erscheint anschließend in der Übersicht.

Übersicht existierender Activation Keys
Übersicht der existierenden Activation Keys

Hinweis: Die Organization ID und der Name des Activation Key sind vertraulich zu behandeln, da mit diesen Informationen Systeme für die Hybrid Cloud Console registriert werden können.

System mit rhc registrieren

Mit dem Befehl rhc -h erhält man eine Beschreibung, wie Organization ID und Activation Key genutzt werden, um das System bei Red Hat zu registrieren:

DESCRIPTION:
   The rhc command controls the system's connection to Red Hat.
   
   To connect the system using an activation key:
     rhc connect --organization ID --activation-key KEY

Führt man den Befehl wie angegeben aus und ist die Registrierung erfolgreich, erhält man folgende Ausgabe:

Connecting host.example.com to Red Hat.
This might take a few seconds.

● Connected to Red Hat Subscription Management
● Connected to Red Hat Insights
● Activated the Remote Host Configuration daemon
● Enabled console.redhat.com services: remote configuration, insights, remediations, compliance

Successfully connected to Red Hat!

Manage your connected systems: https://red.ht/connector

Unter der URL https://red.ht/connector ist der Remote Host Configuration Manager erreichbar. Hier werden die aktuellen Einstellungen angezeigt und können bei Bedarf geändert werden.

Das Bild zeigt die Konfigurationsseite des Remote Host Configuration Manager. Hier werden die Einstellungen für Insights Remediations, rhc Einstellungen und OpenSCAP Policies vorgenommen.
Darstellung der Seite Remote Host Configuration Manager

Der rhc Client konfiguriert auf dem RHEL host den rhcd service, welcher die Verbindung zur Hybrid Cloud Console initiiert und über eine MQTT-Verbindung auf Instruktionen lauscht [14].

Möchte man mehrere Systeme registrieren, empfehle ich die Verwendung der RHEL System Role rhc. Auf diese werde ich in einem folgenden Beitrag noch genauer eingehen.

Die Registrierung und Einbindung in die Hybrid Cloud Console ist damit abgeschlossen.

Ansible Remediation Playbook erstellen und ausführen

Die offizielle Dokumentation für die folgenden Schritte befindet sich unter [12]. Ich habe ein System gewählt, welches noch nicht aktualisiert wurde und daher einige Schwachstellen aufweist.

Das Bild zeigt eine Übersicht von CVEs. Zwei CVEs wurden für die Remediation mit Ansible ausgewählt.
Übersicht der vorhandenen CVE. Zwei Einträge wurden für die Remediation mit Ansible ausgewählt.

In der Übersicht können CVE ausgewählt werden, welche mit Hilfe eines Ansible Remediation Playbook geschlossen werden sollen. Mit einem Klick auf die Schaltfläche Remediate gelangt man in den Assistenten zur Erstellung des Playbooks.

Das Bild zeigt einen Dialog, in dem ein Name für ein neues Playbook vergeben wird.
Der Name des Playbooks kann frei gewählt werden.
Im dargestellten Dialog werden die ausgewählten Systeme angezeigt. Eine Bearbeitung ist hier nochmals möglich.
In Schritt zwei können verwundbare Systeme ausgewählt werden.
Das Bild zeigt den letzten Dialog des Remediate-Assistenten. Es wird auf einen automatischen Neustart hingewiesen.
Review der Einstellungen mit dem Hinweis, dass das Zielsystem durch das Playbook automatisch neugestartet wird.
Das Bild zeigt einen Screenshot von der erfolgreichen Erstellung eines Playbooks.
Bis hierher wurde nur ein Playbook erstellt. Es wurde noch keine Remediation durchgeführt.

Die erstellten Playbooks findet man im Menü unter Red Hat Insights –> Automation Toolkit –> Remediations. Bisher kann das Playbook hier allerdings nur heruntergeladen werden, um es auf einem Ansible Controller in der eigenen Infrastruktur auszuführen. Um diese Playbooks direkt aus der Hybrid Cloud Console heraus ausführen zu können, muss der verwendete User Mitglied einer Gruppe mit der Rolle Remediations administrator sein.

Ein Exkurs in die Rollen- und Rechteverwaltung der Hybrid Cloud Console würde an dieser Stelle zu weit führen. Nachdem die Voraussetzungen für die Ausführung von Remediation Playbooks geschafften wurden, stehen folgende Schritte zur Verfügung.

In der Ansicht des Remediation Jobs kann das Playbook nun direkt ausgeführt werden.
Eine letzte Bestätigung, dann geht es los.

Im Hintergrund passiert nun folgendes:

  1. Das Playbook wird auf den oder die Hosts übertragen
  2. Auf den Hosts wird es durch die dort lokal installierte Ansible Engine (Paket ansible-core) ausgeführt
  3. Der Host wird anschließend automatisch neugestartet
  4. In der Console wird anschließend sichbar, dass die Remediation abgeschlossen wurde

Ob man einem SaaS-Dienst, der von einem US-Unternehmen in den USA gehostet wird, Zugriff auf die eigenen Server gewähren möchte bzw. darf, muss individuell bewertet werden.

Ich gestehe dem Service allerdings zu, dass er die Verwaltung und Remediation von Sicherheitslücken, fehlenden Advisories und Konfigurationsanpassungen durch den Advisor denkbar einfach gestaltet.

Ein Werkzeug für alles?

Für die in diesem Text aufgeführten Anwendungsfälle

  • Registrieren eines RHEL-Hosts an der Hybrid Cloud Console
  • Ausführen von Ansible Remediation Playbooks

ist die Verwendung des rhc-Clients ausreichend; ein Ersatz für den insights-client ist er allerdings nicht. Letzterer wird im Hintergrund weiterhin verwendet, um Insights-Reports an die Hybrid Cloud Console zu senden.

Auch die vielfältigen Optionen des subscription-manager werden nicht abgebildet. Der rhc-Client ist daher mehr eine Ergänzung als ein Ersatz für die bekannten Kommandos.

Fazit

Der rhc-Client ist in meinen Augen das Mittel der Wahl, möchte man RHEL-Systeme für die Verwaltung durch Insights und die Ausführung von Ansible Remediation Playbooks an die Hybrid Cloud Console anbinden.

Ich hoffe euch interessierten Lesern, die bishierhin ausgehalten haben, hat diese Einführung gefallen. In der folgenden Liste findet ihr einige Links, hinter denen ihr euer Wissen noch vertiefen könnt.

Quellen und weiterführende Links

  1. Remote Host Configuration and Management – Using the remote host configuration and management features for Red Hat Insights
  2. Simple Content Access
  3. Red Hat Subscription Management
  4. Red Hat Insights
  5. Einführung in Red Hat Insights
  6. Transition of Red Hat’s subscription services to console.redhat.com
  7. Red Hat Hybrid Cloud Console
  8. Product Documentation for Red Hat Hybrid Cloud Console 2023
  9. Subscription-Manager for the former RHN user, part 13: System Purpose
  10. Remote Host Configuration and Management: Chapter 6. Creating and managing activation keys in the Red Hat Hybrid Cloud Console
  11. Automating system administration by using RHEL System Roles: Chapter 7. Using the rhc System Role to register the system
  12. Creating and managing remediation playbooks in Insights
  13. Executing remediation playbooks
  14. Remote Host Configuration (rhc)

Warum entwickelt/testet ihr (nicht) auf CentOS Stream, Fedora oder RHEL?

07. August 2023 um 05:00

Hi, mein Name ist Jörg. Ich arbeite seit März 2023 als Senior Technical Account Manager für Red Hat und mir schwirren derzeit folgende Fragen im Kopf herum:

  • Wer sind die Menschen, die Open Source Software auf bzw. für CentOS Stream, Fedora und/oder RHEL entwickeln?
    • Sind es Menschen, die dies ausschließlich in ihrer Freizeit tun?
    • Arbeiten sie in Unternehmen, welche nach dem Open Source Entwicklungsmodell arbeiten?
  • Warum habt ihr euch für oder gegen die eine oder andere Distribution entschieden?
  • Was hindert euch daran, eine der genannten Distributionen zu verwenden?
  • Aus welchem Grund bevorzugt ihr andere Distributionen und welche sind dies?

Hinsichtlich dieser Fragen habe ich selbst offensichtlich einen Interessenskonflikt und bin darüber hinaus zu einem hohen Grad betriebsblind. Deshalb bin ich umso mehr daran interessiert, eure Antworten auf diese Fragen zu lesen.

Ich freue mich, wenn ihr euch die Zeit nehmt, um mir zu antworten und mir zu erläutern, wie ihr dazu steht. Eure Nachrichten nehme ich gern auf folgenden Kanälen entgegen:

  • Als Kommentar unter diesem Artikel
  • Als E-Mail an jkastning+distribution (at) my-it-brain (dot) de
  • Als Chat-Nachricht in #my-it-brain:matrix.org

Es freut mich, wenn daraus eine freundliche und konstruktive Diskussion entsteht. Sollte es dabei allerdings zu Trolling oder unangemessenen Äußerungen kommen, werde ich die Kommentare schließen und die Kommunikation einstellen. Bitte geht daher höflich miteinander um und behandelt einander so, wie ihr selbst auch behandelt werden möchtet.

Mein Paperless-NGX-Mini-Konzept

31. Juli 2023 um 05:00

Paperless-NGX ist ein bekanntes und beliebtes Open Source Dokumenten-Management-System (DMS). Auch ich möchte zukünftig meinen „Papierkram“ darin verwalten.

In diesem Artikel halte ich meine Gedanken fest, wie ich plane, paperless-ngx in meiner Umgebung aufzusetzen und zu betreiben.

Dies hilft mir, zu prüfen, ob ich auch an alles Wichtige gedacht habe. Falls euch das Konzept gefällt, dürft ihr es selbstverständlich gerne nachahmen. Und wenn ihr schwerwiegende Fehler darin entdeckt, freue ich mich über einen Hinweis.

Es ist kein Tutorial und keine Schritt-für-Schritt-Anleitung. Zwar mag dieser Text dazu dienen, sich eine eigene Umgebung aufzubauen, Mitdenken ist dabei jedoch zwingend erforderlich.

Ziele

  • Betrieb von Paperless-NGX als rootless-Podman-Container
  • Consumption-Ordner als Samba-Share freigegeben, um via Netzwerk Dateien hineinkopieren zu können
  • Getrennte Benutzerkonten für meine Frau und mich
  • Freigabe gewisser Dokumente für weitere Benutzer(gruppen)
  • Erfolgreicher Restore-Test

Infrastruktur

In meinem Heimnetzwerk betreibe ich einen Desktop-/Server-PC. Auf diesem läuft aktuell RHEL 9 als KVM/QEMU-Hypervisor. Er dient mir ebenfalls als Ansible Control Node. Hierauf betreibe ich eine RHEL-9-VM mit einer rootless-Podman-Installation. Diese VM wird auch meine Paperless-NGX-Instanz hosten.

In der VM wird das EPEL-Repository aktiviert, um daraus die Pakete podman-compose und python3-pexpect installieren zu können.

Falls ich mal nicht mehr weiß, wie dieses Setup aufgebaut wird, finden sich dazu Hinweise in folgenden Links:

Installation mit Ansible

Für die Installation der Anwendung wird die Container Route verwendet. Die Installation wird dabei unter Nutzung der Ansible-Rolle tronde.paperless_ngx_with_rootless_podman automatisiert.

Das Playbook deploy_paperless_ngx.yml, welches auf meiner Synology Diskstation abgelegt ist, führt die Installation und Konfiguration der Anwendung durch. Es installiert und konfiguriert zudem Samba und die Datei-Freigabe des Consumption-Verzeichnisses.

In dem Playbook werden folgende Rollen verwendet:

Die Rollen sind mit dem Playbook in meinem Ansible-Projekt-Verzeichnis auf meiner Synology Diskstation installiert.

Alle Playbooks und Rollen werden mit Git versioniert. Die Repositories werden auf entfernte Rechner synchronisiert.

Vorbereitung

Die Dateien docker-compose.postgres-tika.yml, docker-compose.env und .env werden aus dem Projekt-Repository in das Rollen-Verzeichnis files meiner Ansible-Rolle heruntergeladen. Die Datei docker-compose.postgres-tika.yml wird dabei zu docker-compose.yml umbenannt und bearbeitet.

Um Datenverlust vorzubeugen, wird die Ansible-Rolle mit den angepassten Dateien in die regelmäßige Datensicherung aufgenommen.

Folgende Variablen werden in meinem Ansible-Vault hinterlegt:

# Paperless-ngx with podman-compose
pnwrp_podman_user: alice
pnwrp_podman_group: alice
pnwrp_compose_dir: /home/{{ pnwrp_podman_user }}/paperless-ngx
pnwrp_paperless_superuser: alice
pnwrp_paperless_superuser_email: alice@example.com
pnwrp_paperless_superuser_password: ImWunderland
## Username and password for document scanner
brother_scanner_user: scanner
brother_scanner_pass: ImWunderland

Die Werte der Variablen werden selbstverständlich angepasst.

Das Playbook

Folgender Code-Block zeigt das fertige Playbook mit Beispielwerten:

---
- hosts: host.example.com
  remote_user: alice
  debugger: never
  vars_files:
    - files/alice.vault
  tasks:
    - name: Setup Paperless-NGX with podman-compose in rootless Podman
      include_role:
        name: ansible_role_paperless-ngx_with_rootless_podman

    - name: Enable Port 8000/tcp in host firewall
      ansible.posix.firewalld:
        port: 8000/tcp
        immediate: true
        permanent: true
        state: enabled
      become: true

    - name: >-
        Create and add {{ brother_scanner_user }} to
        {{ pnwrp_podman_group }}
      ansible.builtin.user:
        name: "{{ brother_scanner_user }}"
        comment: "Brother Dokumenten-Scanner"
        create_home: false
        groups: "{{ pnwrp_podman_group }}"
        append: true
        shell: /usr/sbin/nologin
        state: present
        system: true
      become: true

    - name: Include role vladgh.samba.server
      include_role:
        name: vladgh.samba.server
      vars:
        ansible_become: true
        samba_users:
          - name: "{{ pnwrp_podman_user }}"
            password: "{{ alice_password }}"
          - name: "{{ brother_scanner_user }}"
            password: "{{ brother_scanner_pass }}"
        samba_shares:
          - name: consumption
            comment: 'paperless consumption directory'
            path: "{{ pnwrp_compose_dir }}/consume"
            read_only: false
            guest_ok: false
            browseable: true
            owner: "{{ pnwrp_podman_user }}"
            group: "{{ pnwrp_podman_group }}"
            write_list: +{{ pnwrp_podman_group }}

    - name: Enable samba in host firewall
      ansible.posix.firewalld:
        service: samba
        immediate: true
        permanent: true
        state: enabled
      become: true

Das Playbook gewinnt sicher keinen Schönheitswettbewerb, doch arbeitet es bisher robust und tut, was es soll. In Tests habe ich meine Wunschumgebung damit mehrmals provisioniert.

Backup & Restore

Wie es sich gehört, wird erst ein Backup erstellt, dann die Anwendung inkl. aller Daten gelöscht und wiederhergestellt.

Backup

Für das Backup verwende ich ein Ansible-Playbook, welches sich zum Podman-Host verbindet und dort folgende Aufgaben ausführt:

  1. Stelle sicher, dass das Backup-Verzeichnis auf dem Remote-Host existiert
  2. Stoppe alle Paperless-NGX-Container
  3. Exportiere Podman-Volumes in TAR-Archive; hänge das aktuelle Datum an die Dateinamen an
  4. Archiviere und komprimiere paperless-ngx-Verzeichnis auf Remote-Host; hänge das aktuelle Datum an die Dateinamen an
  5. Starte alle Paperless-NGX-Container
  6. Komprimiere die Exporte der Podman-Volumes
  7. Synchronisiere das Backup-Verzeichnis auf dem Remote-Host mit einem Verzeichnis auf meiner Diskstation
  8. Synchronisiere das Diskstation-Verzeichnis mit einem verschlüsselten S3-Bucket

Es fehlt die Aufgabe, alte Backups aufzuräumen. Darum werde ich mich kümmern, wenn 70% des verfügbaren Speicherplatzes belegt sind.

Der folgende Code-Block zeigt ein Muster des verwendeten Playbooks:

---
- name: Backup podman volumes
  hosts: host.example.com
  gather_facts: true
  vars:
    paperless_ngx_dir: /home/alice/paperless-ngx
    docker_compose_file: docker-compose.yml
    remote_backup_dir: /home/alice/backups
    diskstation_backup_dir: /home/alice/diskstation/home/backups/host.example.com

  tasks:
    - name: Ensure backup directory exists
      ansible.builtin.file:
        path: "{{ remote_backup_dir }}"
        state: directory
        owner: alice
        group: alice
        mode: 0777

    - name: Stop paperless-ngx containers
      ansible.builtin.command: >
        podman-compose -f {{ paperless_ngx_dir }}/{{ docker_compose_file }} stop

    - name: List podman volumes
      ansible.builtin.command: podman volume ls --quiet
      register: __podman_volumes
      tags:
        - volumes

    - name: Output __podman_volumes
      ansible.builtin.debug:
        msg: "{{ item }}"
      loop: "{{ __podman_volumes['stdout_lines'] }}"
      tags:
        - volumes

    - name: Export podman volumes
      ansible.builtin.command: >
        podman volume export {{ item }} --output {{ remote_backup_dir }}/{{ item }}_{{ ansible_facts['date_time']['date'] }}.tar
      loop: "{{ __podman_volumes['stdout_lines'] }}"

    - name: Compact {{ paperless_ngx_dir }}
      community.general.archive:
        path: "{{ paperless_ngx_dir }}"
        dest: "{{ remote_backup_dir }}/paperless-ngx_{{ ansible_facts['date_time']['date'] }}.tar.gz"
        format: gz

    - name: Start paperless-ngx containers
      ansible.builtin.command: >
        podman-compose -f {{ paperless_ngx_dir }}/{{ docker_compose_file }} start

    - name: Compress volume exports
      community.general.archive:
        path: "{{ remote_backup_dir }}/{{ item }}_{{ ansible_facts['date_time']['date'] }}.tar"
        format: gz
        remove: true
      loop: "{{ __podman_volumes['stdout_lines'] }}"
      tags:
        - compress

    - name: Sync backups to diskstation
      ansible.posix.synchronize:
        archive: true
        compress: false
        delete: false
        dest: "{{ diskstation_backup_dir }}"
        mode: pull
        private_key: /home/alice/.ssh/ansible_id_rsa
        src: "{{ remote_backup_dir }}/"
      delegate_to: localhost
      tags:
        - rsync

    - name: Sync backups from diskstation to contabo S3
      ansible.builtin.command: rclone sync -P ../backups/ secure:backups
      delegate_to: localhost
      tags:
        - rsync

Das Playbook wird einmal wöchentlich ausgeführt. Ob ich für die geplante Ausführung cron oder systemd timer units verwende, habe ich noch nicht entschieden. Ich tendiere aus Neugier zu letzterem.

Um ein Offsite-Backup zu haben, werden die Dateien von der Diskstation einmal wöchentlich verschlüsselt und in einen S3-Speicher synchronisiert. Ich nutze dafür das Programm rclone und S3-kompatiblen Speicher von Contabo. Die folgenden Links bieten weiterführende Informationen dazu:

Restore

Der Ablaufplan für die Wiederherstellung der Anwendung mit ihren Daten sieht wie folgt aus:

  1. Eine rootless-Podman-Umgebung bereitstellen
  2. podman-compose bereitstellen
  3. TAR-Archive auf Zielsystem übertragen
  4. Paperless-NGX mit Playbook installieren
  5. Alle Container stoppen
  6. Inhalt der TAR-Archive in die Podman-Volumes importieren (siehe podman-volume-import(1)): gunzip -c hello.tar.gz | podman volume import myvol -
  7. Alle Container starten

Fazit

Bereitstellung, Sicherung und Wiederherstellung funktionieren wie beschrieben. Damit kann ich nun beginnen und die Anwendung konfigurieren und mit meinem Papierkram füttern.

Die Samba-Freigabe habe ich ebenfalls getestet. Sie funktioniert wie erwartet. PDF-Dateien mit dem Befehl find Documents -type f -iname "*.pdf" -exec cp {} /consume \; hineinzukopieren ist übrigens besonders dann eine gute Idee, wenn man sehen möchte, welche Dateien so in den Tiefen des eigenen Dateisystems schlummern.

Mit Ansible über YAML Lists and Dictionaries iterieren

17. Juli 2023 um 05:00

In diesem Artikel beschreibe ich die beiden Ansible-Variablen-Typen „List variables“ und „Dictionary variables“ sowie die Kombination beider Typen. Ich zeige mit einem einfachen Playbook, wie diese Variablen-Typen in einer Schleife (eng. loop) durchlaufen werden können.

Während der Text mir zur Übung und Erinnerung dient, hoffe ich, dass er für die Einsteiger unter euch eine hilfreiche Einführung bietet. Für weiterführende Informationen verlinke ich im Text direkt auf die Ansible-Dokumentation.

List

Eine Liste ist eine Variable mit einem Namen und einem bis mehreren Werten. Folgender Code-Block zeigt die List-Variable namens list mit ihren zwei Werten:

list:
  - Alice Cooper
  - Bob Marley

Die Einrückung der Werte ist wichtig. Sie erhöht nicht nur die Lesbarkeit, sondern vermeidet auch Lint-Fehler bei der Anwendung von ansible-lint. Bedauerlicherweise läuft euer Playbook auch, wenn ihr die Werte nicht einrückt, doch bitte ich euch, euch diesen schlechten Stil nicht anzugewöhnen.

Listen sind mit Arrays verwand. Sie besitzen einen Index, welcher bei 0 beginnt und für jedes Listen-Element (für jeden Wert) um 1 inkrementiert wird. Folgendes Beispiel zeigt, wie man das Listen-Element mit dem Wert „Alice Cooper“ der einfachen Variable favorit zuweisen kann:

favorit: "{{ list[0] }}"

Dictionary

Ein Dictionary speichert Daten in Schlüssel-Wert-Paaren (excuse my German). Dabei darf der Wert eines Dictionary wiederum ein Dictionary sein.

Ein einfaches Dictionary sieht wie folgt aus:

Felder:
  Feld1: 10ha
  Feld2: 40ha

Möchte man z.B. auf den Wert des Schlüssels Feld2 aus dem Dictionary Felder zugreifen, geht dies wie folgt:

mein_feld: "{{ Felder['Feld2'] }}"
# oder
mein_feld: "{{ Felder.Feld2 }}"

Die beiden folgenden Code-Blöcke zeigen zwei Beispiele für etwas komplexere Dictionaries, über die ich später iterieren werde:

dict:
  Alice:
    last_name: Cooper
    job: singer
  Bob:
    last_name: Marley
    job: singer
virtual_machines_with_params:
  vm1:
    cpu_count: 2
    memory_mb: 2048
    guest_os: rhel8
  vm2:
    cpu_count: 2
    memory_mb: 1024
    guest_os: rhel9

Auch hier ist die Einrückung sehr wichtig. Macht man dabei einen Fehler, fängt man sich einen Syntax-Fehler bei der Ausführung des Playbooks ein.

List of Dictionaries

Beide zuvor beschriebenen Variablen-Typen können miteinander kombiniert werden. Folgendes Beispiel zeigt eine Liste von Dictionaries:

list_of_dicts:
  - first_name: Alice
    last_name: Cooper
    job: singer
  - first_name: Bob
    last_name: Marley
    job: singer

Syntaxfehler

In Ansible und YAML spielt die Einrückung von Code eine sehr wichtige Rolle. Des Weiteren ist bei der Kombination von Variablen-Typen nicht alles erlaubt. Folgender Code-Block zeigt ein fehlerhaftes Beispiel und die Fehlermeldungen, die es generiert:

$ cat nonsense.yml 
---
nonsense:
 - first_name: Alice
     last_name: Cooper
     job: singer
 - first_name: Bob
     last_name: Marley
     job: singer

$ ansible-lint nonsense.yml
WARNING  Listing 1 violation(s) that are fatal
load-failure: Failed to load YAML file
nonsense.yml:1 mapping values are not allowed in this context
  in "<unicode string>", line 4, column 15


             Rule Violation Summary              
 count tag          profile rule associated tags 
     1 load-failure min     core, unskippable    

Failed after : 1 failure(s), 0 warning(s) on 1 files.

Tipp: Um Fehler bei der Eingabe zu vermeiden, habe ich meinen Editor Vim mit folgenden Optionen konfiguriert: set ts=2 sts=2 sw=2 et ai cursorcolumn

Playbook

Das folgende Playbook nutzt das Modul ansible.builtin.debug, um Werte der genannten Variablen-Typen auszugeben. Es zeigt dabei, wie diese Variablen in einer Schleife durchlaufen werden können.

Damit es übersichtlich bleibt, nutze ich Tags, um die Tasks im Playbook einzeln ausführen zu können.

$ cat output_dicts_and_lists.yml 
---
- name: Output content of dicts_and_lists.yml
  hosts: localhost
  gather_facts: false
  become: false
  vars_files:
    - dicts_and_lists.yml
  tasks:
    - name: Task 1 Ouput all vars in dicts_and_lists.yml
      loop:
        - "{{ list }}"
        - "{{ dict }}"
        - "{{ list_of_dicts }}"
      ansible.builtin.debug:
        var: item
      tags:
        - dicts_and_lists

    - name: Task 2 Loop over some list
      loop: "{{ list }}"
      ansible.builtin.debug:
        msg: "Name: {{ item }}"
      tags:
        - list

    - name: Task 3 Loop over some dictionary
      loop: "{{ dict | dict2items }}"
      ansible.builtin.debug:
        msg: "Firstname: {{ item.key }} Lastname: {{ item.value.last_name }}"
      tags:
        - dict

    - name: Task 4 Loop over some list_of_dicts
      loop: "{{ list_of_dicts }}"
      ansible.builtin.debug:
        msg: "Firstname: {{ item.first_name }} Lastname: {{ item.last_name }}"
      tags:
        - list_of_dicts

Task 1: Ouput all vars in dicts_and_lists.yml

Dies ist der erste Task aus obigem Playbook. Er gibt die Werte der Variablen list, dict und list_of_dicts aus. Diese habe ich als Liste an loop übergeben (siehe Loops in der Dokumentation).

$ ansible-playbook output_dicts_and_lists.yml --tags dicts_and_lists
…
PLAY [Output content of dicts_and_lists.yml] ***********************************

TASK [Task 1 Ouput all vars in dicts_and_lists.yml] ****************************
ok: [localhost] => (item=['Alice Cooper', 'Bob Marley']) => {
    "ansible_loop_var": "item",
    "item": [
        "Alice Cooper",
        "Bob Marley"
    ]
}
ok: [localhost] => (item={'Alice': {'last_name': 'Cooper', 'job': 'singer'}, 'Bob': {'last_name': 'Marley', 'job': 'singer'}}) => {
    "ansible_loop_var": "item",
    "item": {
        "Alice": {
            "job": "singer",
            "last_name": "Cooper"
        },
        "Bob": {
            "job": "singer",
            "last_name": "Marley"
        }
    }
}
ok: [localhost] => (item=[{'first_name': 'Alice', 'last_name': 'Cooper', 'job': 'singer'}, {'first_name': 'Bob', 'last_name': 'Marley', 'job': 'singer'}]) => {
    "ansible_loop_var": "item",
    "item": [
        {
            "first_name": "Alice",
            "job": "singer",
            "last_name": "Cooper"
        },
        {
            "first_name": "Bob",
            "job": "singer",
            "last_name": "Marley"
        }
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In der Ausgabe ist zu erkennen, dass Listen mit [ ] und Dictonaries mit { } umschlossen werden. Der folgende Code-Block zeigt zum Vergleich den Inhalt der Datei dicts_and_lists.yml.

---
list:
  - Alice Cooper
  - Bob Marley

dict:
  Alice:
    last_name: Cooper
    job: singer
  Bob:
    last_name: Marley
    job: singer

list_of_dicts:
  - first_name: Alice
    last_name: Cooper
    job: singer
  - first_name: Bob
    last_name: Marley
    job: singer

Task 2: Loop over some list

Als Nächstes schauen wir uns die Ausgabe von Task 2 an, welcher lediglich die einzelnen Listenelemente nacheinander ausgibt.

$ ansible-playbook output_dicts_and_lists.yml --tags list
PLAY [Output content of dicts_and_lists.yml] ***********************************

TASK [Task 2 Loop over some list] **********************************************
ok: [localhost] => (item=Alice Cooper) => {
    "msg": "Name: Alice Cooper"
}
ok: [localhost] => (item=Bob Marley) => {
    "msg": "Name: Bob Marley"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Die Variable item referenziert das jeweils aktuelle Element der Liste, welche mit loop durchlaufen wird.

Task 3: Loop over some dictionary

Um Scrollen zu vermeiden, zeigten die beiden folgenden Code-Blöcke noch einmal den entsprechenden Task aus obigem Playbook und das Dictionary, welches für dieses Beispiel benutzt wird. Der dritte Code-Block zeigt dann die dazugehörige Ausgabe.

    - name: Task 3 Loop over some dictionary
      loop: "{{ dict | dict2items }}"
      ansible.builtin.debug:
        msg: "Firstname: {{ item.key }} Lastname: {{ item.value.last_name }}"
      tags:
        - dict

Bevor ein Dictionary mit loop verarbeitet werden kann, muss es in eine Liste transformiert werden. Dies geschieht mit Hilfe des Filters dict2items.

In einigen älteren Playbooks sieht man statt loop ein Lookup-Plugin in der Form with_dict: "{{ dict }}". Dies ist ebenfalls korrekt, heute jedoch nicht mehr gebräuchlich.

dict:
  Alice:
    last_name: Cooper
    job: singer
  Bob:
    last_name: Marley
    job: singer
$ ansible-playbook output_dicts_and_lists.yml --tags dict

PLAY [Output content of dicts_and_lists.yml] ***********************************

TASK [Task 3 Loop over some dictionary] *****************************************
ok: [localhost] => (item={'key': 'Alice', 'value': {'last_name': 'Cooper', 'job': 'singer'}}) => {
    "msg": "Firstname: Alice Lastname: Cooper"
}
ok: [localhost] => (item={'key': 'Bob', 'value': {'last_name': 'Marley', 'job': 'singer'}}) => {
    "msg": "Firstname: Bob Lastname: Marley"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Task 4: Loop over some list_of_dicts

Auch hier sind Dictionaries involviert, doch wird kein Filter dict2items benötigt, da es sich bereits um eine Liste handelt, welche an loop übergeben wird.

Die drei folgenden Code-Blöcke zeigen die verwendete Liste, den Task aus obigem Playbook und die Ausgabe.

list_of_dicts:
  - first_name: Alice
    last_name: Cooper
    job: singer
  - first_name: Bob
    last_name: Marley
    job: singer
    - name: Task 4 Loop over some list_of_dicts
      loop: "{{ list_of_dicts }}"
      ansible.builtin.debug:
        msg: "Firstname: {{ item.first_name }} Lastname: {{ item.last_name }}"
      tags:
        - list_of_dicts
$ ansible-playbook output_dicts_and_lists.yml --tags list_of_dicts

PLAY [Output content of dicts_and_lists.yml] ***********************************

TASK [Loop over some list_of_dicts] ********************************************
ok: [localhost] => (item={'first_name': 'Alice', 'last_name': 'Cooper', 'job': 'singer'}) => {
    "msg": "Firstname: Alice Lastname: Cooper"
}
ok: [localhost] => (item={'first_name': 'Bob', 'last_name': 'Marley', 'job': 'singer'}) => {
    "msg": "Firstname: Bob Lastname: Marley"
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Auch hier ist wieder an den { } zu erkennen, dass item jeweils eine Liste enthält. Der Zugriff auf die Werte geschieht durch die Referenzierung des jeweiligen Schlüssel-Namens. So ist z.B. Alice der Wert des Schlüssels first_name.

Bonusmaterial: Lists in Dicts

Jörn hat ein weiteres Beispiel beigesteuert. Da die Kommentarfunktion von WordPress den Code nicht sauber darstellt, spendiere ich Jörn eine eigene Überrschrift und baue sein Beispiel hier ein.

Jörns Datenstruktur sieht wie folgt aus:

dict_of_lists:
  - name: foo 
    elems:
      - foo one 
      - foo two 
      - foo three
  - name: bar 
    elems:
      - bar one 
      - bar two 
  - name: baz 
    elems:
      - baz one 
      - baz two 
      - baz three

Jörn möchte nun zuerst auf alle Elemente (elems) von foo zugreifen, dann auf jene von bar usw. Dazu nutzt Jörn das Lookup Plugin subelements.

Folgender Code-Block nutzt die Datenstruktur in einem Playbook, um die verschachtelten Elemente auszugeben. Aufruf und Ausgabe zeigt der darauf folgende Block.

---
- name: Lists in dicts
  hosts: localhost
  become: false
  vars:
    dict_of_lists:
      - name: foo
        elems:
          - foo one
          - foo two
          - foo three
      - name: bar
        elems:
          - bar one
          - bar two
      - name: baz
        elems:
          - baz one
          - baz two
          - baz three

  tasks:
    - name: Loop over lists in dicts
      ansible.builtin.debug:
        msg: "Name: {{ item.0.name }}, element {{ item.1 }}"
      loop: "{{ dict_of_lists | subelements('elems') }}

Und hier nun der Playbook-Aufruf mit Ausgabe:

$ ansible-playbook dict_of_lists.yml

PLAY [Lists in dicts] ************************************************************************

TASK [Gathering Facts] ************************************************************************
ok: [localhost]

TASK [Loop over lists in dicts] ************************************************************************
ok: [localhost] => (item=[{'name': 'foo', 'elems': ['foo one', 'foo two', 'foo three']}, 'foo one']) => {
    "msg": "Name: foo, element foo one"
}
ok: [localhost] => (item=[{'name': 'foo', 'elems': ['foo one', 'foo two', 'foo three']}, 'foo two']) => {
    "msg": "Name: foo, element foo two"
}
ok: [localhost] => (item=[{'name': 'foo', 'elems': ['foo one', 'foo two', 'foo three']}, 'foo three']) => {
    "msg": "Name: foo, element foo three"
}
ok: [localhost] => (item=[{'name': 'bar', 'elems': ['bar one', 'bar two']}, 'bar one']) => {
    "msg": "Name: bar, element bar one"
}
ok: [localhost] => (item=[{'name': 'bar', 'elems': ['bar one', 'bar two']}, 'bar two']) => {
    "msg": "Name: bar, element bar two"
}
ok: [localhost] => (item=[{'name': 'baz', 'elems': ['baz one', 'baz two', 'baz three']}, 'baz one']) => {
    "msg": "Name: baz, element baz one"
}
ok: [localhost] => (item=[{'name': 'baz', 'elems': ['baz one', 'baz two', 'baz three']}, 'baz two']) => {
    "msg": "Name: baz, element baz two"
}
ok: [localhost] => (item=[{'name': 'baz', 'elems': ['baz one', 'baz two', 'baz three']}, 'baz three']) => {
    "msg": "Name: baz, element baz three"
}

PLAY RECAP ************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Fazit

Das waren nun eine Menge Code-Blöcke. Mir hat es geholfen, dieses Thema noch einmal zu rekapitulieren. Listen können direkt an loop übergeben werden. Dictionaries müssen zuerst den Filter dict2items durchlaufen.

In diesem Text wurden noch nicht alle Fälle besprochen. So wurden nested lists und tiefer verschachtelte Dictionaries ausgespart, um den Artikel nicht noch mehr in die Länge zu ziehen.

Ich hoffe, der Text war auch für die Anfänger und Einsteiger unter euch hilfreich.

Internetanbindung um zweiten Anschluss erweitern

03. Juli 2023 um 05:00

Hi. Heute bin ich an euren Ideen und Empfehlungen interessiert. Wie würdet ihr folgende Aufgabe angehen?

Ist-Zustand

Das Bild zeigt eine vereinfachte Skizze des Heimnetzwerks, bestehend aus Connect Box (Router), Pi-Hole und LAN.
Vereinfachte Skizze meines Heimnetzwerks

Aktuell ist mein Heimnetzwerk über einen Unitymedia/Vodafone-Kabelanschluss mit dem Internet verbunden. Für die Verbindung zum Netz verwende ich die Unitymedia-Connect-Box. Die WLAN-Funktion und der DHCPv4-Server sind deaktiviert, da sich der Pi-Hole und ein Netgear-Orbi-System um diese Funktionen kümmern.

Dieses Setup hat einen Nachteil. Das Router Advertisement der Connect Box lässt sich nicht deaktivieren und nicht weiter konfigurieren. Mit diesem werden die DNS-Server des Internet Service Provider (ISP) im LAN announced. Diese werden von den Clients mit einer höheren Priorität genutzt als der Pi-Hole, was dessen Einsatz ad absurdum führte. Um dieses Problem zu mitigieren, habe ich die DHCPv6 Adressvergabe der Connect Box auf das Minimum von 1 Adresse reduziert. Damit entfaltet der Pi-Hole seine Wirkung und wir bleiben von Werbung weitestgehend verschont. Da die Clients im LAN nun jedoch keine IPv6-Adressen mit Scope Global besitzen, lassen sich Hosts im Internet, welche nur über IPv6 erreichbar sind, nicht ansprechen.

Es kommt ein Glasfaseranschluss hinzu

Voraussichtlich gegen Ende diesen Jahres kommt ein Glasfaseranschluss des Anbieters Sewikom hinzu. Dieser wird bis in den Keller gelegt und endet im sogenannten Hausübergabepunkt (HÜP). An den HÜP wird ein eigener Router via Kupfer-Patch-Kabel angeschlossen.

Der Router ist noch nicht vorhanden und muss von mir gekauft werden.

Gewünschtes Zielszenario

Ich möchte zukünftig beide Anschlüsse parallel nutzen können. Entweder in einer Active-Standby-Konfiguration oder Active-Active-Konfiguration. In letzten Fall wäre auch eine Möglichkeit charmant, in der ich konfigurieren kann, welche Clients welchen WAN-Anschluss bevorzugt nutzen sollen. Fällt ein Anschluss aus, sollen alle Geräte den verbliebenen Anschluss nutzen können.

Damit der Router nicht zum Single-Point-of-Failure wird, möchte ich für diesen ein Cold-Standby-Gerät vorhalten, da Hardware mit Hot-Standby-Unterstützung für das Heimnetzwerk vermutlich übertrieben teuer wird.

Bei der Lösung muss berücksichtigt werden, dass ich auch zukünftig nicht auf DNS-Filterlisten verzichten möchte. Ob diese Funktionalität vom Pi-Hole oder von einer integrierten Router-/Firewall-Lösung bereitgestellt wird, ist jedoch zweitrangig.

Vermutlich bietet es sich an, ein Netzwerkgerät zu verwenden, welches neben der Gateway-/Routing-Funktionalität auch eine Firewall bietet, die den Verkehr zwischen verschiedenen Netzwerkzonen steuern kann.

Wie habt ihr das gelöst?

An dieser Stelle kommt ihr ins Spiel. Wer von euch betreibt bereits ein solches Szenario mit zwei Internetanschlüssen (Glasfaser und Kabel) und wie habt ihr das gelöst?

Welche Hardware verwendet ihr? Warum habt ihr euch für diese entschieden und wovon würdet ihr aus Erfahrung abraten?

Bitte schreibt mir eure Antworten in die Kommentare, per E-Mail oder in den Chat (#my-it-brain:matrix.org).

RHEL System Roles: storage

19. Juni 2023 um 05:00

Willkommen zu Teil 6 meiner losen Reihe über die RHEL System Roles. In diesem Teil stelle ich euch die Rolle storage vor, mit welcher sich unpartitionierte Laufwerke und LVM-Volumes verwalten lassen.

Zuerst stelle ich meinen Anwendungsfall vor. Anschließend beschreibe ich, wie ich diesen mithilfe der RHEL System Role storage löse.

Während mir dieser Artikel zur Dokumentation dient, soll er euch den Einsatz von RHEL System Roles verdeutlichen.

Hinweis: Zum Zeitpunkt der Erstellung dieses Artikels unterstützt die Rolle die LVM-Konfiguration lediglich auf unpartitionierten Laufwerken, welche komplett als Physical Volume (PV) genutzt werden.

Wer sich an dieser Stelle fragt, was RHEL System Roles sind, wie man sie installiert und nutzt, dem empfehle ich am Anfang zu beginnen: Vorstellung der Red Hat Enterprise Linux (RHEL) System Roles.

Anwendungsfall

Mit der Ansible-Rolle kvm_provision_lab (siehe [1,2]) provisioniere ich virtuelle Maschinen (VM) auf KVM/QEMU-Hypervisoren. In „Labor-Umgebung mit Ansible in KVM erstellen“ habe ich die Anwendung dieser Rolle bereits detailliert beschrieben. Eine VM wird darin als ein YAML-Dictionary nach folgendem Muster definiert:

test-vm1:
    vm_ram_mb: 512
    vm_vcpus: 1
    vm_iftype: network
    vm_net: default
    os_type: rhel9
    file_type: qcow2
    base_image_name: rhel9-template
    vm_template: "rhel9-template"
    second_hdd: true
    second_hdd_size: "2G"

Das Beispiel im Code-Block provisioniert eine VM mit einem zweiten Blocklaufwerk. Dieses wird in der VM als /dev/vdb konfigruiert.

Um das zweite Laufwerk nutzen zu können, müssen zuerst eine Partitionstabelle und eine Partition erstellt und diese mit einem Dateisystem formatiert werden. Alternativ kann das Gerät auch für LVM verwendet werden.

Ich möchte aus /dev/vdb ein PV für LVM machen, um es einer Volume Group (VG) vg_data hinzuzufügen und ein Logical Volume (LV) zu erstellen, welches die gesamte Speicherkapazität von /dev/vdb nutzt.

Die Rolle

Durch die Installation des Pakets rhel-system-roles existiert diese Rolle storage bereits auf meinem System und muss nur noch konfiguriert werden. Die Rolle selbst findet man im Pfad /usr/share/ansible/roles/rhel-system-roles.stroage/ und die Dokumentation in /usr/share/doc/rhel-system-roles/storage/README.md. Aus letzterer stammt auch folgendes Beispiel:

Example Playbook
----------------

```yaml
- hosts: all

  roles:
    - name: rhel-system-roles.storage
      storage_pools:
        - name: app
          disks:
            - sdb
            - sdc
          volumes:
            - name: shared
              size: "100 GiB"
              mount_point: "/mnt/app/shared"
              #fs_type: xfs
              state: present
            - name: users
              size: "400g"
              fs_type: ext4
              mount_point: "/mnt/app/users"
      storage_volumes:
        - name: images
          type: disk
          disks: ["mpathc"]
          mount_point: /opt/images
          fs_label: images

```

Da ich auf /dev/vdb ein LVM konfigurieren möchte, kopiere ich mir das Dictionary storage_pools aus obigen Beispiel und passe es für mein Playbook an.

Das Playbook

---
- hosts: test-vm1

  roles:
    - name: rhel-system-roles.storage
      storage_pools:
        - name: vg_data
          disks:
            - vdb
          volumes:
            - name: data1
              size: "2 GiB"
              mount_point: "/mnt"
              fs_type: ext4
              state: present

Obiges Playbook führt folgende Schritte auf dem Host test-vm1 durch:

  1. Das Blockgerät /dev/vdb wird als PV für LVM konfiguriert.
  2. Es wird die Volume Group (VG) vg_data auf dem PV /dev/vdb erstellt.
  3. In der VG vg_data wird das LV data1 erstellt.
  4. Das LV wird mit dem Dateisystem Ext4 formatiert.
  5. Das LV wird unterhalb von /mnt eingehängt.

Innerhalb des Gast-Betriebssystems lässt sich mit folgenden Kommandos prüfen, dass die Konfiguration wie gewünscht durchgeführt wurde.

[root@test-vm1 ~]# lsblk vdb
lsblk: vdb: not a block device
[root@test-vm1 ~]# lsblk /dev/vdb
NAME            MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vdb             252:16   0   2G  0 disk 
└─vg_data-data1 253:0    0   2G  0 lvm  /mnt
[root@test-vm1 ~]# pvs
  PV         VG      Fmt  Attr PSize  PFree
  /dev/vdb   vg_data lvm2 a--  <2.00g    0 
[root@test-vm1 ~]# vgs
  VG      #PV #LV #SN Attr   VSize  VFree
  vg_data   1   1   0 wz--n- <2.00g    0 
[root@test-vm1 ~]# lvs
  LV    VG      Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  data1 vg_data -wi-ao---- <2.00g                                                    
[root@test-vm1 ~]# mount | grep mnt
/dev/mapper/vg_data-data1 on /mnt type ext4 (rw,relatime,seclabel)
[root@test-vm1 ~]# echo "Hallo Welt!" >/mnt/world.txt
[root@test-vm1 ~]# cat /mnt/world.txt
Hallo Welt!

Fazit

Der betrachtete Anwendungsfall lässt sich mit der vorgestellten Ansible-Rolle schnell und einfach umsetzen. Man deklariert lediglich die Wunschkonfiguration im Ansible-Playbook und die Rolle kümmert sich um den Rest, wie die Installation der notwendigen Pakete auf den Zielsystemen.

Unterstützt werden als Zielsysteme aktuell EL 7-9 sowie Fedora. Damit ist sie für die Anwendung auf Debian bzw. darauf basierende Systeme nicht geeignet. Wie man auch für diese Systeme ein einfaches Playbook entwirft, um LVM für Blockgeräte zu konfigurieren, werde ich in einem folgenden Artikel zeigen.

Ich hoffe, dass euch auch die Vorstellung dieser Rolle gefallen hat und wünsche euch viel Spaß bei der Nutzung der RHEL System Roles.

Quellen und weiterführende Links

  1. https://galaxy.ansible.com/Tronde/kvm_provision_lab
  2. https://github.com/Tronde/kvm_provision_lab
  3. https://github.com/linux-system-roles/storage
  4. Vorstellung der Red Hat Enterprise Linux (RHEL) System Roles
  5. RHEL System Roles: selinux
  6. RHEL System Roles: timesync
  7. RHEL System Roles: sshd
  8. RHEL System Roles: firewall

Utilize PowerCLI to resize VMDK files of multiple VMs

13. Juni 2023 um 19:20

This is the translated version of an article written in German originally. I translated it as a non-German speaking person has shown interest in the topic.

Disclaimer: This tutorial comes without warranty and support. Use at your own risk.

In this tutorial, I would like to show a minimal example on how selected VMDK files of specific VMs can be resized with using the PowerCLI.

This is useful, for example, when so many VMs are affected that the time and effort required to manually enlarge them via the vSphere (web) client seems too great.

Only the resizing of the VMDK file is considered here. The subsequent resizing of the partition and file system within the guest operating system, which is also necessary, is not part of this tutorial.

Goal

For a minimal example, from a group of VMs the second and third hard disk of VM-Test-5 and VM-Test-6 are to be enlarged. The respective second hard disk is to be enlarged from 250 GB to 500 GB and the respective third hard disk is to be enlarged from 400 GB to 800 GB.

Requirements

A working installation of the VMware PowerCLI and the ability to access the vCenter Server is a prerequisite to follow this tutorial.

Here we go

The following code block shows how the necessary information about the VMs is read out to be processed.

PowerCLI C:\Scripts> Get-VM | Where-Object {$_ | Select-String -pattern "VM-Test-\d"}

Name                 PowerState Num CPUs MemoryGB
----                 ---------- -------- --------
VM-Test-5        PoweredOn  4        24.000
VM-Test-7        PoweredOn  4        16.000
VM-Test-6        PoweredOn  4        24.000


PowerCLI C:\Scripts> Get-VM | Where-Object {$_ | Select-String -pattern "VM-Test-[5,6]{1}"}

Name                 PowerState Num CPUs MemoryGB
----                 ---------- -------- --------
VM-Test-5        PoweredOn  4        24.000
VM-Test-6        PoweredOn  4        24.000


PowerCLI C:\Scripts> $VM = Get-VM | Where-Object {$_ | Select-String -pattern "VM-Test-[5,6]{1}"}
PowerCLI C:\Scripts> Get-VM $VM | Get-HardDisk | FT Parent, Name, CapacityGB -AutoSize

Parent        Name        CapacityGB
------        ----        ----------
VM-Test-5 Hard disk 1         40
VM-Test-5 Hard disk 2        250
VM-Test-5 Hard disk 3        400
VM-Test-5 Hard disk 4         80
VM-Test-6 Hard disk 1         40
VM-Test-6 Hard disk 2        250
VM-Test-6 Hard disk 3        400
VM-Test-6 Hard disk 4         80

From the above output you can see that we want to enlarge the VMDK files which are called „Hard disk 2“ and „Hard disk 3“ respectively.

In the code block that follows, I first define a few variables, then double check that I am selecting the correct VMDK files for the operation, and then I resize them.

PowerCLI C:\Scripts> $HardDisk = 2
PowerCLI C:\Scripts> $HardDisk = "Hard disk " + $HardDisk
PowerCLI C:\Scripts> $HardDiskSize = 500
PowerCLI C:\Scripts> Get-HardDisk -vm $VM | where {$_.Name -eq $HardDisk}

CapacityGB      Persistence                                              Filename
----------      -----------                                                    --------
250.000         IndependentPersis... ...STD-2.9T-02] VM-Test-5/VM-Test-5_1.vmdk
250.000         IndependentPersis... ...STD-2.9T-01] VM-Test-6/VM-Test-6_1.vmdk


PowerCLI C:\Scripts> Get-HardDisk -vm $VM | where {$_.Name -eq $HardDisk} | Set-HardDisk -CapacityGB $HardDiskSize -Conf
irm:$false

CapacityGB      Persistence                                                    Filename
----------      -----------                                                    --------
500.000         IndependentPersis... ...STD-2.9T-02] VM-Test-5/VM-Test-5_1.vmdk
500.000         IndependentPersis... ...STD-2.9T-01] VM-Test-6/VM-Test-6_1.vmdk


PowerCLI C:\Scripts> Get-VM $VM | Get-HardDisk | FT Parent, Name, CapacityGB -AutoSize

Parent        Name        CapacityGB
------        ----        ----------
VM-Test-5 Hard disk 1         40
VM-Test-5 Hard disk 2        500
VM-Test-5 Hard disk 3        400
VM-Test-5 Hard disk 4         80
VM-Test-6 Hard disk 1         40
VM-Test-6 Hard disk 2        500
VM-Test-6 Hard disk 3        400
VM-Test-6 Hard disk 4         80


PowerCLI C:\Scripts> $HardDisk = 3
PowerCLI C:\Scripts> $HardDisk = "Hard disk " + $HardDisk
PowerCLI C:\Scripts> $HardDiskSize = 800
PowerCLI C:\Scripts> Get-HardDisk -vm $VM | where {$_.Name -eq $HardDisk}

CapacityGB      Persistence                                                    Filename
----------      -----------                                                    --------
400.000         IndependentPersis... ...STD-2.9T-02] VM-Test-5/VM-Test-5_2.vmdk
400.000         IndependentPersis... ...STD-2.9T-01] VM-Test-6/VM-Test-6_2.vmdk


PowerCLI C:\Scripts> Get-HardDisk -vm $VM | where {$_.Name -eq $HardDisk} | Set-HardDisk -CapacityGB $HardDiskSize -Conf
irm:$false

CapacityGB      Persistence                                                    Filename
----------      -----------                                                    --------
800.000         IndependentPersis... ...STD-2.9T-02] VM-Test-5/VM-Test-5_2.vmdk
800.000         IndependentPersis... ...STD-2.9T-01] VM-Test-6/VM-Test-6_2.vmdk


PowerCLI C:\Scripts>

If the above code block is not self-explanatory, feel free to post your questions about it in the comments. I’ll try to complete the tutorial in a timely manner.

WP fail2ban: Gutes Plugin mit ausbaufähiger Dokumentation

12. Juni 2023 um 05:00

WP fail2ban ist ein Plugin zum Schutz von WordPress-Installationen vor Brute-Force-Angriffen. Installation und Konfiguration habe ich bereits im Artikel WordPress mit Fail2Ban vor Brute-Force-Angriffen schützen dokumentiert. Dieser Text beschäftigt sich mit der offiziellen Dokumentation des Plugins, bzw. dem Text, der sich als Dokumentation ausgibt.

Ich stelle hier meine Erwartung an eine Dokumentation heraus, zeige die Schwächen der exemplarisch ausgewählten Dokumentation heraus und gebe einen Tipp, wie man weniger schlechte Dokus schreibt. Ich schließe mit Fragen an meine Leserinnen und Leser und freue mich auf eure Rückmeldungen.

In meinen Augen sind folgende drei Abschnitte zwingender Bestandteil einer jeden Dokumentation:

  1. Was ist dies für eine Anwendung? Wofür wird sie verwendet und wofür nicht?
  2. Wie wird diese Anwendung installiert?
  3. Wie wird diese Anwendung konfiguriert?

Die ersten beiden Punkte mag ich als erfüllt betrachten. Beim dritten Punkt sehe ich ein Problem.

Bildschirmfoto der WP fail2ban-Installationsanleitung. Zeitstempel 2023-06-04T20:54+02

Die Installationsanleitung ist prägnant. Sie enthält einen Link, der suggeriert, zur Konfigurationsanleitung zu führen. Dort erwartet den neugierigen Leser folgendes Bild.

Bildschirmfoto vom Einstieg in die WB fail2ban-Konfigurationsanleitung. Zeitstempel 2023-06-04T20:59+02

Hier gibt es noch keine nützlichen Informationen zu sehen. Die Seite ist in meinen Augen überflüssig. Aber gut, ein Satz tut nicht weh. Mit einem Klick auf „Next“ geht es weiter.

Bildschirmfoto WP fail2ban-Dokumentation. Zeitstempel 2023-06-04T21:04+02

Hier steht im Wesentlichen, dass Nutzer, welche sich bereits auskennen, zum nächsten Abschnitt gehen können. Leider finden sich für neue Nutzer hier kaum brauchbare Informationen. Der Hinweis, die Datei wp-config.php zu sichern, bevor man diese bearbeitet, ist nett, mehr nicht. Es wird erwähnt, dass die freie (im Sinne von Freibier) Version des Plugins durch Definition von Konstanten in der Datei wp-config.php konfiguriert wird. Wie so eine Konstante aussieht oder wo man weiterführende Informationen dazu findet, steht hier nicht. Ich habe an dieser Stelle entsprechende Hinweise erwartet. Gut, ich kann ja noch auf „Next“ klicken.

Bildschirmfoto WP fail2ban-Dokumentation, Abschnitt Logging. Zeitstempel 2023-06-04T21:14+02

Auch in diesem Abschnitt findet sich keine Information, was man nun mit der Datei wp-config.php soll. Immerhin gibt es in Abschnitt 4.2.1. einen Link, der Nutzer, welche nicht mit der Konfiguration vertraut sind, zur Konfigurationsanleitung führen soll. Ich habe ein Déja Vu und fühle mich langsam ver…hohnepiepelt. Also klicke ich auf den nächsten LInk. Es heißt ja schließlich: „Was lange währt, wird endlich gut.“

TL;DR: Auch auf der nächsten Seite erfahren wir nichts über die wp-config.php.

Bildschirmfoto der URL: https://docs.wp-fail2ban.com/en/5.0/configuration/fail2ban.html#configuration-fail2ban. Zeitstempel 2023-06-04T21:21+02

Zur Erinnerung: Ich nutze die freie Version des Plugins WP fail2ban, welches angeblich durch die Definition von Konstanten in der Datei wp-config.php konfiguriert wird. Welche Konstanten dies sind und wie man diese konfiguriert, wird auch auf Seite 4 immer noch nicht mit einem Wort erklärt.

Stattdessen lernt man in Abschnitt „4.3.1.1. Typical Settings“, dass die Dateien wordpress-hard.conf und wordpress-soft.conf in das Verzeichnis fail2ban/filters.d zu kopieren sind. Hier wurden in meinen Augen zwei Fehler gemacht:

  1. Es wird nicht erwähnt, wie man die Dateien wordpress-,{hard,soft}.conf erhält bzw. erstellt. Als unerfahrener Nutzer strandet man hier. Zum Glück hatte ich mir das damals aufgeschrieben.
  2. Es wird eine relative Pfadangabe fail2ban/filters.d genutzt. Dies ist nicht ganz so wild, ich persönlich bevorzuge es, wenn vollständige Pfadangaben genutzt werden, damit Nutzer das entsprechende Verzeichnis sicher finden.

Fazit

Eine Dokumentation sollte die notwendigen Informationen bereitstellen, mit denen auch neue Nutzer eine Anwendung installieren und konfigurieren können. Dies ist nicht so leicht, wie es auf den ersten Blick erscheint, leiden Autoren, welche die Anwendung bereits kennen, doch häufig unter Betriebsblindheit und können sich nur schwer in die Rolle des unerfahrenen Nutzers versetzen.

Wenn ich selbst Dokumentationen schreibe, gebe ich diese meist Kolleginnen und Kollegen zu lesen und arbeite deren Rückmeldungen mit ein. Dies hat in der Vergangenheit zu deutlich besseren Ergebnissen geführt.

Die hier kritisierte Dokumentation ist ein Beispiel dafür. Sie befindet sich damit leider in guter Gesellschaft im Internet.

Ohne meinen Eingangs erwähnten Artikel hier im Blog wäre ich nicht in der Lage gewesen, mir dieses Plugin wieder einzurichten. Nun werde ich einige Tage prüfen, ob es wie erhofft arbeitet und dann ggf. einen Merge-Request mit einigen Verbesserungsvorschlägen einreichen.

Fragen an meine Leserinnen und Leser

Wie steht ihr zu Dokumentation? Ist das eher etwas für alte weiße Männer mit grauen Bärten? Oder wünscht ihr euch ebenfalls belastbare und ausführliche Dokumentationen zu den von euch verwendeten Anwendungen?

Tragt ihr selbst zu Dokumentationen bei? Welche Erfahrungen habt ihr dabei gemacht? Welche Tipps könnt ihr Schreiberlingen geben, die ihr Projekt dokumentieren möchten?

Bitte hinterlasst mir eure Antworten in den Kommentaren oder im Chat.

Rollen müssen verfügbar sein, nicht einzelne Personen.

05. Juni 2023 um 05:00

In diesem Artikel möchte ich euch ein Modell vorstellen, nach dem sich Wissen auf verschiedene Personen verteilen lässt, um dieses Wissen und die Funktion von Rollen in einem Unternehmen verfügbar zu halten.

Bei den Rollen kann es sich zum Beispiel um den Virtualisierungs-Administrator, den Linux-Admin oder die Rechnungseingangsprüfung sowie den Versand handeln. Die jeweilige Rolle kann dabei von ein oder mehreren Personen ausgefüllt werden. Wichtig ist lediglich, dass die Rolle jederzeit ihre Funktion erfüllen kann.

Das Modell, welches ich gleich vorstelle, stammt nicht von mir. Ein Nerd aus den USA, dessen Namen ich leider nicht mehr weiß, hat es mir am Rande des OpenStack Summit 2018 in Berlin vorgestellt.

RAID – Redundant Array of Independent Dudes

Ja, ihr habt richtig gelesen. Es geht um RAID, aber ohne Festplatten und dafür mit Dudes oder allgemein Personen, die Rollen ausfüllen. Ihr werdet in den folgenden Abschnitten lernen, wie sich die verschiedenen RAID-Level auf die Verfügbarkeit einer Rolle auswirken.

RAID 0 – Nur gemeinsam sind wir stark

Das Bild zeigt zwei Personen, die jeweils zwei Aufgaben wahrnehmen. Die beiden Personen haben nichts weiter miteinander zu tun. Es findet kein Wissensaustausch zwischen ihnen statt.
Zwei Personen nehmen unabhängig voneinander verschiedene Aufgaben wahr.

Dieses Konstrukt habe ich zum Glück noch nicht in der Praxis angetroffen. Hierbei wird eine Rolle von zwei Personen ausgefüllt, welche die Funktion der Rolle jedoch nur im Team sicherstellen können. Fällt eine Person aus, ist die andere allein nicht ausreichend handlungsfähig. Die Funktion der Rolle ist nicht sichergestellt.

RAID 1 – Zwei Personen für eine Rolle

Hier herrscht volle Redundanz. Zwei Personen sind für eine Rolle verantwortlich. Fällt eine Person aus, kann die andere sämtliche damit zusammenhängende Aufgaben allein ausführen. Die Vertretung ist im Falle von Krankheit, Urlaub oder Knast damit zu 100 % sichergestellt.

Gleichzeitig ist der Abstimmungsbedarf minimal, da sich nur zwei Personen miteinander abstimmen müssen.

Das Bild zeigt vier Personen. Jeweils zwei Personen nehmen die gleichen Aufgaben wahr. Pfeile symbolisieren den Informationsfluss zwischen den Personen.
Jeweils zwei Personen stimmen sich miteinander ab, um sich gegenseitig vertreten zu können (RAID 1).

Wenn es gut läuft und man bei der Personal-Akquise ein glückliches Händchen hat, lassen sich vielleicht sogar zwei Personen kombinieren, die zwei oder vielleicht sogar drei Rollen in Personalunion besetzen können.

Zu beachten ist, dass die Leistungsfähigkeit der Rolle beeinträchtigt sein mag, wenn 50 % der normalen Kapazität fehlen. Dies ist von der regelmäßigen Belastung bzw. Auslastung der einzelnen Personen abhängig.

RAID 5 – Parität und Leistung mit erhöhtem Abstimmungsbedarf

Das insgesamt erforderliche Wissen ist in diesem RAID-Level auf mindestens drei oder mehr Personen verteilt. Keine Person verfügt für sich allein über genug Wissen, um eine Rolle vollständig ausfüllen zu können. In der Gesamtheit ist das Wissen jedoch so verteilt, dass bei Ausfall einer Person (Krankheit, Urlaub, Knast, etc.) kein Wissen unwiederbringlich verloren geht, sondern der Verlust durch die verbliebenen Personen aufgefangen werden kann. Dies bezieht sich nicht nur auf das Wissen, sondern auch auf die zu erbringende Leistung.

Das Bild zeigt sechs Personen, von denen jeweils drei die gleichen Aufgaben wahrnehmen. Pfeile unterschiedlicher Farbe zeigen, welche Personen dabei in einer Kommunikationsbeziehung zueinander stehen.
Zwei Teams bestehend aus jeweils drei Personen. Jedes Team stimmt sich zu seinen Aufgaben ab. Es handelt sich quasi um zwei separate RAID-5-Verbünde.

Da jede Person nun mehr als eine Kollegin oder einen Kollegen hat, wird der Abstimmungsbedarf größer. Die einzelnen Personen müssen sich auf dem Laufenden halten, was die Kollegen so tun, um diese bei Bedarf vertreten zu können.

Hat jede Person in diesem RAID-Verbund nur die eine Rolle, für die dieses RAID gebildet wurde, ist das kein Problem. Man hat einfach ein größeres Team, das seinen Job macht. Das funktioniert auch noch, wenn alle in diesem Team/RAID noch eine zweite oder vielleicht auch dritte Rolle ausfüllen. Denn es bleiben dieselben beteiligten Personen, die sich untereinander austauschen können und müssen.

RAID 55 – Wie konnte das passieren?

Ein Bild sagt auf mehr als viele Worte:

Das Bild zeigt sechs Personen, von denen jede zwei Rollen ausfüllt. Jede Rolle ist dreimal im Bild vorhanden. Pfeile verbinden die Personen, die die gleiche Rolle ausfüllen, um darzustellen, wie unübersichtlich es bei ungünstiger Aufgabenverteilung wird.
RAID 55 – Wenn die Aufgabenverteilung unübersichtlich wird

In vorstehendem Bild werden die gleichen Aufgaben durch die gleiche Anzahl von Personen wahrgenommen. Allerdings sind in diesem Bild die Rollen ungeschickt zwischen den Personen verteilt, was einen hohen Kommunikationsaufwand zur Folge hat, da sich mehr Personen zu mehr Themen miteinander abstimmen müssen.

Hinzukommt, dass die Urlaubsplanung in diesem unübersichtlichen Szenario ebenfalls erschwert wird, muss doch darauf geachtet werden, dass die Funktionen der einzelnen Rollen verfügbar bleiben und man nicht versehentlich zwei von drei Personen in den Urlaub schickt, welche die gleiche Rolle ausfüllen und von denen mindestens zwei Personen verfügbar sein müssen.

Leider habe ich dieses Bild in der Praxis schon mehr als einmal gesehen. Es entsteht immer dann, wenn Teams immer weitere Themen übernehmen müssen und man versucht, eine Aufgabe auf immer mehr vorhandene Köpfe zu verteilen, weil gerade jemand da ist, der noch 10 Minuten freie Zeit pro Woche hat.

Dabei mag man sich ausmalen, wie das vorstehende Bild sich verändert, wenn die Anzahl der Personen und Aufgaben unter Beibehaltung der ungeschickten Aufgabenverteilung steigt. Ein Modell, das es in meinen Augen zu verhindern lohnt.

Zusammenfassung

Ich mag RAIDs, da sich mit ihnen auf einfache Weise die Komplexität von Aufgaben-, Arbeitslast-Verteilung und Kommunikations- und Abstimmungs-Aufwände visualisieren und erklären lassen.

Wie gefällt euch das Modell? Habt ihr ähnliche oder ganz andere Erfahrungen in vergleichbaren Team-Strukturen gemacht?

❌
❌