Hadmut Danisch

Ansichten eines Informatikers

Die kaputtzerteilhabte Softwarelandschaft

Hadmut
8.11.2021 16:18

Es geht mir so auf die Nerven…

Ich muss leider feststellen, dass ich mit einem Sofwareprojekt kaum vorankomme, weil ich seit Wochen und Monaten vorrangig damit beschäftigt bin, irgendwelche Probleme und Bugs zu jagen und mich mit sonstwas allem rumzuschlagen, was nicht funktioniert oder worum sich keiner kümmert, Bug Reports aufzumachen und ewig zu warten.

Ich will mal drei, vier Beispiele symptomatisch herausgreifen, die zeigen, wie man nicht mehr vorankommt, sondern nur noch seine Zeit vergeigt.

Puppet

Ich schimpfe ja gerne darauf, dass Behörden, Universitäten und ähnliches nach einem Hackerangriff oft Monate oder über ein Jahr brauchen, um ihren IT-Krempel wieder hochzukriegen.

Im professionellen Bereich installiert man Server und Dienste eigentlich gar nicht mehr von Hand, sondern über automatisierte Installationssysteme, in denen man beschreibt, was wie und wo zu installieren ist, und die das dann machen.

Das hat sehr viele Vorteile.

Es ist beliebig reproduzierbar. Man kann nicht nur die Installation selbst testen, sondern auch das, was man damit produziert, beliebig oft reproduzieren und als Testsystem verwenden. Man vergisst dabei nichts, wenn man es wiederholt und muss ich überlegen, verdammt, wie habe ich das damals gemacht.

Man hat es damit auch automatisch dokumentiert. Denn wenn man dem Konfigurationssystem aufgeschrieben hat, wie das System zu bauen ist, und das dann da herauskommt, steht zwangsläufig alles, was dazu führte, in dieser Beschreibung.

Man hat es beschleunigt, weil die Automatisierung natürlich viel schneller abläuft als eine Installation von Hand.

Man kann damit beliebig viele parametrisierte Maschinen erzeugen. Hat man beispielsweise eine Schulsoftware, und die Installation entsprechend parametrisiert, kann man dasselbe für die X-Schule, die Y-Schule, die Z-Schule laufen lassen und so weiter.

Man kann damit viel Geld sparen, weil man nicht nur Arbeitszeit spart, sondern auch Systeme – vor allem in der Cloud – nicht mehr ständig vorhalten muss, sondern nur noch bei Bedarf installiert und hinterher löscht. Weil nicht mehr der Zustand des Systems selbst die Dokumentation ist.

Man kann viel schneller auf Sicherheitseinschläge reagieren, weil man eben nicht mehr das heilige System hat, das man irgendwie retten, reparieren und am Laufen halten muss, weil keine Sau mehr weiß, wie man es installiert hatte, sondern wird dadurch in die Lage versetzt, ein kompromittiertes System jederzeit einfach löschen, wegschmeißen und komplett neu erzeugen lassen zu können. Günstigerweise natürlich, nachdem es einen Patch oder Hinweis gibt, wie man die Wiederholung des Angriffs verhindern kann.

Es gibt sogar Techniken und Methoden, diese Softwareinstallation sowohl bei virtuellen Maschinen, auch in der Cloud, als auch auf richtiger Hardware vollautomatisch anzuschmeißen. Wenn man das ordentlich macht, muss man dann, wenn man die Maschine braucht, gar nichts mehr tun. Man stöpselt die neue Hardware an oder bestellt eine virtuelle Maschine in der Cloud, und schwupsdiwups fällt nach ein paar Minuten die fertig durchinstallierte und betriebsbereite Maschine heraus.

Das ist übrigens einer der Gründe, warum ich für das Theater an Gerichten, Ämtern und Universitäten um den Wiederaufbau der Infrastruktur nach Hackerangriff so wenig Verständnis habe. In einem professionellen Umfeld würde man einfach sagen, alles wegschmeißen und sofort neu erzeugen.

