News
Das Neuste aus der Welt von Adfinis SyGroup
Als bekannt wurde, dass Microsoft MSSQL auf Linux portiert, dachte sich wohl so mancher Sysadmin, dass das in einer Katastrophe endet. Enterprise-Anbieter haben bisher nicht mit gelungenen Linux Ports geglänzt – Oracle DB auf einem Linux-Server zu installieren (und konfigurieren) gehört zu den mitunter schlimmsten Erfahrungen, die ein Admin sammeln kann. Bei Microsoft sieht das so aus:
$ curl https://packages.microsoft.com/config/rhel/7/mssql-server.repo | sudo tee /etc/yum.repos.d/mssql-server.repo
$ sudo yum update
$ sudo yum install mssql-server
Man mag sich verwundert die Augen reiben – Microsoft hat tatsächlich verstanden, wie man Software für Linux paketieren muss. \o/
Doch wie sieht MSSQL für Linux aus der Nähe aus? Engineers der Adfinis SyGroup wagten einen Blick hinter die Kulissen.
Unter der Haube
Eines der wichtigsten Credos beim Portieren von MSSQL auf Linux ist, dass sich das Laufzeitverhalten gegenüber Windows nicht verändert. Applikationen sollen nicht einmal merken, wenn im Backend ein Tux Einzug hält.
Hier stellt sich sofort die Frage, wie Microsoft ein solches Unterfangen löst, schliesslich gibt es immer Edge Cases, wenn man eine Lösung auf eine komplett andere Plattform portiert. Genau solche Edge Cases will man bei einer zentralen Enterprise-Anwendung ausschliesen, schliesslich könnten schon minimalste Regressions bei einer kritischen Lösung immense Schäden auslösen. Schaut man sich noch die vielen Abhängigkeiten an, welche MSSQL hat, stellt man fest, dass eine eigentliche Portierung inkl. aller Libs und Umgebungen wie CLR, eine Monster-Aufgabe darstellt, die sich vom Aufwand her nur schlecht rechtfertigen lässt. In solchen Situationen ist Erfindergeist gefragt und wir finden, dass Microsoft eine sehr kreative Lösung gewählt hat.
Eines sei schon im Voraus gesagt, Microsoft benutzt +/- die selben Executables und Libraries unter Linux wie unter Windows. Wie das ganze geht, erläutert die folgende Übersicht.
SQL OS
Bereits mit SQL Server 2005 hat Microsoft begonnen, Betriebssystem-abhängige Teile in einem eigenen Modul namens SQLOS zusammenzufassen. Das Ziel war damals jedoch noch nicht, andere Plattformen zu unterstützen, sondern tiefergreifende Monitoring- und Analysefunktionen bereitstellen zu können. Dies hatte jedoch den positiven Nebeneffekt, dass die meisten Zugriffe auf das Betriebssystem zentralisiert wurden. Dies wurde für die Portierung auf Linux später zu einem grossem Vorteil. Allerdings war diese Implementation natürlich noch nicht auf die Unterstützung verschiedener Betriebssysteme ausgelegt und viele Windows-Spezifika waren für die übergeordneten Schichten immer noch klar ersichtlich.
Mit diesem Layer könnten zwar die System-Aufrufe zentralisiert portiert werden, jedoch würden die weiteren Module und Bibliotheken, welche von SQL Server verwendet werden, davon immer noch nicht profitieren. Zum Glück hatte eine andere Abteilung innerhalb Microsoft mit dem Projekt Drawbridge begonnen, eine Abstraktion für Windows-Prozesse zu implementieren – ursprünglich, um die Virtualisierung von Windows-Systemen zu vereinfachen.
Drawbridge
Drawbridge ist ein Research Projekt von Microsoft, das schon 2011 das Licht der Welt erblickte. Im Grunde ging es bei Drawbridge darum, den Overhead bei der Virtualisierung von Windows Systemen zu reduzieren. Um dies zu erreichen, benötigte Microsoft knapp zusammengefasst folgende Bestandteile:
- Prozess-Isolation
- Layer, der das Windows ABI (Kernel/Syscalls) abbildet
- User Space Implementation der Windows APIs/Libs (win32 Subsystem)
- Treiber auf dem Gast-System um das Memory für die VM zu initialisieren
Diese Zutaten ergeben bereits ein relativ klares Bild, was bei Drawbridge passiert, wenn eine VM erstellt wird. Als erstes initiiert der Treiber auf dem Gast-System den Speicher für die virtuelle Maschine. In diesem Schritt wird ein Layer geladen, der das Windows ABI abdeckt – dies wird mit einem User Space NT Kernel bewerkstelligt. Zudem wird eine Library in den Speicher der VM geladen, welche die Windows APIs abbildet. Sowohl der User Mode Kernel wie auch die Library, welche die zahlreichen APIs abbildet, sind Bestandteil von LibOS. Sobald die VM mit LibOS initiiert ist, können darin Windows Binaries ausgeführt und Windows Libraries geladen werden ohne dass ein Syscall oder API-Aufruf die VM verlassen muss.
Drawbridge wurde gemäss unseren Informationen nie in ein Produkt integriert, zeigte aber auf, wie man “leichte Windows Virtualisierung” machen könnte.
LibOS
Wie bereits erwähnt, beinhaltet Drawbridge eine vollständige User Space-Implementation der Windows System Calls und der APIs die unter Windows benötigt werden. Das heisst, dass Drawbridge eine Art User Space Version des NT-Kernels implementierte (NTUM genannt – “user mode NT”) zudem gehört eine Library zu LibOS, welche die Windows APIs im User Space abbildet. Beide Elemente sind gegenüber den eigentlichen Implementationen in einer normalen Windows Umgebung massiv schlanker gehalten, ergeben aber eine Laufzeitumgebung, welche sich nichts anders verhält, als ein herkömmliches Windows.
SQL PAL
Drawbridge und SQLOS ermöglichen in Kombination, MSSQL Server unter Linux auszuführen, gehen aber in ihrer Implementation zum Teil viel zu weit und lösen teilweise die gleichen Probleme. Aus diesem Grund hat das Team bei Microsoft entschieden, die relevanten Teile zu extrahieren und aus Drawbridge, LibOS und dem Abstraktions-Layer SQLOS einen neuen Plattform-Abstraktionslayer (PAL) zu bauen. Dieser enthält nur die für SQL Server relevanten ABI und APIs und bietet alles, was nötig ist, um eine Laufzeitumgebung für MSSQL zu bieten. Die unterste Schicht besteht dabei aus einem Linux Binary (im User Space), welches den Rest der Umgebung initiiert.
Offene ToDos bezüglich SOS und LibOS
Der aktuelle Status ist, dass MSSQL auf Linux bereits problemlos funktioniert, jedoch ist das Team von Microsoft noch nicht fertig mit der Zusammenlegung von SOS und LibOS. So gibt es momentan zwei Versionen von SOS / LibOS innerhalb des SQL Servers für Linux, wobei die “obere” Version Calls an SQL PAL weiterleitet, welches wiederum die neuere Version von SOS verwendet, um via einer Host Bridge Anfragen an den Linux-Kernel zu senden. Microsoft arbeitet aktuell intensiv daran, diese Doppelspurigkeit zu eliminieren und die beiden Instanzen zu vereinheitlichen, damit am Schluss die gesamte Abstraktion in SQL PAL erledigt werden kann.
Die finale Architektur im Überblick
Wie erwähnt, haben Drawbridge und SQLOS einige Überschneidungen, welche Microsoft noch eliminiert. Generell bildet SQL PAL die Laufzeitumgebung für MSSQL und das RPM/DEB Paket bringt alle Executables sowie die nötigen zusätzlichen Windows Libraries mit um MSSQL, aufsetzend auf SQL PAL, ausführen zu können. Gemäss Microsoft werden rund 81MB unkomprimierte Windows Libraries mitgeliefert (das ist nur rund 1% einer kompletten Windows-Installation), das SQL PAL Binary ist rund 8MB gross.
Die Software landet übrigens in /opt
und wird mit systemd verwaltet. Microsoft liefert dabei alles pfannenfertig und inklusive man pages aus.
Generell lässt sich der Prozess Ablauf, um MSSQL auf Linux zu starten, wie folgt beschreiben: die Host-Komponente (standard Linux Binary) startet als erstes SQL PAL und dieses initiiert wiederum den MSSQL Server in der “emulierten” Windows Umgebung.
Die finale Architektur sieht in etwa so aus:
Der geneigte Leser wird wohl bereits festgestellt haben, dass dieser Ansatz dem Windows Subsystem for Linux sehr ähnlich sieht.
Erste Erfahrungen
In Zusammenarbeit mit einem unserer Kunden arbeiten wir bereits an der ersten Migration einer MSSQL DB auf Linux.
Die ersten Erfahrungen sind sehr gut und zeigen, dass das Konzept auch in der Praxis funktioniert.
Für das Management der DB unter Linux bietet sich sowohl das CLI wie auch SSMS an, letzteres muss aber bis auf weiteres noch auf Windows ausgeführt werden. Als plattformunabhängige Alternative zu SSMS für Admins die kein Windows nutzen, hat Microsoft die offizielle MSSQL-Erweiterung für Visual Studio Code im Angebot, welches unter Linux, Mac und Windows eingesetzt werden kann. Dabei handelt es sich zwar nicht um einen vollständigen Ersatz für SSMS, die Lösung funktioniert aber sehr gut und bietet u.a. auch IntelliSense support.
Einschränkungen von MSSQL auf Linux
Microsoft kommuniziert sehr offen, wie es bezüglich den aktuellen Einschränkungen von MSSQL auf Linux aussieht und führt diese in den Release Notes exakt auf.
Momentan noch nicht verfügbar sind beispielsweise:
- Volltext Suche
- Replikation
- Active Directory Authentisierung
Genauere Informationen dazu findet man in den offiziellen Release Notes.
Nächste Schritte
Wir planen diverse weitere Tests und wenn es die Zeit zulässt, werden wir noch das eine oder andere weitere Thema in diesem Blog abdecken. Insbesondere interessiert sind wir am Clustering von MSSQL unter Linux, sowie dem Einsatz von MSSQL in Containern.
Fazit
Man muss Microsoft für die vorliegende Lösung ein Kränzchen winden – was die Engineers aus Redmond in Bezug auf die technische Umsetzung vorgemacht haben, hinterlässt bei uns staunende Techies.
Mit dem gewählten Ansatz ebnet Microsoft zudem den Weg für die Portierung weiterer Windows Dienste auf Linux. Schliesslich könnte SQL PAL auch für Exchange, AD, IIS, usw. Pate stehen – uns würde jedenfalls nicht erstaunen, wenn Microsoft schon 2017 verkündet, dass es nun auch Exchange für Linux gibt.
Interesse?
Haben Sie Interesse, MSSQL auf Linux zum Fliegen zu bekommen? Wir helfen sehr gerne weiter und unterstützen Sie mit unserer gesammelten Expertise bei möglichen Migrations-Projekten. Gerne treten wir mit Ihnen in Kontakt, Sie erreichen uns unter info@adfinis.com.
Quellen
Im Bereich von Webserver sind viele Möglichkeiten vorhanden, um Verbindungen besser abzusichern, aber auch Cross-Site Attacken zu verhindern.
SSL
Es werden hier zuerst die einfachen SSL/TLS Konfigurationen, danach noch erweiterte SSL/TLS Features, wie HSTS und OCSP aufgezeigt. Grundsätzlich wird empfohlen immer aktuelle Protokolle und Cipher Suites, zum Beispiel aus dem Mozilla Wiki, zu kopieren. Diese werden oft nachgeführt und es sind nicht nur verschiedene Cipher Suites aufgelistet, sondern auch die jeweilige Kompatibilitätsliste dazugegeben.
Die Konfiguration “Modern” ist zwar anstrebenswert, jedoch werden sich dadurch ältere Clients oft nicht mehr auf die Server verbinden können. Daher empfiehlt es sich eher, die Konfiguration “Intermediate” zu nutzen. Im Mozilla Wiki und bei Cipherli.st sind auch immer die Konfigurationen verschiedener Software gegeben. Cipherli.st mag zwar übersichtlicher sein und mehr Beispiele aufzeigen, die Cipher Suites sind jedoch längst nicht so durchdacht, wie im Mozilla Wiki. Daher sollten die Cipher Suites eher aus dem Mozilla Wiki übernommen werden.
Nginx
server { listen 80 default_server; listen [::]:80 default_server;
# Redirect all HTTP requests to HTTPS return 301 https://$host$request_uri; }
server { listen 443 ssl http2; listen [::]:443 ssl http2;
# Certs sent to the client in SERVER HELLO are concatenated ssl_certificate /path/to/signed_cert_plus_intermediates; ssl_certificate_key /path/to/private_key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits ssl_dhparam /path/to/dhparam.pem;
# Intermediate configuration, tweak to your needs ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) add_header Strict-Transport-Security max-age=15768000;
# OCSP Stapling
# Fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on;
## Verify chain of trust of OCSP responses ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
resolver <IP DNS resolver>;
[...] }
Nginx erwartet als CA Zertifikat (Parameter ssl_certificate
) das Zertifikat aller Intermediate CAs und das eigene Server Zertifikat (alles im PEM Format). Diese können einfach zusammen kopiert werden (das erste Zertifikat im File sollte das Server Zertifikat sein).
Apache
<VirtualHost *:443> [...] SSLEngine on SSLCertificateFile /path/to/signed_certificate_followed_by_intermediate_certs SSLCertificateKeyFile /path/to/private/key
# Uncomment the following directive when using client certificate authentication
#SSLCACertificateFile /path/to/ca_certs_for_client_authentication
# HSTS (mod_headers is required) (15768000 seconds = 6 months) Header always set Strict-Transport-Security "max-age=15768000" [...] </VirtualHost>
# Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off
# OCSP Stapling, only in httpd 2.3.3 and later SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off SSLStaplingCache shmcb:/var/run/ocsp(128000)
Testen
Um HTTPS Server zu testen, eignet sich Qualys SSL Labs am besten. Dort sind auch bei neuen Attacken schnell Tests eingebaut, welche die Server auf die Vulnerabilities testen. Alternativ kann hierzu auch Hardenize verwendet werden. Dieses befindet sich momentan aber noch in einer Testphase.
Es ist möglich, mit openssl
manuell zu testen, der folgende Test kann dabei einfach mit den eigenen Parameter erweitert werden. Dies ist nur ein Basis Command, welcher den Inhalt des Server Zertifikates in Textform darstellt. Es kann damit auch die Cipher Suite getestet werden, da dies aber lange und vielzählige Commands sind, wird empfohlen, dies mit den vorhandenen Diensten zu machen. Ist dies nicht gewünscht oder technisch nicht möglich, kann z.B. SSL Decoder lokal installiert und ausgeführt werden, die Sources dazu befinden sich auf GitHub ist.
$ openssl s_client -connect example.com:443 2>/dev/null </dev/zero | openssl x509 -noout -text
Weitere Parameter sind in der Manpage von s_client
und x509
dokumentiert.
Weitere Features im Bereich von SSL/TLS
Webserver können auch Headers für Strict-Transport-Security
und Public-Key-Pins
ausliefern. Welche gewünscht sind und welche nicht, hängt vom Einsatz ab.
Strict-Transport-Security – RFC 6797
Die Idee dahinter ist, dass wenn ein Browser mit einer Webseite einmal eine Verbindung hatte, zukünftig weis, dass immer HTTPS genutzt werden soll. Den Wert, der vom Webserver gesendet wird, ist die Anzahl Sekunden für wie lange diese Einstellung gültig sein soll.
Public-Key-Pins – RFC 7469
Mit Public Key Pinning (HPKP) wird die Subject Public Key Info
im Zertifikat angegeben (ist schon im Certificate Signing Request), welcher der Webserver ausliefern muss. Mit der stark wachsenden Verbreitung von Let’s Encrypt ist dies nicht mehr so simpel, da dort die Zertifikate automatisch erneuert werden. Wird immer der selbe Certificate-Signing-Request verwendet, funktioniert HPKP, dies muss jedoch so vom Let’s Encrypt Client umgesetzt sein. Das Verständnis von HPKP ist enorm wichtig, um dieses korrekt umzusetzen. Werden Fehler gemacht, können Webseiten gegebenenfalls von gewissen Clients über längere Zeit nicht mehr genutzt werden. Backup Keys sind Pflicht und werden auch vom RFC vorausgesetzt. Backups des Servers dürfen natürlich nicht vergessen gehen.
Weiterführendes
Webserver sollten auch gewisse Headers, z.B. gegen Cross-Site-Scripting, ausliefern. Welche gewünscht sind und welche nicht, hängt vom Einsatz ab. securityheaders.io bietet die Möglichkeit gängige Headers zu testen:
- Content-Security-Policy
- X-Frame-Options
- X-XSS-Protection
- X-Content-Type-Options
Diese Optionen können Auswirkungen auf die Webseite haben und brauchen teilweise spezifische Anpassungen.
Eine mögliche Konfiguration von Nginx sieht wie folgt aus (in der server
Section):
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
add_header Content-Security-Policy "script-src 'self'";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
Die entsprechenden Werte sind per Default konfiguriert und sollten so angepasst werden, dass die Seite auch funktioniert. Gängige Browser zeigen in den Developer Tools beim Laden der Seite, was verhindert wurde. Dadurch kann darauf geschlossen werden, welche Werte noch hinzugefügt werden müssen.
Links
Bei Matrix handelt es sich um ein Protokoll, welches sein Hauptmerkmal auf chatten legt. Das Protokoll ist darauf ausgelegt, die schon bestehenden Chat-Lösungen wie z.B. XMPP (Jabber), IRC oder Mattermost zu verlinken.
Vergleich XMPP
XMPP hat grundsätzlich dieselbe Idee, ein Unterschied ist der Aufbau des Protokolles. XMPP hat ein Basis RFC und kann so mit diversen XEPs erweitert werden. Dies macht das Protokoll sehr komplex und jeder Server kann andere XEPs implementieren. Im Gegensatz dazu besteht Matrix aus einem RFC in welchem alles spezifiziert ist. Wenn neue Features dazu kommen, muss das Basis Protokoll selber mit einem neueren RFC erweitert werden.
Funktionalität
Das Protokoll ist auf Basis von HTTP aufgebaut. Jeder Channel und jeder Client ist mindestens einem Server zugeordnet. So hat zum Beispiel der Server example.com den Channel foo, welcher nach dem entsprechenden Namensschema “#foo:example.com“ heisst. Dieser Channel kann aber über mehrere Server verteilt werden, so kann er z.B. auch über “#foo:example.org“ verfügbar gemacht werden. Dies hat den Vorteil, dass ein Channel auch bei Ausfall eines Servers weiterhin verfügbar ist.
Wird eine Message an einen Server geschickt, wird diese danach an jeden Server weitergeleitet, auf welchem ein User diesen Raum ebenfalls aktiviert hat.
Bridges
Es gibt zum Beispiel eine IRC Bridge, welche das IRC Netzwerk Freenode auf Matrix.org zur Verfügung stellt. Wird dem Channel “#freenode_#ansible:matrix.org“ gejoint, sieht dies auf Seite von IRC aus, als ob ein neuer User den Channel “#ansible“ joint, es gibt hierbei pro User und IRC Server eine Verbindung vom Matrix.org Server aus. Auf der Seite von Matrix präsentiert sich das Ganze wie ein normaler Matrix Channel.
Aktuell sind schon diverse Bridges vorhanden. Unten ist eine Übersicht der aktuellen Situation.
Identity Service
Jeder User hat eine Matrix User Identifikation, welche sich nach dem Schema “@user:domain“ richtet, also beispielsweise “@bob:matrix.org“. Die Matrix Accounts werden auf den jeweiligen Homeserver gespeichert. Um Matrix Accounts mit anderen Accounts zu verknüpfen, existiert der Identity Service. Aktuell existiert als bekannter Identity Service Provider nur [Vector.im](https://vector.im). Dieses Feature ist aber optional, da die eigentlichen Accounts auf den jeweiligen Servern liegen und nur die Verknüpfung zu anderen (ausserhalb von Matrix) Accounts dort abgespeichert werden.
Implementationen
Da es sich bei Matrix um ein Protokoll handelt, braucht es noch Implementationen davon. Dabei können drei Komponenten getrennt angeschaut werden, die Server, die Clients und die Bridges.
Server
Die gebräuchlichste Server Implementation ist Synapse, welche in Python implementiert ist. Diese wird von den Protokoll-Entwicklern als ihre Referenz-Implementation zur Verfügung gestellt.
Bridges
Es gibt schon in ganz verschiedene Netzwerke eine Bridge. Die wohl gebräuchlichste ist IRC, von welcher es schon mehrere Produkte gibt. Die Liste der unterstützten Netzwerke ist bereits gross und so können unter anderen auch Bridges zu XMPP, Mattermost, Slack oder GitHub betrieben werden.
- Types of bridge
- Bridge Implementations
Die Integration der Bridges ist mit der Weboberfläche riot.im sehr simpel. Das Aktivieren eines neuen Bots funktioniert in etwa so, dass ein neuer Channel erstellt und in diesem dann der jeweilige Bot hinzugefügt wird. Dafür gibt es in den Room Settings einen Menüpunkt “Manage Integrations”. Diese Bridges werden von Riot zur Verfügung gestellt, die Auswahl ist aber begrenzt. Sollen andere Bots und Bridges hinzugefügt werden oder ist z.B. ein IRC Netzwerk nicht verfügbar, muss der entsprechende Bot oder die entsprechende Bridge selber zur Verfügung gestellt werden.
Clients
Es gibt schon reichlich Clients. Synapse bringt eine kleine Weboberfläche mit. Eine der gebräuchlichsten Oberfläche ist Riot, welche als Web-Applikation, Android App und iPhone App zur Verfügung steht. Riot ist dabei eine reine Webapplikation, welche auf die API von Matrix zugreift. Sie hat selber keine Datenbank oder persistente Daten im Hintergrund.
Eine weiterer Client ist WeeChat, für welchen es ein Plugin gibt. Dies ist für all jene interessant, welche gerne einen Client in der Konsole bedienen.
Erkenntnisse
Matrix macht es einfach über ein Protokoll auf die verschiedenen, schon vorhandenen Protokolle zu zugreifen. Die Möglichkeit den Client selber zu wählen ist ein zusätzliches Nice-to-have.
Diverse Implementationen sind noch in einer Alpha bis Beta Phase. Dies schränkt die Wahl der einzelnen Komponenten beträchtlich ein.
Das Protokoll kennt nur einen reduzierten Satz von HTTP Headern. So ist zum Beispiel der Server Name Indicator (SNI) nicht implementiert, was dazu führt, dass Matrix nur unter gewissen Umständen hinter einem Reverse Proxy betrieben werden kann.
Wer viel mit diversen Linux Systemen arbeitet und diese noch manuell aufsetzt, kennt das Problem, dass immer das entsprechende Installationsmedium fehlt. Weiter wäre immer ein Rescue System zu haben auch hilfreich, viele nutzen dafür Live Systeme wie grml, Kali oder Damn Small Linux. Jedes dieser Systeme hat aber Einschränkungen, z.B. ist teilweise eine Ausgabe auf der seriellen Konsole zwingend, jedoch vom entsprechenden System nicht unterstützt.
In diesem Artikel wird kurz ein Systemimage präsentiert, welches im Frust von zu vielen USB Sticks für Installations- und Live-Systemen entstand. Die Anforderungen waren:
- “Live”-System für Rescue
- Installations-Medium für mehrere gängige Distributionen
- Einfach die neusten Images einspielen
- Keine eigenen Anpassungen an den diversen Systemen
Ansatz
Auf einem USB Stick wird ein Arch Linux installiert, welches mithilfe von Grub bootet. Grub bietet neben dem Arch Linux auch die Möglichkeit andere Systeme zu booten oder zu installieren.
Grub und das “Live” Arch Linux werden auf der seriellen und graphischen Konsole dargestellt. Wo möglich trifft dies auch auf die anderen Systeme zu (was nicht immer möglich ist, da z.B. ein Kali Linux nur graphisch startet). Das “Live” Arch Linux wird nicht als echtes Live-System aufgebaut, sondern ist weiterhin Read-Write, da somit auch zusätzliche Pakete und Updates installiert werden können.
Eine aktuelle Liste der Systeme, welche mit diesem Image gebootet werden können, ist folgende:
- “Live” Arch Linux (Rescue System; Read-Write)
- Arch Linux Installer
- Debian Jessie Netinstall
- Debian Jessie Preseed Install (mit lokalem Preseed-File und Netinstall für die Pakete)
- CentOS 7 Installer
- Kali Linux
- Tails
Probleme
Die verschiedenen Systeme erwarten unterschiedliche Kernel-Parameter, dies bereitete des öfteren Probleme, da Systeme nicht korrekt oder gar nicht booteten. Eine grosse Hilfe war hierbei das Arch Linux Wiki, welches einen Artikel zu diesem Thema hat.
Die diversen “Live” Systeme werden in der /etc/grub.d/40_custom
eingetragen. Dies passiert manuell, je nach System wird direkt der Kernel und das InitramFS gestartet oder es wird zuerst ein ISO Image Loopback gemounted. Zwei Beispiele, welche genau diese zwei Fälle abbilden, sind hier gezeigt:
- CentOS 7 Installer Menuentry
menuentry 'CentOS 7 Installer' {
set kernel='/centos-7-vmlinuz'
set initrdfile='/centos-7-initrd.gz'
set append='console=ttyS0,115200n8 devfs=nomount'
set ip='ip=192.168.1.10::192.168.1.1:255.255.255.0:host.example.com:enp1s0:off nameserver=8.8.8.8'
set repo='repo=http://pkg.adfinis.com/centos/7/os/x86_64'
set vnc='vnc vncpassword=password'
linux $kernel $append $ip $repo $vnc --
initrd $initrdfile
}
- Kali Linux Installer Menuentry
menuentry 'Kali Linux 2016.2 amd64' {
set isofile='/kali-linux-2016.2-amd64.iso'
loopback loop $isofile
linux (loop)/live/vmlinuz boot=live findiso=$isofile noconfig=sudo username=root hostname=kali
initrd (loop)/live/initrd.img
}
Die entsprechenden Config Optionen sind in der Grub Dokumentation beschrieben. Welche Parameter einem Kernel mitgegeben werden können, hängt zum einen von der Kernel-Version ab, zum anderen von der Distribution. Eine Liste von möglichen generischen Parametern ist auf kernel.org abrufbar.
Image
Das Image wird öffentlich zur Verfügung gestellt. Es wird keine Haftung zur Aktuallität oder allfälligen Problemen übernommen:
https://files.adfinis.com/rescue-multiboot/rescue-multiboot-latest.img.gz
Nach dem Herunterladen kann das Image auf einen USB Stick transferiert werden. Der USB Stick muss mindestens 8 GB Speicherplatz bieten. Dabei werden alle Daten auf dem USB Stick gelöscht. Ist das Image auf den USB Stick transferiert, wird die Partition noch auf das Maximum vergrössert. Der String /dev/sd<X>
muss dabei unbedingt durch die Disk des USB Sticks ersetzt werden.
$ DISK="/dev/sd<X>"
$ gzip -cd rescue-multiboot-latest.img.gz | dd of="$DISK" bs=8M
$ printf "d\nn\np\n1\n2048\n\nw\n" | fdisk "$DISK"
$ e2fsck -f "${DISK}1"
$ resize2fs "${DISK}1"
Updates
Der USB Stick sollte gelegentlich aktualisiert werden. Vorbereitend sollte dafür das “Live” Arch Linux gestartet werden.
Nach dem Start wird jeweils eine Netzwerk Verbindung hergestellt. Die vorhandenen Interfaces können mit ip addr show
dargestellt werden. Das Interface muss teilweise noch mit ip link set $INTERFACE up
gestartet werden. Danach wird eine IP-Adresse am einfachsten über Ethernet per DHCP geholt, dafür einfach dhcpcd $INTERFACE
starten. Anschliessend sollte das System eine IP-Adresse haben und kann mit pacman -Syu
aktualisiert werden.
Komplexere Netzwerk Verbindungen können mithilfe von netctl
hergestellt werden. Entsprechende Konfigurationsbeispiele sind im Verzeichnis /etc/netctl/examples
zu finden und müssen nach /etc/netctl
kopiert und danach angepasst werden. Starten kann man diese mit netctl start $CONFIGNAME
. Die verschiedenen Images zum Installieren oder Live-Booten sind im Root Verzeichnis. Sie können simpel aktualisiert werden, indem die jeweils aktuellsten Versionen der ISOs, Kernel und initrd Images heruntergeladen werden. Es gibt keine Anpassungen an den Images oder initrd Images.
Um Debian-Pakete automatisiert zu bauen, haben wir uns entschieden, GitLab CI einzusetzen. GitLab CI bietet die Möglichkeit Tasks aufgrund von definierbaren Ereignissen, wie zum Beispiel Git-Tags, auszuführen.
Wir haben einen generischen Docker-Container erstellt, der die Basis-Tools für den Paketbau enthält und von GitLab verwendet wird, um das Paket zu bauen. Der Docker-Container erlaubt es, Updates in der Build-Umgebung einfach einzuspielen, da der Container einfach durch einen neuen ersetzt werden kann.
Nachfolgend wird die automatisierte Paketierung des Log Analyse Tools GoAccess gezeigt. Viele Tools sind jeweils nicht in der neusten Version paketiert, womit selbst Hand angelegt werden muss.
Debian-Paket vorbereiten
Als erstes werden die Dateien erstellt, welche den Bau des Debian-Pakets steuern. Im Fall von GoAccess sind das die folgenden:
debian/changelog # Änderungen am Paket und der Software
debian/compat # Kompatibilitätslevel für debhelper
debian/control # Paketspezifische Angaben wie Abhängigkeiten und Beschreibung
debian/rules # Anweisungen für debhelper
Debian selbst bietet bereits eine ausführliche Dokumentation an, welche den Einstieg in die Paketierung vereinfacht.
Docker-Container vorbereiten
Auf einem Hostsystem muss ein Container vorbereitet werden, in dem das Paket danach gebaut werden kann. Dazu wird zuerst das Dockerfile
erstellt:
FROM debian:wheezy
ADD setup.sh /opt/
RUN /bin/bash /opt/setup.sh
Im Dockerfile
(offizielle Dokumentation) wird angegeben, welches Basis-Image verwendet werden soll. In diesem Fall ist das Debian Wheezy. Danach wird das Script setup.sh
in das Verzeichnis /opt/
des Containers kopiert.
In setup.sh
wird der zu verwendende Mirror konfiguriert sowie die grundlegendsten Abhängigkeiten installiert, die bei jedem Build verwendet werden können:
#!/bin/sh
# change to our own mirror
echo "deb http://pkg.adfinis.com/debian/ wheezy main non-free contrib" > /etc/apt/sources.list
echo "deb http://security.debian.org/ wheezy/updates main" >> /etc/apt/sources.list
echo "deb http://pkg.adfinis.com/debian/ wheezy-updates main contrib non-free" >> /etc/apt/sources.list
# requirements
apt-get update
apt-get -y install git dh-make build-essential autoconf autotools-dev
Sobald diese Dateien vorbereitet sind, kann man den Docker-Container bauen:
$ docker build -t generic-package-build-runner:v1 .
Der Docker-Container ist nun erstellt und kann verwendet werden.
GitLab CI konfigurieren
Jetzt muss der vorbereitete Docker-Container für das aktuelle Projekt registriert werden, in dem ein Paket gebaut werden soll:
$ gitlab-ci-multi-runner register \
--non-interactive \
--url "$(GITLAB_URL)" \
--registration-token "$(CI_TOKEN)" \
--description "Generic debian wheezy package build runner" \
--executor "docker" \
--docker-image "generic-package-build-runner:v1"
Die GitLab URL und das CI Token können im GitLab-Projekt auf der Seite “Settings” > “Runners” eingesehen werden. Jedes Projekt hat sein eigenes CI-Token.
Damit GitLab CI weiss, welche Befehle im Container ausgeführt werden müssen, wird die Datei .gitlab-ci.yml
innerhalb des Repositories erstellt.
# Wird vor den Scripts in den Stages ausgeführt
before_script:
- source /etc/profile
# Definiert Stages, die ausgeführt werden sollen
stages:
- build
# Stage "build"
run-build:
stage: build
script:
- apt-get install -y libncurses5-dev libglib2.0-dev libgeoip-dev libtokyocabinet-dev zlib1g-dev libncursesw5-dev libbz2-dev
- autoreconf -fvi
- cp COPYING debian/copyright
- dpkg-buildpackage -us -uc
- mkdir build
- mv ../goaccess*.deb build/
# Diese Stage wird nur bei neuen Tags ausgeführt
only:
- tags
# Die Dateien, welche in GitLab zur Verfügung gestellt werden sollen
artifacts:
paths:
- build/*
Der wichtigste Teil dieser Datei ist die Stage run-build
. In diesem Teil wird definiert, welche Aktionen durchgeführt werden, wann diese durchgeführt werden und wo die Dateien liegen, welche durch den Build erstellt werden.
Da ein generischer Docker-Container erstellt wurde, müssen die benötigten Abhängigkeiten im ersten Schritt zuerst noch installiert werden.
Anschliessend wird der Bauvorgang mit autoreconf
vorbereitet. Dadurch wird unter anderem das Makefile erstellt, welches für den Build unerlässlich ist. Da wir das Copyright aus dem Paket übernehmen, kopieren wir dieses nach debian/
.
Mit dem Befehl dpkg-buildpackage
wird der Bauvorgang anschliessend gestartet. Dadurch wird das Paket kompiliert und das Debian-Paket erstellt. Diese Pakete werden danach in den erstellten Ordner build
verschoben und auf GitLab hochgeladen.
Workflow
Sobald wir einen neuen Release haben, wird ein Git-Tag erstellt. Durch den erstellten Git-Tag wird in GitLab ein neuer Build gestartet, welcher das Paket in der neuen Version baut.
Das erstellte Paket steht dann im Webinterface von GitLab zur Verfügung, wo es heruntergeladen werden kann.
Ausblick
Die gebauten Pakete bzw. Artifakte sollten idealerweise entsprechend automatisiert weiterverarbeitet werden, indem man diese beispielsweise auf einen Mirror hochlädt. In unserem Fall verwenden wir einen Bot, der auf Anweisung eines GitLab-Webhooks die Artifakte auf den Zielserver herunterlädt, dort einem Aptly Repository hinzufügt und das Repository entsprechend publiziert, so dass der Prozess vom Bau des Pakets bis zur Publizierung vollständig automatisiert werden kann. Das Resultat kann schlussendlich auf unserem öffentlichen Aptly Mirror eingesehen werden.