Seite wählen

NETWAYS Blog

Things done wrong: Custom Packages

Homer Simpson
Als Consultant begegne ich öfter Konzepten jeglicher Art, sei es das ich sie erstellen darf oder mich bei der Umsetzung an diese halten muss. Besonders wenn letztere unkommentiert als Firmenrichtlinie hinzunehmen sind, komme ich oft nicht mehr aus dem Kopfschütteln raus. In diesem Blogpost will ich nun anfangen mit solchen Konzepten abzurechnen und werde wohl immer wieder neue Themen folgen lassen. Ich werde hierbei keine Kundenbeispiele direkt übernehmen sondern Beispiele mischen um es noch weiter zu überspitzen. Auch soll sich natürlich niemand angegriffen fühlen, wenn sein Konzept ähnlich aussieht, denn meist lässt es sich mit historisch gewachsen begründen. Aber vor allem will ich Probleme aufzeigen, die durch die Konzepte erstehen und dazu anregen solche veralteten Konzepte auf den Prüfstand zu stellen.
Das erste Thema, das ich aufgreifen möchte, ist das Thema Softwareinstallation. Die meisten Projekte und Administratoren haben mittlerweile eingesehen, dass lokale Installation aus dem Quelltext-Archiv nicht mehr zeitgemäß ist. Darum liefern Projekte oftmals auch direkt Pakete aus oder stellen zumindest die dazu nötigen SPEC-Files bereit. Die Gründe hierfür sind meist Nachvollziehbarkeit, geringerer Aufwand, kein Kompiler auf dem System, kein mühsames Ermitteln von Abhängigkeiten, etc. Daher existieren viele Konzepte für das Paketieren von Software, welche nicht vom Distributor ausgeliefert wird. Genau mit diesen möchte ich mich beschäftigen.
Nun auf welche Vorgaben trifft man häufig?
* Selbst paketierte Software soll in ein bestimmtes Verzeichnis installiert werden
* Die Software soll einem speziellen eigenem Benutzer gehören
* Alles soll aus einem einzelnen Paket kommen
* Das Paket soll schon die fertige Konfiguration enthalten
* Pakete müssen parametrierbar sein, da je nach Umgebung andere Pfade, Benutzer, etc. verwendet werden sollen.
Mit diesen Vorgaben möchte ich mich nun im Folgenden auseinandersetzen.
Das Argument selbst paketierte Software in ein eigenes Verzeichnis zu installieren ist üblicherweise Sicherheit. Dieser Mythos hält sich erstaunlicherweise und ich suche den Sicherheitsgewinn ähnlich verzweifelt wie den Yeti oder Nessie. Vielleicht lässt sich hier noch entsprechend argumentieren wenn das Verzeichnis mit speziellen Mount-Optionen als separate Partition eingehängt ist. Aber die Optionen, die einen wirklichen Sicherheitsgewinn bieten wie ACLs oder das Abschalten gewisser Optionen wie das Ausführen von Dateien, Uid-Flags, Devices, werden hier meist nicht genutzt. Zudem könnten diese meist besser und gezielter eingesetzt werden, wenn das Paket in Standardpfaden installiert ist und nur gewisse Verzeichnisse ausgehängt werden, zum Beispiel für temporäre Daten.
Gefährlich wird dies meist in Kombination mit der Vorgabe alles einem bestimmten Benutzer zu übereignen. Eigentlich ist ein Benutzername völlig egal. Benutzer unter denen ein Dienst läuft sollten sich aber üblicherweise nicht am System anmelden können und auch nicht auf schreibend auf ihre Konfiguration oder gar Binärdateien zugreifen können. Die Vorgabe kommt meist daher, dass der Benutzer dann allerdings zur Administration verwendet wird statt administratives und Dienstkonto zu trennen. Kann der Dienst nun seine Konfiguration schreiben, eröffnet dies viele Möglichkeiten für Exploits, denn es hat meist seinen Grund warum ein Dienst mit einem unpriviligierten Benutzer läuft. Noch besser wird es wenn der Benutzer den Dienst mittels sudo als root starten darf und Startskript, in dieses eingebundene Dateien oder Binärdateien verändern kann, damit sind in Sekunden die Rechte ausgeweitet, also genau das Gegenteil vom Ziel der Vorgabe erreicht.
Auch andere Sicherheitskonzepte wie SELinux werden durch die verbogenen Pfade schnell unwirksam, denn ohne die entsprechenden Dateikontexte greift die Policy nicht mehr. Der Aufwand Pakete so umzubiegen und dann weiterzupflegen, insbesondere wenn auch Python-, Perl- oder ähnliche Pfade umgebogen werden, ist dann üblicherweise auch so groß, dass Updates seltener gemacht werden als wenn die Software ohne weiteren Aufwand bezogen werden könnte. Auch dies setzt die Sicherheit weiter herunter.
Natürlich gibt es auch Konzepte, die den Aufwand gering halten, wie die von Red Hat eingeführten Software Collections, trotzdem muss immer noch selbst Aufwand betrieben werden. Der Aufwand ist dann besser darin investiert ein Konzept zu erstellen, welches dem Administrator der Zusatzsoftware erlaubt entsprechende Befehle mit sudo aufzurufen und Konfigurationsdateien über ACLs zu editieren, Logdateien zu lesen, …
Die Vorgaben zusätzliche Dateien oder angepasste Konfigurationen schon mit dem Paket mitzuliefern sind zwar machbar, erhöhen aber die Komplexität weiter und es lässt sich schwerer nachvollziehen woher Dateien ursprünglich kommen. Zusätzliche Dateien sollten also in eigene Pakete, Konfigurationen wenn man nicht auf eine Konfigurationsmanagementlösung setzen möchte in ein eigenes Konfigurationspaket. Über Befehle wie rpm -qf lässt sich dann nachprüfen aus welchem Paket eine Datei kommt, mit rpm -qi erhält man Informationen wie die Bezugsquelle und rpm -qV zeigt welche Dateien nachträglich verändert wurden.
Die Anforderung Pakete parametrierbar zu machen finde ich besonders seltsam, da es beim Paketieren nicht nur darum geht Software nicht auf dem System zu übersetzen, sondern auch Nachvollziehbarkeit in allen Aspekten zu schaffen. Da sich nie ausschließen lässt, dass ein anders gesetzter Parameter die ausgeführte Software beeinflusst, geht hierdurch für mich viel Nachvollziehbarkeit verloren. Diese möchte man besonders beim Updaten haben um Probleme auszuschließen.
Ich hoffe zum Nachdenken angeregt zu haben und Argumentationsgrundlagen für entsprechende Konzepte geliefert zu haben. Die nächsten Konzepte, die ich bei Gelegenheit betrachten möchte, sind das Benutzer- und Softwaremanagement und danach fällt mir bestimmt noch weiteres ein, wenn Interesse besteht. Und wer sein Konzept von mir zerpflückt haben möchte oder eins geschrieben braucht, ich bin natürlich ebenso käuflich wie die Kollegen. 😉