Nun gibt es da viele Tools, die da ähnliche Aufgaben lösen. Ich habe bisher Puppet und Ansible benutzt. Chef kenne ich nur vom Hörensagen. Saltstack kenne ich gar nicht. Gibt inzwischen auch noch andere Ansätze wie Docker/Kubernetes. Ohne solche Tools könnte ich schon meine eigenen Rechner seit Jahren nicht mehr auf dem gleichen Stand halten und hätte längst den Überblick über alle Software und deren Besonderheiten und Installationstricks verloren. So habe ich das alles schön beisammen. Und obwohl meine Softwareinstallation inzwischen ziemlich riesig ist, muss ich auf einem neuen Rechner nur das Linux installieren und Puppet laufen lassen – fertig. Manuell wäre ich tagelang damit beschäftigt und würde nie alles und alles fehlerfrei hinkriegen.

Ansible ist nett, wenn es um kleine, isolierte Aufgaben geht und Abläufe, die man nur einmal laufen lässt. Und hat bessere Anpassungen an Standardsoftwareprodukte.

Puppet dagegen ist bei großen, komplexen Aufgaben deutlich schneller und leistungsfähiger, braucht aber client und server.

Aber, ach.

Bei vielen Linuxdistributionen ist noch Puppet 5 dabei, das aber nicht mehr supported wird und deshalb veraltet ist. Die Firma hinter Puppet, die Puppet Labs, arbeitet an Puppet 6 und Puppet 7.

Um meine Kenntnisse zu aktualisieren und keine veraltete Software zu verwenden, habe ich neulich angefangen, ein Projekt mit Puppet 7 zu bauen. (Für Insider: Puppet 5 war noch beidseitig in Ruby geschrieben, das fanden sie aber zu langsam. Puppet 6 wurde dann serverseitig auf JRuby mit der JVM portiert, und bei Puppet 7 haben sie angefangen, Kernfunktionen in einer JVM-Sprache zu schreiben. Ich glaube, es war Clojure oder sowas.)

Mir fiel da beim Bauen eine schwerwiegende Fehlfunktion auf, die es bei Puppet 5 noch nicht gab. Ich habe nämlich meine alten Kochrezepte verwendet. Ein Beispiel, an dem ich das bemerkt habe:

  1. Ich installiere den ssh-Server als Paket.
  2. Ich konfiguriere den ssh-Server, indem ich die Konfigurationsdatei anpasse. Dabei bügle ich nicht einfach eine neue Datei über, sondern setze in der mitgelieferten Datei nur die wichtigen Variablen per augeas auf die wichtigen Werte, damit Neuerungen in neuen Konfigurationsdateien nicht weggebügelt werden. Also beispielsweise die Authentifikation per Passwort abzuschalten.
  3. Dann starte ich den ssh-Server neu, damit er mit dieser Konfiguration läuft.

Funktionierte so seit Jahren, bis einschließlich Puppet 5.

Hier aber wurde der zweite Schritt übersprungen, und das ohne jeglichen Kommentar, ohne jede Meldung. Der ssh-Server wurde aktiviert, aber nicht konfiguriert. Stand also mit eingeschalteter Passwortauthentifikation da. War nur ein Testsystem und noch nicht im Internet, aber ich habe es gemerkt. Und natürlich untersucht. Hat mich viel Zeit gekostet. Der Server liefert die Anweisungen richtig an den Client, aber der Client kann augeas nicht aufrufen, weil die Pfade im client nicht stimmen und er eine Ruby-Bibliothek nicht findet. Statt aber eine Fehlermeldung auszugeben oder zu warnen, tut das Ding stillschweigend so, als wäre alles durchgelaufen.

Sowas ist natürlich kapital gefährlich, wenn Dienste eingeschaltet werden, die nicht so konfiguriert sind, wie man das wollte, und ähnliche Probleme.

Also habe ich am 18. August einen Bug-Report aufgemacht und als sicherheitsrelevant (deshalb nicht öffentlich sichtbar) und dringend gekennzeichnet.

Sie haben auch recht schnell reagiert, das geprüft und den Bug bestätigt.

Da dachte ich schon, ich falle vom Stuhl. Steht drin, sie hätten die Ursache auch gleich gefunden und festgestellt, den Bug bei Puppet 6 und 7 schon sehr, sehr lange drin, aber nicht bemerkt zu haben.

Wie, bitte!?

Das Ding führt zentrale Funktionen schon seit längerer Zeit nicht aus, und die merken es selbst nicht?

