Vorinitialisierter FTP-Server in Docker

Bevor hier jetzt einige gleich aufschreien für was man eine derartig krude Sache überhaupt brauchen kann, es gibt durchaus Fälle in denen etwas derartiges nützlich ist. Mir ist durchaus bewusst, dass FTP (ohne TLS) kein wirklich aktueller Standard mehr ist und auch das Protokoll mit der “out-of-band”-Regelung mit getrennten Ports etwas altbacken wirkt. Besser wäre es natürlich hier auf SFTP (welches als Basis SSH nutzt und somit direkt Verschlüsselung anbietet) zu nutzen. Zudem wurde ja auch schon mehrfach angekündigt, dass immer weniger Browser FTP nativ unterstützen wollen. Das Protokoll hat sich schlichtweg etwas überlebt, aber es ist leider in ganz vielen Bereichen immer noch im Einsatz – und genau dafür benötigte ich diese Konstellation: Für ein Projekt bei dem ich im Rahmen der Tests sicherstellen muss, dass FTP-Verbindungen bzw. die Verarbeitung von per FTP bereit gestellten Dateien wie erwartet funktionieren. Bisher habe ich mir dafür immer eine virtuelle Maschine in der Hinterhand gehalten und diese dann entsprechend hochgefahren bzw. konfiguriert. Das geht auch auf einem CI/CD-System wie Jenkins, aber schicker wäre es doch wenn man einfach ein Image starten kann (vorzugsweise in einem gekappselten  Netzwerk) und die Konfiguration und ggf. sogar schon die notwendigen Testdaten liegen fix und fertig bereit.

Insgesamt muss ich leider sagen: Diese Nuss hat mich mehr Nerven gekostet als gedacht.

<pre>FROM fauria/vsftpd

COPY ftp-custom-dir-list /tmp/
COPY ftp-user-list /etc/vsftpd/user-list
COPY init_users_and_directories.sh /tmp/
COPY vsftpd.conf /etc/vsftpd/vsftpd.conf

RUN chmod +x /tmp/init_users_and_directories.sh && mkdir -p /var/log/vsftpd/
RUN /tmp/init_users_and_directories.sh

ENTRYPOINT ["/usr/sbin/vsftpd"]
CMD ["/etc/vsftpd/vsftpd.conf"]

Hier sind einige Kleinigkeiten versteckt die man beachten muss: Das aufgerufene Skript kümmert sich letztlich während des Bauens des Images darum, dass die notwendigen Verzeichnisse angelegt werden und die Benutzerliste in eine Berkeley-DB überführt wird, damit sie später zur Authentifizierung genutzt werden kann. Das Format gilt es hierbei zu beachten: Immer abwechselnd Benutzername und Passwort in einer Zeile.

<pre>db_load -T -t hash -f /etc/vsftpd/userlist /etc/vsftpd/virtual_users.db</pre>

Es gibt noch einige Kleinigkeiten, die einem ggf. das Leben schwer machen. Zum einen ist VSFTP nicht wirklich ein gesprächiges Programm, ich habe auch mit sehr viel Suchen keine Möglichkeit gefunden in irgendeinem Log mehr als die FTP-Verbindungen zu finden, geschweige denn irgendwelche Aussagen warum es initial mit der Authentifizierung nicht so ganz klappen wollte.

Authentifizierung ist ein gutes Stichwort: Wie man hier sieht habe ich auf die Verschlüsselung der Passwörter verzichtet. Für das angestrebte Ziel einen Testserver zu haben auf dem man Dateien ablegen zum Testen ablegen kann und den man hinterher wieder wegwirft ist das gerade noch zu verschmerzen, für die Produktion ist ein deratiges Vorgehen definitiv nicht geeignet! Hier darf man sich dann aber mit den Wirren von PAM (plugable authentification module) herum schlagen, auch dieses Tool ist zumindest im Docker-Umfeld eher schweigsam und verrät sicherheitsgerichtet nicht wirklich was gerade schiefläuft.

Wer sich das von mir verwendete Basis-Image anschaut wird feststellen, dass es eigentlich auch noch diverse Parameter gibt, die man dem Container mitgeben könnte. Das habe ich allerdings lahmgelegt, denn für meinen Anwendungsfall benötige ich ja stets ein einheitliches Set an Benutzern und Verzeichnissen. Selbst wenn ich den Container beim Testen mit docker-compose hochfahren würde, bekäme ich so nicht die Kohäsion die ich mir speziell für diesen Fall wünschen würde: Einmal bauen und alles ist für den spezifischen Anwendungsfall schon vorbereitet.

Damit es mit verschlüsselten Passwörtern klappt, muss man folgende Punkte beachten:

Passwörter kann man sich mittels folgendem Befehl in Hashes umwandeln lassen:


openssl passwd -1 meintollesPasswort

Wenn man es stärker automatisieren möchte kann man sich das natürlich auch in ein Skript packen welches die Datei der User durchackert und das automatisch macht. Ganz wichtig ist aber dann auch die Anpassung der PAM-Konfiguration

<pre>#%PAM-1.0
auth   required   pam_userdb.so  db=/etc/vsftpd/virtual_users crypt=crypt
account    required   pam_userdb.so  db=/etc/vsftpd/virtual_users crypt=crypt
session    required   pam_loginuid.so

Man muss PAM hier mitteilen, dass die Passwörter in verschlüsselter Form vorliegen. Nicht wundern, dass ich oben nicht mit crypt als Methode im Zusammenhang mit openssl gearbeitet habe: Crypt ist dort die Urform des Hash-Algorithmus für Passwörter. Aus historischen Gründen dürfen Passwörter dort nur 8 Zeichen lang werden. Hier sei nochmals darauf hingewiesen, dies betrifft nur die Art und Weise wie die Passwörter auf dem Server gespeichert werden, die Übertragung bei FTP erfolgt weiterhin ohne Veschlüsselung – hier muss man ggf. mit VPN oder anderen Mechanismen nachhelfen (oder eben gleich SFTP einsetzen).

Wer genau aufgepasst hat, wird feststellen, dass in der PAM-Konfiguration scheinbar ein Fehler ist (und dieser hat mich lange beschäftigt). Es ist aber richtig: die Datei muss auf .db enden, die Referenz für pam_userdb.so muss aber ohne dieses Suffix erfolgen. Wer auch immer sich das ausgedacht hat – wirklich gut dokumentiert ist es auf keinen Fall.

 

IPv6 – Wer hat Angst vor langen IP-Adressen?

Nachdem ich ja in einigen Posts nunmehr beschrieben habe wie man sich einen eigenen DNS-Server unter Docker mit samt IPv6 hinstellen kann (inkl. einer Rückwärtskompatibilität für IPv4) habe ich mich gefragt was denn noch so problematisch ist am Umstieg auf IPv6. Mein derzeitigen, subjektiven Ergebnisse fasse ich hier einmal zusammen. Vorsicht dieser Post kann ggf. Spuren von Zynismus, Sarkasmus und auch einen Schuß Frustration meinerseits enthalten.

Natürlich ist derartige Kritik leicht daher geredet, daher werde ich auch einige Lösungen bzw. Lösungsansätze vorstellen.

Continue reading

DNS mit Docker Teil III – dnsdist als Router / Loadbalancer