Dirk Götz
Dirk Götz
Principal Consultant

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Puppet, Ansible, Foreman und andere Systems-Management-Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich wie nun bei NETWAYS.

RPM-Packaging: Software Collections selbst gemacht

RPM-Icon from www.softicons.com used under LGPL
Zum Abschluss meiner kleinen Reihe von Hilfestellungen zum Thema Paketieren von Software mittels RPM möchte ich die Software Collections beleuchten. Die Software Collections sind ein relativ neues Modell von Red Hat zur Parallelinstallation von Software in unterschiedlichen Version. Um von der in der eigentlichen Distribution enthaltenen Version unabhängig zu sein erfolgt die Installation in ein abweichendes „root“-Verzeichnis, wobei es sich nicht um eine echte chroot-Umgebung handelt, da der Zugriff auf außerhalb liegende Ressourcen trotzdem möglich ist. Stattdessen werden entsprechende Umgebungsvariablen zur Verwendung gesetzt.
Red Hat liefert diese über einen eigene Channel aus, für CentOS und Fedora heißt die Anlaufstelle . Eine Software Collection besteht hierbei aus einem Metapaket, dass die Verzeichnisstruktur erstellt und Skripte mitliefert um diese zu nutzen. Hierbei ist die Funktionsweise recht simpel: Nachdem die Software Collection installiert wurde, können mittels einem Befehl die entsprechenden Umgebungsvariablen gesetzt und diese beispielsweise in einer neuen Shell genutzt werden.