Na, gut, dachte ich, jetzt wissen sie es ja und sagen, sie hätten die Ursache erkannt und würden mit Hochdruck dran arbeiten.

Zumal sie ja, das ist heute ganz hip, „agil“ sind und mit Scrum arbeiten.

Der Bug-Report ist inzwischen fast drei Monate alt. Ich war inzwischen zweimal im Ausland.

Ab und zu kommt mal ein Update, dass sie was gefixt hätten. Der Fehler liege im Client. Ab der Version 7.12.1 sei es gefixt.

Wochen nach dem Bug-Report hat die öffentlich verfügbare Ruby-Gem zu puppet gerade mal den Sprung von 7.11.0 auf 7.12.0 geschafft, wobei nicht mal klar ist, welches ihrer GIT-Repositories überhaupt das relevante ist.

Aber ein zentrales Sicherheits- und Funktionsproblem, das nicht nur eine Nebensache ist, sondern das ganze Ding zum Problem macht, habe sie immer noch nicht hinbekommen:

gem search --remote -e puppet

*** REMOTE GEMS ***

puppet (7.12.0 ruby universal-darwin x64-mingw32 x86-mingw32)

Es ist mir einfach schleierhaft, was da abläuft. Einen solchen Bug hätte ich im Eilverfahren mit höchster Priorität fixen lassen. Es hätte eigentlich auch gar nicht vorkommen dürfen, dass der Bug so lange existierte und unerkannt bleiben konnte.

Network Manager und IPv6

Schon vor längerer Zeit, ich weiß nicht mal mehr, wann, ich glaube so kurz nach Ubuntu 20.04, ist mir aufgefallen, dass im Netzwerk bei mir was nicht stimmt. Verbindungen von host zu host waren manchmal signifikant zu langsam.

Irgendwann habe ich mir mal die Zeit genommen, um der Sache nachzugehen und sie zu analysieren.

Die IPv6-Routen waren das Problem, aber nur auf solchen Systemen, die NetworkManager einsetzten. Auf Server-Systemen, auf RASPBIAN, auf MacOS waren sie in Ordnung.

Mein Router plärrt per IPv6-DHCP und per RA herum, welche Netzwerke wir gerade so haben. Zwei, um genau zu sein. Einen offiziellen, routbaren Netzbereich, den ich vom Provider kriege, und einen site-local Bereich, den ich im Router eingetragen habe. Deshalb plärrt der Router, die FritzBox, fünf Dinge durch das Netzwerk: Nämlich je einen Präfix für die beiden Bereiche, dazu nochmal eine Route auf sich selbst für die beiden Bereiche (scheint überflüssig, wird aber gebraucht für Systeme, die nur auf Routen, und nicht auf Präfixe reagieren) und noch eine default-Route auf sich selbst.

Die meisten Systeme kommen damit klar, und setzen die Routen richtig, und zwar für die beiden Präfixe eine Link-Route, weil der Rechner ja selbst am Segment ist und keinen Router braucht.

Nur die Ubuntu-Desktop-Systeme, die NetworkManager einsetzen, ignorieren die Präfixe und setzen stattdessen nur die zusätzlich verkündeten Routen für die beiden Netzwerkbereiche. Und das erklärt, warum die Verbindungen funktionieren, aber deutlich langsamer sind. Sei werden dann nämlich nicht vom Switch geswitcht, sondern vom Router geroutet. Geht auch, ist aber viel langsamer.

Deshalb fällt’s auch nicht gleich auf. Weil es funktioniert, nur eben drastisch langsamer.

Schon vor langer Zeit Bug aufgemacht. Keine Reaktion.

Nun das neue Ubuntu 21.10 geprüft, Bug immer noch drin. Uh, dachte ich, in der Langzeitversion 22.04, die demnächst kommt, sollte das schon gefixt sein. Etwas so Elementares wie das Routing stimmt nicht, und keinen stört’s.

Also einen Bug Report upstream aufgemacht. Also bei den Developern von NetworkManager selbst, obwohl ich nicht wusste, ob die das überhaupt zu verantworten haben oder das eine Ubuntu-Anpassung ist.