Wer meine bisherigen Posts zu Docker und DNS verfolgt hat, weiß: Da steht noch was aus (ich komme nur momentan nicht immer ganz zeitnah dazu meine Erfahrungen zusammen zu schreiben.

Was bisher geschah:

Was jetzt noch aussteht ist eine Sache die mit der Microservice-Architektur von PowerDNS im Vergleich zu “klassischen” Nameservern wie BIND zusammen hängt: BIND ist monolitisch und kümmert sich um jegliche Anfrage die gestellt wird. In PowerDNS hat man diese Dinge wie oben bereits angedeutet aufgetrennt: Einen Spezialisten zum Auflösen von externen Einträgen (Recursor) und einen weiteren Prozess der sich um die Sachen kümmert für die man selbst verantwortlich ist (authorative). Continue reading

Anwendungsfall für MSSQL in Docker unter Linux

Wie in einem meiner letzten Beiträge beschrieben, kann man mittlerweile einen MSSQL-Server auch unter Linux in Docker laufen lassen. Nun gilt es noch die berechtigte Frage zu klären: Weshalb sollte man sowas tun? Gibt es für dieses Konstrukt überhaupt sinnvolle Anwendungsfälle? Für alle die es eilig haben: Ja die gibt es. Wer es im Detail wissen will sollte weiter lesen.

Der Anwendungsfall für mich hängt indirekt auch mit der Jahreszeit zusammen, wie in jedem Jahr fällt mir als Schriftführer unseres Sportvereins die Aufgabe zu, mich um den Versand der Jahreszeitschrift zu kümmern. Man könnte es auch eine Alternative zu Weihnachtskarten nennen. Für die Verwaltung des Vereins haben wir eine fertige Software die leider nicht open source ist, geschweige denn dass sie nativ unter Linux laufen würde. Aus Sicht eines Anwendungsentwicklers ist die Software nicht gerade optimal, aber sie ist nunmal da und die anderen Mitglieder des Vorstands sind damit vertraut. Mal eben etwas zu ändern ist an dieser Stelle nicht drin.

Continue reading

MSSQL-Server mit Docker unter Linux

Der Titel hört sich im ersten Moment etwas schräg an – insbesondere wenn man zu den etwas älteren Semestern gehört, die noch die Anfeindungen Microsofts in Richtung Linux kennen gelernt haben. Unter anderem mit Werbesprüchen wie “ein freies Betriebssystem hat nicht nur Vorteile” – verbunden mit einem Bild welches Piguine als Repräsentanten von Linux zeigte mit nicht ganz passenden Köpfen. Das war 2001 und geworben wurde für Windows 2000. Die Zeiten haben sich geändert und mittlerweile gibt es sogar offizieller Weise ein “Windows Subsystem for Linux” (WSL) und auch erfreuliche Entwicklungen hin zu einer deutlich brauchbareren (Power-)Shell als es die altgediente command.com bzw. cmd.exe je waren. Das Ganze kommt nicht ganz von ungefähr – mit der Microsoft Azure Cloud mussten Werkzeuge her mit denen man Systeme vernünftig remote administrieren kann – da ist es durchaus legitim einmal zu schauen was bei anderen Betriebssystemen für den Erfolg mit verantwortlich ist.

Continue reading

Domain Name Server mit PowerDNS – Schritt 1 – Konzept, Netzwerk und Authorative Server

Nachdem ich ja schon einiges in der letzten Zeit über DNS und Co geschrieben habe, geht es diesmal um eine konkrete Umsetzung. Lange Zeit habe ich schon einen eigenen DNS-Server betrieben, damals noch mit BIND. Mit den letzten Serverumzügen habe ich das dann der Einfachheit halber meinem Hosting-Anbieter überlassen (das richte ich ein, wenn der Rest läuft …). Wie das mit aufgeschobenen Aufgaben so ist, irgendwann wird der Status Quo zu einen “Dauerorium” (die verstetigte Version eines Provisoriums).

Nun wollte ich es endlich angehen, und dabei auch einige zusätzliche Funktionen nachzurüsten. Unter anderem einen eigenen Ipv6 fähigen DynDNS-Service. Nach etwas Recherche stand ein grober Plan:

  • PowerDNS mit MySQL Backend
  • MySQL Server (läuft bereits, bekommt nur ein zusätzliches Schema)
  • Ein (Dyn)DNS-Frontend zur einfacheren Verwaltung und als HTTP(s) Schnittstelle zum Updaten
  • Microservice-Ansatz für die Einzelteile mit Docker als Paravirtualisierung
  • soweit möglich alles nativ in IPv6

Continue reading

Container und IPv6 – Basics zum Verständnis / Netzwerkzuschnitt

In diesem Beitrag erläutere ich erst einmal die grundlegenden Probleme welche sich beim Einsatz von Container-Lösungen im Netzwerk ergeben und wie man sie sinnvoller Weise technisch lösen kann. Schlüssel hierfür ist die Verwendung von IPv6 anstelle von IPv4. In einem weiteren Artikel beschreibe ich dann die konkrete Umsetzung. Wer sich mit IPv6 und Containern bereits sicher fühlt kann diesen Artikel ggf. überspringen.

Container sind der aktuelle Stand der Technik was die Auslieferung und die Laufzeitumgebung für Serversoftware betrifft. Die Para-Virtualisierung löst einige Probleme die man typischer Weise hatte, unter anderem das Alles-oder-Nichts-Problem, wenn es darum geht Systemsoftware zu aktualisieren. Mit jedem größeren Versionssprung gibt es die Gefahr, dass bestimmte Teile des eigenen Codes nicht mehr laufen. Aktuell gibt es immer noch genügend Projekte und Software welche auf ältere (um nicht zu sagen teilweise uralte) Versionen von PHP angewiesen sind um zu funktionieren. Mit dem Versionssprung von 5.x nach 7.0 sind einige Altlasten und Funktionen über Bord geworfen worden, unter anderem auch der gesamte Stack für die MySQL-Anbindung, was einigen Anwendungen dann doch das Genick bricht. Häufig stand man nun vor dem Problem, für einen Teil des gehosteten Angebots die Version anheben zu wollen, aber die Altlasten müsste man dafür erst einmal auf Stand bringen. Das ist nicht immer ohne weiteres möglich. Mit Containern schafft man sich hier ggf. kleinere Services mit jeweils ihrer maßgeschneiderten Umgebung – inklusive abgeschottetem Datenbankserver, den sich nicht mehr alle Angebote teilen müssen (über die Vor- und Nachteile von Datenbanken in Containern kann man einen eigenen Artikel schreiben).

Continue reading