$ ruby --version
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
$ scl enable ruby193 bash
$ ruby --version
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]

Gegebenenfalls kann dieses Kommando auch in einem Wrapper-Skript untergebracht werden, so dass es noch leichter zu verwenden ist.

$ ruby193-ruby --version
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]

So kann beispielsweise Foreman direkt auf dieses Skript als zu verwendende Ruby-Version verweisen.
Und nicht nur die Verwendung ist sehr einfach auch die Erstellung ist sehr simpel. Der zusätzliche Aufwand ist die Erstellung eines Metapakets wobei das Tool spec2scl helfen kann, bei Bedarf die Erstellung von einem oder mehreren Wrapperskripten und die Anpassung des SPEC-Files.
Die Anpassungen halten sich hierbei in Grenzen, da hier mit Makros gearbeitet wird die durch die Software Collection Werkzeuge gesetzt werden. Ein bisschen aufpassen muss man mit Dateien, die außerhalb der Software Collection benötigt werden wie Apache- oder Sudo-Konfiguration. Um hier nun kein Beispiel komplett abzutippen möchte ich nur auf die Red Hat Dokumentation verweisen.
Um das Paket dann mit den gewohnten Werkzeugen zu erstellen, wird noch das Paket scl-utils-build benötigt. Möchte man statt dem lokalen rpmbuild lieber mock verwenden, muss hierbei das Paket durch die mock-Konfiguration in den Chroot-Umgebungen installiert werden! Und noch ein kleiner Tipp verwendet nur die vorgesehenen Makros scl und _scl_prefix, interne Makros wie _scl_vendor funktionieren nicht zuverlässig auf allen Versionen!
Der Aufruf um dann das neue Paket für die Software Collektion zu bauen ist dann nur unwesentlich komplexer als vorher:

mock -r epel-6-x86_64 --define '_scl_prefix /opt/netways' --define 'scl icinga-1.12' rpmbuild/SRPMS/icinga-1.12-interfacetable_v3t-0.05.1-1.fc20.src.rpm

Damit schließe ich zumindest fürs erste meine Reihe zum Thema RPM ab und wünsche jedem viel Erfolg beim Ausprobieren und viel Spaß mit der gewonnen Zeit wenn Software nicht auf jedem System manuell zu installieren ist.

Dirk Götz
Dirk Götz
Principal Consultant

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Puppet, Ansible, Foreman und andere Systems-Management-Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich wie nun bei NETWAYS.

RPM-Packaging: Die Werkzeuge