Man reagiert. Aber verhalten. Ich bin doch nicht der erste, der das bemerkte, vor Monaten hatte schon mal jemand anderes den Effekt bemerkt, und einen Bug Report aufgemacht, der aber automatisch wieder geschlossen wurde, weil nichts passierte. Das ist in der Softwarebranche inzwischen leider so. Bugs, um die sich gewisse Zeit niemand kümmert, werden als erledigt geschlossen.

Man diskutiert einen Workaround und wie das doch eigentlich viel besser sei, weil nämlich manche Systeme die Netzwerkeinstellung eingeschaltet haben, ICMP6 redirects zu akzeptieren. Heißt: Wir haben zwar die Routen falsch eingestellt, aber weil der freundliche Router ja auf jeden Verbindungsversuch mit einem „Du Depp, an dem Netz bist Du doch selber dran!“ reagiert, bräuchte man doch eigentlich keine richtigen Routen, weil das damit für jede Verbindung korrigiert werde.

Jain.

Das Akzeptieren von solchen Redirects gilt als Sicherheitsloch, weil man damit Verbindungen übernehmen und man-in-the-middle-Attacken durchführen kann, weshalb nicht nur allenthalben auf Sicherheitsseiten dringend geraten wird, das abzuschalten, sondern viele Distributionen das auch abschalten und übrigens ich auf allen meinen Systemen auch (nämlich per oben erwähntem Puppet, damit ich es auch nicht vergesse).

Und nun grübelt man darüber, ob man nun soll oder nicht, während alle anderen Betriebssysteme und Linux-Distributionen es richtig machen.

Herrje.

Calamares

Vor einiger Zeit ist mir aufgefallen, dass auf einem Rechner bestimmte Aufgaben die Programme nicht nur abstürzen lassen, sondern dann den ganzen Rechner ungenießbar machten.

Grund:

Installierte man neuere Lubuntu-Versionen (Ubuntu mit der Desktop-Variante LXDE, ich mag den normalen Ubuntu-Desktop nicht so), kommt ein anderes Installationsprogramm zur Anwendung als normal. Es heißt Calamares und macht seine Sache eigentlich nicht schlecht, aber setzt ein tmpfs auf /tmp, hält also die /tmp-Dateien im RAM, statt auf Platte.

Im Gegensatz zu ramfs kann tmpfs zwar auch seine Daten in eine Swap-Datei auslagern, aber die legte Calamares zumindest bis Lubuntu 20.04 ja auch nicht an, und es ist unsinnig, ein ram-Filesystem zu verwenden um es dann auf Platte zu swappen.

Das nun führt dazu, dass dann, wenn man ordentlich Daten nach /tmp ablädt, etwa, weil man ein Video produziert oder umkopiert, oder ein Installationsmedium erzeugt, also mal Dateien im GB-Bereich, der gesamte RAM aufgebraucht wird und der Rechner in den RAM-Mangel kommt, außerdem nach /tmp nicht mehr geschrieben werden kann.

Nun kann man sich darüber streiten, ob das Norm-konform ist, weil manche schreiben, dass /tmp nicht nur zeitlich begrenzt speichert, sondern auch vom Umfang her sehr begrenzt sein könne, für große Dinge solle man /var/tmp nehmen. Tun nur viele Programme eben nicht, und da liegen die Daten dann auch wieder rum, bis man sie von Hand wegputzt.

Außerdem sollte man es dann Ubuntu-einheitlich machen. Und nicht nur ab und zu.

Gut, das kann man jetzt manuell leicht korrigieren (per Puppet nicht ganz so leicht, weil man auf laufende Programme Rücksicht nehmen muss), einfach die Zeile aus /etc/fstab rauswerfen, unbedingt (!) die Rechte von /tmp dann noch richtig setzen, und für alles andere noch eine Swap-Datei anlegen und eintragen. Aber man muss es halt machen.

Schon vor Ewigkeiten Bug aufgemacht.

Nischt passiert.

Also noch einen aufgemacht, upstream. bei Calamares.

Man versteht das Problem.

Und stellt fest, dass man eigentlich gar keinen triftigen Grund dafür hat, das so zu tun, außer eben, dass man es seit 2014 so macht und nicht weiter drüber nachgedacht hat.

Man hat das damals gemacht, um die teuren und wertvollen SSDs vor Zugriffen zu schonen (wäre effektiver, noatime zu setzen), und das überhaupt nur dann gesetzt, wenn man bemerkt hat, dass man auf eine SSD installiert.