RPM-Icon from www.softicons.com used under LGPL
Wie versprochen will ich heute nach dem Arbeitsmaterial und der Bauanleitung vorstellen womit mein Werkzeugkoffer für das Bauen von Paketen bestückt ist. Auch ein paar Werkzeuge die ich nicht nutze, aber bestimmt für den ein oder anderen eine Alternative oder Ergänzung darstellen möchte ich kurz erwähnen.
Das Basiswerkzeug rpmbuild hat wohl jeder bereits einmal gesehen, der sich mit dem Thema befassen durfte. Unser Arbeitsmaterial Quelltext und Patches bereitgelegt, angewandt auf die Bauanleitung und es entstehen Schritt für Schritt oder auch in einem Rutsch sowohl Binärpakete als auch Sourcepaket. Letzteres kann alternativ auch als Ausgangspunkt dienen um ein Paket einfach für eine andere Zielplattform zu bauen. Und warum erwähne ich die Möglichkeit des schrittweisen Bauens? Einfach weil es mir so einfacher fällt das Spec-File zu entwickeln. Immer schön eine Sektion schreiben, testen, aus- oder verbessern und zur nächsten übergehen.
So ein bisschen was von Schweizer Armeemesser haben die rpmdevtools. Intial nutze ich hier rpmdev-setuptree um mir eine Buildumgebung aufzubauen. Die Templates von rpmdev-newspec und rpmdev-newinit stellen meist die Ausgangsbasis für die weitere Arbeit dar. Wenns mal wieder schnell gehen muss wird mit rpmdev-bumpspec die Version erhöht und ein Changelog-Eintrag erstellt bevor die neue Version gebaut wird. Bei komplizierter Nummerierung hilft rpmdev-vercmp und rpmdev-rmdevelrpms und rpmdev-wipetree unterstützen beim Hauskeeping. Die beiden letzten sind aber auch der Grund warum nur auf einer virtuellen Maschine paketiere. Selten genutzt werden die anderen Werkzeuge in dieser Sammlung, können aber auch sehr hilfreich sein.
Wenn ich rpmbuild als Schraubenschlüssel bezeichnet hätte dann wäre mock der Koffersatz mit allen Schraubenschlüsseln für jeden Schraubentyp. mock nimmt die gleiche Ausgangsbasis wie rpmbuild baut aber dann in einer chroot-Umgebungen Pakete für beliebige Architekturen und Distributionen. Aber nicht nur das, wenn ein Projekt neben dem Quelltext auch ein Spec-File in einem Git-Repository liegen kann, kann man mock die ganze Arbeit erledigen lassen. Es clont das Repository, baut ein Archiv und dann die Pakete. Wer dann auch gleich noch mehr auf einmal erledigt haben will nutz mockchain und lässt gleich mehrere Pakete bauen.
Die Wasserwaage zur Qualitätskontrolle stellt dann rpmlint dar. Dieses sollte gegen das Specfile, die nicht-installierten und installierten Pakete ausgeführt werden. Hierbei werden neben viele, viele formale Fehlern auch viele potentielle Probleme aufgezeigt. Einen Teil davon kann man sicher ignorieren, rpmlint aber komplett still zu bekommen sorgt sicher für ein qualitativ hochwertiges Paket.
Einen letzten Werkzeugsatz benötigt man um dann die Pakete der breiten Öffentlichkeit zugänglich zu machen. Einen GPG-Key und rpm zum Signieren der Pakete ist erstmal Grundvoraussetzung und sollte genutzt werden um aufzuzeigen, dass ein Paket qualitätsgesichert ist. Createrepo kann dann genutzt werden um die Pakete in einem Repository zu veröffentlichen. Createrepo kann auch mit Gruppeninformationen für die Installation versehen werden, diese können mit dem Tool yum-groups-manager erstellt werden.
Wer eine GUI braucht installiert sich das passende Modul in Eclipse. Wer einen Buildserver braucht den mehrere Package Maintainer gleichzeitig nutzen können, sollte sich den auf mock aufbauenden Buildserver koji anschauen, den das Fedora Projekt nutzt, oder er schaut sich den Werkzeugkasten der Suse-Welt an bis hin zum OpenSuse-Buildserver, alternativ gibt es aber auch kommerzielle Produkte für denjenigen der Support braucht. Aber mit all diesen Werkzeugen habe ich bisher wenig Erfahrung sammeln dürfen.
Ich hoffe dieser kleine Überblick hilft dem ein oder anderen. Auf meiner Agenda für diese kleine Serie steht nun noch eine kleine Einführung in Red Hats Software Collection als Konzept für Pakete zur parallelen Installation von Softwareversionen.

Dirk Götz
Dirk Götz
Principal Consultant

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Puppet, Ansible, Foreman und andere Systems-Management-Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich wie nun bei NETWAYS.

RPM-Packaging: Die Bauanleitung

RPM-Icon from www.softicons.com used under LGPL
In diesem Blogpost möchte ich mich nach dem Quelltext mit der zweiten wichtigen Datei bei Paketbau befassen, dem Spec-File. Ich tituliere dieses immer als Bauanleitung und üblicherweise ist die Erstellung dieses meinen Hauptarbeit beim Paketieren.
Das Spec-File lässt sich in verschiedene Abschnitte aufteilen: Header, Preparation, Clean, Build, Install, Scriptlets, Files und Changelog.
Der Header beschreibt das Paket inklusive Abhängigkeiten und definiert eigene lokale Makros. Viele dieser Beschreibungsfelder werden allerdings durch die unterschiedlichen Programme ausgewertet und aufbereitet, so dass es hier für fast alles feste Vorgaben gibt an die man sich halten sollte. Details finden sich in den Packaging-Guidelines des Fedora-Projekts. Wichtig ist es auch zu wissen, dass hierbei mit Verzweigungen gearbeitet werden kann, so dass ein Spec-File auch für verschiedene Versionen einer Distribution oder auch verschiedene Distributionen verwendet werden kann. Allerdings muss dann sehr auf den Überblick geachtet werden.
Preparation ist der Abschnitt in dem der Quelltext entpackt und gepatcht wird. Dieser wird wie beim letzten Mal geschrieben besonders dann kompliziert wenn sich der Quelltext nicht an bestimmte Konventionen hält.
Clean ist eigentlich optional, da das Aufräumen des Verzeichnisses in dem der Paketbauprozess stattfindet nicht standardmäßig aufgerufen wird.
Build ist die Sektion in der der Quelltext mittels make oder anderen Werkzeugen übersetzt wird und kann entfallen wenn es sich um Pakete handelt, die dies nicht benötigen.
Im Abschnitt Install wird anschließend die Installation in das temporäre Verzeichnis durchgeführt. Üblicherweise in dem dieses Verzeichnis als Variable DESTDIR gesetzt wird und die INSTALL_OPTS auf einen leeren String gesetzt werden.
Scriptlets können bei der Installation und Deinstallation von Paketen ausgeführt werden, wobei es über die Abfrage wie oft ein Paket vorhanden ist, möglich ist beispielsweise Update und Deinstallation zu unterscheiden. Hierbei ist es wichtig darauf zu achten, dass der Rückgabewert immer 0 ist, so dass auch bei fehlschlagenden Skripten die Installation möglich ist. Auch sollten keine Änderungen an der eigentlichen Installation vorgenommen werden oder Dienste (neu-)gestartet werden.
Im Abschnitt Files werden die Dateien aus der Installation in das Paket übernommen. Hier werden die Rechte, Besitzer und Gruppe vorgegeben, aber auch bestimmte Kennzeichnungen vorgenommen. Eine Datei kann beispielsweise als Dokumentation gekennzeichnet werden oder als Konfigurationsdatei. Aufpassen sollte man, dass Dateien nicht als zu einem Paket gehörend markiert werden, die bereits durch ein anderes Paket zur Verfügung gestellt werden.
Ein übersichtliches Beispiel in dem doch alles vorkommt stellt das Spec-File für unseren EventDB Correlator dar.
Beim nächsten Mal will ich dann ein paar Werkzeuge und Hilfsmittel für die Paketentwicklung vorstellen.

Dirk Götz
Dirk Götz
Principal Consultant

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Puppet, Ansible, Foreman und andere Systems-Management-Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich wie nun bei NETWAYS.

RPM-Packaging: Der Quelltext