Ja … pffff … mmhhhh … mal sehen…

Extra-fall-vom-Stuhl:

Im usprünglichen Bug-Report an Ubuntu hatte ich das Problem beschrieben, dass das mit tmpfs auf /tmp kracht, wenn man sehr große Dateien oder eben viele Daten nach /tmp schreibt, beispielsweise Videos produziert oder Installationsimages erzeugt. Weil die halt gerne mal gigabytegroß werden können.

Inzwischen sind sie aufgewacht. Schreibt mir einer, das könne doch gar nicht sein, da hätte ich was falsch verstanden. Calamares sei ein Programm, um Linux auf Rechnern zu installieren. Das würde weder Videos noch Installationsimages herstellen.

Kubernetes in LXD

Ob man Kubernetes mögen sollte, lasse ich hier mal bewusst offen.

Man sollte es kennen. Und egal, ob man es mag oder nicht, es hat sich zu einer Art de-facto-Standard und Wettkampfsieger gemausert. Seit VHS wissen wir, dass der Sieger nicht immer zwingend der Beste ist, aber halt der, der sich durchsetzt.

Eigentlich heißt es, man sollte Kubernetes nicht unter fünf Rechnern anfangen, zwei Kontrolleinheiten und drei Ausführungsknoten mindestens, sonst macht’s ja auch keinen Spaß, aber Ubuntu war so net, das alles unter dem Namen microk8s (k8s = Abkürzung für Kubernetes, weil es sich so ähnlich wie k-eight-s anhört) in einen einzigen snap zusammenzupacken, und zwar auch so, dass es auf einem einzelnen Knoten läuft. Das ist zwar eigentlich unsinnig, weil man dann die Redundanz nicht hat und mit docker compose viel einfacher und bequemer zum gleichen Ziel käme, hilft aber beim Entwickeln, Testen, Verstehen. Und kann inzwischen auch als Knoten eines Clusters fungieren. Also eigentlich feine Sache. Läuft bloß nicht so stabil, wie ich mir das vorstellen würde. Und braucht oft viel CPU, wenn mal wieder irgendwelche Prozesse durchdrehen.

Deshalb käme man in Kenntnis seiner Werkzeuge auf die Idee, das in LXD zu packen. LXC und LXD sind auch Containerumgebungen, nicht unähnlich zu docker, nur dass sie nicht nur einen Prozess, sondern ein ganze Linux einpacken, das sich aber den Kernel mit dem Wirt teilt. Wenn man es mal verstanden hat und seine komplizierte Konfiguration durchblickt, ein nützliches Tool. Also packt man microk8s oder was auch immer man als Kubernetes installieren will, in so einen LXD-Container und hat das dann nicht nur schön sauber vom restlichen System getrennt, sondern kann es nach Belieben bequem ein- und ausschalten. Und hat ein definiertes, sauberes System. Nennt man Aufräumen, Ordnung halten.

Aber, ach.

Geht nicht.

Server dreht durch, Server stürzt ab, Server wird neu gestartet, Spiel geht in Endlosschleife von vorne los.

Untersucht, woran es liegt.

Der microk8s-daemon kubelite will

Set sysctl 'net/netfilter/nf_conntrack_max' to 131072

machen, um da einen hinreichend großen Wert zu haben. Und zwar so dämlich, dass er das auch setzt, wenn der eingetragene Wert sogar höher war, setzt es also mitunter auch runter statt nur rauf.

Das führt zu

open /proc/sys/net/netfilter/nf_conntrack_max: permission denied

Warum?

Weil es ab irgendeinem Linux-Kernel (angeblich 4.1, selbst Ubuntu 20.04 hat schon 5.4) eine Änderung gab. Kontrolldateien wie diese sind innerhalb von Containern nicht mehr schreib-, sondern nur noch lesbar. Deshalb kann man da nichts mehr reinschreiben. Muss man auch nicht, weil der default-Wert da längst hoch genug ist.

Irgendwas in Kubernetes ist aber so doof, dass gleich der ganze Prozess terminiert, wenn das nicht geht. Und dann geht’s von vorne los.

Das Problem ist bekannt und wurde auch anderweitig schon beschrieben. Beispielsweise zu Rancher OS in LXD, selbes Problem.