RPM-Icon from www.softicons.com used under LGPL
Nachdem es mich in letzter Zeit immer öfter trifft, dass ein Kunde die Installation aus Paketen bevorzugt und es eigentlich auch mein bevorzugter Weg der Installation ist, wollte ich eine lockere Serien anfangen rund um das Thema.
Starten möchte ich mit dem Thema mit dem auch ein Paket startet und dass oftmals schon die ersten Hindernisse bereithält, dem Quelltext.
Ein RPM-Paket besteht prinzipiell aus zwei Dingen: dem Quelltext (wenn nötig mit Patches) und einer Bauanleitung, dem Spec-File. Im Spec-File wird angegeben von wo der Quelltext bezogen wird, wie dieser vorzubereiten, zu übersetzen und zu installieren ist, aber auch solche Themen wie die Lizenz unter der er veröffentlicht ist spielen eine Rolle.
Der Quelltext bleibt hierbei unverändert außer es müssen Dateien entfernt werden,die es lizenzrechtlich nicht erlauben sie zu verteilen. Daher muss alles was an Änderungen notfalls wichtig ist in Form eines Patches eingebracht werden. Warum dies leider oft notwendig ist, möchte ich im folgenden erläutern.
Mein Hauptgrund einen Patch hinzuzufügen ist die vorgesehene Installationsroutine. Diese besteht meist aus dem üblichen ./configure, make, make install, welche sich auch zum Paketieren eignet. Andere Optionen sind natürlich auch möglich, aber nur solang sie keine Interaktion erfordern. Wenn dies der Fall ist, schreibe ich diese üblicherweise gleich auf den Standard um.
Aber auch die übliche Make-Routine muss nicht immer eine gute Ausgangsbasis sein. Viele Entwickler sehen leider nur eine Installation in die von ihnen gewählten Standard-Pfade vor, meist /usr/local/bin oder ähnliches. Hierbei werden zur Sicherheit diese Verzeichnisse auch üblicherweise noch mittels install erstellt. Leider führt beides zu Problemen, denn bei der Erstellung eines RPM wird der Installationsvorgang von einem unpriviligierten Benutzer unterhalb eines speziellen Verzeichnisses durchgeführt, dem sogenannten Buildroot. Pfade außerhalb können also nicht angelegt werden und Dateien auch nicht anderen Benutzern übereignet werden.
Die Lösung hierfür sind mit configure konfigurierbare Pfade, da diese aber auch so in Konfigurationsdateien oder ähnlichem referenziert werden, muss noch ein weiterer Mechanismus genutzt werden um in die Buildroot zu installieren. Hierfür wird eine Variable DESTDIR genutzt, diese wird in den Makefiles dem eigentliche Zielpfad vorangestellt. Somit stehen in Konfigurationsdateien die echten Pfade wie beim Konfigurieren angegeben und die Installation erfolgt in diese Pfade relativ zur Buildroot.
Nun haben wir nach das Problem der Dateirechte. Werden diese beim install festangegeben, muss gepatcht werden. Guter Stil ist es diese als Variable INSTALL_OPTS zu hinterlegen, so dass diese auch in unserer Bauanleitung einfach überschrieben werden können.
Dies sind die üblichen Probleme. Patches um eine Hotfix einzupflegen solang noch kein Release erfolgt ist, sind dank git überhaupt kein Problem mehr. Fehlende Lizenzangaben finden sich ebenso immer seltener wie schlecht gepackter Quelltext, also ohne übergeordnetes Verzeichnis oder mit falscher Dateiendung.
Wenn sich nun Entwickler angesprochen fühlen und ihre Installationsroutine umschreiben wollen, habe ich ein paar Beispiele hierfür:
EDBC (Make-Routine für Systempfade umgebaut
Icinga-Cronk BP-Addon (phing durch make ersetzt)
Interfacetable_v3t (Make-Routine um DESTDIR ergänzt)
Und wenn nun jemand nach unseren Paketen fragt, kann ich leider nur weiter um Geduld bitten, aber wir arbeiten daran. Versprochen!

Dirk Götz
Dirk Götz
Principal Consultant

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Puppet, Ansible, Foreman und andere Systems-Management-Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich wie nun bei NETWAYS.