Das Problem ist sogar schon gefixt. Aber erst in Kubernetes 1.23. Und die ist noch nicht erschienen.

Ruby on Rails

Neulich einen Bug Report aufgemacht.

Bisher war Ruby on Rails gut, und ein neu erzeugtes leeres Projekt lag so in der Größenordnung von 1MByte.

In der neuesten Version hat man das aber so umgemodelt, dass gleich jeder erdenkliche JavaScript-Scheiß geladen wird. Ein neues Projekt ist dann weit über 100 MByte groß.

Ganz abgesehen davon, dass man das alles gar nicht braucht, habe ich darin auch Pakete gefunden, von denen man nicht herausfindet, was sie überhaupt machen, die nicht mehr gewartet werden oder von denen die Maintainer inzwischen sogar selbst warnen und sagen, man solle sie nicht mehr verwenden.

Bug report aufgemacht, weil unnütze und sogar gefährliche Pakete mit Sicherheits- und anderen Lücken zwangsinstalliert werden.

Ergebnis: Bin für eine Woche vom Kommentieren gesperrt worden, weil es nicht respektvoll ist, das nicht zu mögen. Der Verursacher hat sich doch solche Mühe gegeben, den Mist zusammenzusammeln.

Es ist zum Mäusemelken

Das waren jetzt nur ein paar Beispiele. Längst nicht alles.

Aber ein großer Teil er Zeit bei Entwickeln steht eben nicht mehr für Entwicklung zur Verfügung, sondern geht für Fehleranalysen drauf, für Bug-Reports, für das Rumärgern mit tiefeninkompetenten Maintainern, Ignoranz, Überforderung, fehlendem Testen, mangelhaften Abläufen.

Und das wurde nach meiner Beobachten drastisch schlimmer, seit das alles so woke ist, seit jeder „teilhaben“ kann, seit man per Code of Conduct jede Pappnase reinlassen muss.

Mir fällt das beispielsweise bei Ubuntu auf, dass Bugs kaum noch ernstlich bearbeitet werden. In vielen Fällen passiert gar nichts, außer dass sie von der Software irgendwann automatisch wieder geschlossen werden, weil nichts passiert. Oder es kommt einer an, um sich um einen „zu kümmern“, dem man sofort anmerkt, dass er überhaupt nicht verstanden hat, worum es da geht, was das Problem ist, was da passiert, und einfach nur irgendeinen Käse faselt, damit sich sozial um den Bugreporter gekümmert ist und der sich nicht so allein fühlt. Und wenn man dann noch was sagt, dass er den Bug nicht verstanden hat, sofort zutiefst beleidigt ist und respektvollen Umgang einfordert oder androht, einen zu sperren.

Mir fällt auch auf, dass unglaublich viele Softwarepakete nicht mehr gewartet werden und zwischen ein und meist drei, vier Jahren, also seit das so mit dieser Woke- und Teilhabewelle losging und die überall diese Codes of Conduct reindrückten, um die Projekte mit Deppenteilhabe zu überschwemmen. Eine Korrelation ist zwar keine Kausalität, aber von vielen Projekten ist bekannt, dass man die langjährigen Entwickler und Maintainer rausdrückte, weil man durchsetzte, die auch für Privatverhalten, und einfach deren Meinung und Äußerungen, selbst wenn sie mit dem Projekt einfach gar nichts zu tun hatten und anderweitig geäußert wurden, aus ihren eigenen Projekten zu schmeißen.

Gleichzeitig eben hat man überall per „Teilhabe“ selbst die unfähigsten Paradiesvögel reingedrückt, die jede normale Arbeit sabotieren, sich nur um solchen Genderscheiß drehen und durchsetzen, dass man „Master“ und „Slave“ ersetzen muss.

Dieser ganze Woke-Scheiß zieht eine Schneiße der Zerstörung hinter sich her, und die Zerstörung hat die Open-Source-Szene voll ergriffen.

Wir sehen jetzt hier die Schäden dieser Schwachsinnspolitik. Fast nichts funktioniert mehr vernünftig oder wenigstens vertretbar.

Aber: Digitalisierung wollen sie alle haben. Und „Teilhabe“.

Nichts funktioniert mehr, wenn jeder daran „teilhaben“ können muss.

Ein unfassbar dummes Politprogramm.