Das ganze Internet im privaten Netzwerk – Teil 2

Alles im LAN: Portainer, Nginx Proxy Manager und Docker absichern, TLS, DNS, Domain Routing, Ports schließen, IT-Security, Network, SOHO, Cloud – How To.

Das Dokument enthält eine Anleitung für die Absicherung von Docker, Portainer und Nginx Proxy Manager mit Zertifikaten und durch Schließen von offenen Ports. Die Anwendung läuft auf einer Workstation innerhalb eines privaten Netzwerks. Die Konstruktion dieses Netzwerks ist Thema im ersten Teil des Dokuments.

Die Fokussierung auf spezielle Dienste und Sicherheitsmechanismen hat einen Grund. Oftmals in einem lokalen Netzwerk vernachlässigt, soll das Dokument zeigen, dass es durchaus sinnvoll ist, sich damit vertraut zu machen.

Denn mit der Virtualisierung und zunehmenden Containerisierung führt der Weg zu öffentlichen Instanzen und in die Cloud. Und für die Container-Orchestrierung sind Portainer und Nginx Proxy Manager wirklich fantastische Werkzeuge. Spätestens in diesem Umfeld ist es höchst riskant, technisch mögliche Sicherheitseinstellungen nicht zu kennen oder darauf zu verzichten.

Vorbereitungen

Zielgerät für die Installation ist eine Workstation mit einem Ubuntu Server als Betriebssystem. Zur Veranschaulichung wird LAN-3 aus dem vorherigen Beispiel als Serverstandort angenommen.

Auf dieser Maschine laufen allerdings schon mehrere virtuelle Server mit einem Apache Webserver. IP-Adressen von 192.168.32.140 bis 192.168.32.149 sind bereits vergeben. Diese Konstellation stellt eine zusätzliche Herausforderung dar. Denn Apache, Docker und Nginx Proxy Manager konkurrieren um die gleichen Ports 80 bzw. 443. Trotzdem sollen die Programme laufen, ohne Konflikte oder Kollisionen.

Deshalb bekommt das Interface der Workstation zusätzlich eine neue IP-Adresse, zum Beispiel

192.168.32.150

Docker erkennt und berücksichtigt die von der Workstation bereits genutzten Adressen automatisch. Letztlich ist der Proxy Manager vorgeschaltet und agiert noch vor den anderen Diensten. Er verteilt die Anfragen auf die Docker-Container. Daher wird eine neue, freie IP-Adresse benötigt, auf der nicht schon andere Dienste laufen. Ein Interface mit mehreren IP-Adressen ist ein Sonderfall in diesem Beispiel.

Typischerweise würde man auf einem separaten, „frischen“ Server, nach der Docker Installation, den Webserver in einem Docker Container errichten. In diesem Beispiel laufen Apache und Docker parallel. Das Experiment zeigt aber, dass Apache und Nginx Proxy tatsächlich nebeneinander laufen können. Es bedarf jedenfalls auch zusätzliche Änderungen der Konfigurationen vom Apache Server.

So, damit genug Verwirrung gestiftet. Die nächsten Installationsschritte und Einstellungen sind im Grunde immer gleich. Auf der Workstation in diesem Beispiel, auf einem neuen, „frischen“ Server, auf einem öffentlichen Root-Server oder auf einem Virtual Privat Server (VPS) oder in der Cloud. Im Vordergrund steht schließlich die Absicherung der Installation.

Installation

Docker

Nächster Schritt ist die Installation von Docker auf dem System. Dafür gibt es sehr gute Anleitungen. Jetzt besteht die Möglichkeit, Docker Images zu laden und Container zu erstellen.

Portainer

Portainer ist der erste Container. Dabei kommt die freie Community Edition zum Einsatz. Portainer CE ist eine großartige, freie Open Source Software mit einer grafischen Oberfläche für die Verwaltung von Docker Containern. Seine Installation erfolgt über das Terminal. Aber zuvor erstellt man ein separates Docker Volume, damit die Einstellungen von Portainer nicht verloren gehen. Das Volume trägt die entsprechende Bezeichnung portainer_data.

docker volume create portainer_data

Danach wird das Portainer-CE Image geladen und ein Container mit dem Namen portainer erstellt:

docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

Portainer ist über Port 8000 sowie 9000 erreichbar. Zur Administration gelangt man mit der IP-Adresse (localhost) und Port 9000. In diesem Beispiel lautet die Adresse:

http://192.168.32.150:9000
http://127.0.0.1:9000

Bei der erstmaligen Anmeldung muss man das Konto für einen Administrator einrichten. Das Setup ist damit schon abgeschlossen. Neue Docker Container können nun mit Hilfe von Portainer sehr leicht orchestriert werden. Dazu kopiert man den Inhalt einer Docker Compose Datei in Portainer und erzeugt daraus einen neuen Stack.

Weitere Einstellungen und Konfiguration

Endpoint

Auf der Workstation sind mehrere Interfaces aktiv. Portainer soll aber nur auf dem Endpoint mit der IP-Adresse 192.168.32.150 aktiv sein. Auf einem öffentlich zugänglichen Server trägt man die öffentliche Server IP ein.

In dieser Phase läuft Portainer auf einer IP mit einem exponierten Port. Auf einem öffentlichen Server verfügt diese Installation über keinen ausreichenden Schutz. Daher folgen weitere Schritte zur Anpassung.

DNS und Subdomain

Zur Absicherung des Servers braucht man einen Domain und ein Zertifikat. Da in dem lokalen Netzwerk ein DNS-Server, eine eigene Zertifizierungsstelle und Zertifikate vorhanden sind, lassen sich die nächsten Schritte schnell umsetzen.

In den Zonendateien fügt man für die IP-Adresse 192.168.32.150 den gewünschten Subdomain als A-Record oder CNAME ein. Das gleiche entsprechend für den Reverse DNS.

Die Verbindung gelingt nun mit dem Domain Namen und dem Port, zum Beispiel

http://portainer.its-my.lan:9000

Ein gemeinsames Docker Netzwerk für Portainer und Nginx Proxy

Proxy und Portainer müssen gemeinsam ein und dasselbe Docker Netzwerk nutzen. In diesem SInne erstellt man ein neues Netzwerk am besten vor der Installation des Nginx Proxy Managers.

Mit dem folgenden Befehl im Terminal erscheint eine Auflistung aller vorhandenen Netzwerke

docker network ls

Docker Netzwerke lassen sich mit Portainer erstellen oder im Terminal. In diesem Beispiel heißt das Netzwerk proxynet.

Damit Portainer auch diesem Docker Netzwerk beitritt, klickt man in Portainer auf die Liste der Container, wählt dann den Portainer Container und wählt schließlich unter „Netzwerk beitreten“ das Netzwerk proxynet aus.

Kurzer Zwischenstand

Portainer läuft „frisch“, bedeutet überwiegend mit Standardeinstellungen, hat Zugriff auf das Netzwerk proxynet, ist über eine Domain und Port 9000 erreichbar. Jetzt fehlt noch eine Verschlüsselung. Und der exponierte Port sollte geschlossen werden. Was den Port betrifft, ist Schutz durch eine Firewall vorstellbar. Aber besser ist es, den Port erst gar nicht zu öffnen, beziehungsweise nicht nach außen zu exponieren. Unter anderem für diese Punkte kommt nun Nginx Proxy Manager ins Spiel.

Installation von Nginx Proxy Manager als Container Stack

Ausgangspunkt für den zweiten Container Stack mit dem Nginx Proxy Manager ist das Docker Compose File von jc21 auf Github. Man erkennt, dass der Proxy auch eine MariaDB Datenbank benötigt. Die Angaben passt man den eigenen Bedürfnissen an. Wichtig ist es, in der YAML-Datei das gemeinsame Netzwerk einzutragen.

version: '3'
networks:
  default:
    external:
      name: proxynet
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: npm
...

Anschließend den Inhalt der Compose Datei kopieren und in Portainer einfügen. Danach kann man den neuen Stack erstellen. Unter Docker laufen jetzt zwei Container mit Portainer und Nginx Proxy Manager.

Nginx Proxy Manager einrichten

Der Proxy lauscht auf Port 81. Mit dem Benutzernamen admin@example.com sowie mit dem Password changeme kann man sich mit dem Admin Interface verbinden. Die Adresse lautet:

http://192.168.32.150:81/

Direkt nach dem erstmaligen Login muss man zuerst die Anmeldung für den Administrator einrichten.

SSL-Zertifikate

Unter dem Menübefehl „SSL-Zertifikate“ kann man Zertifikate hochladen.

In diesem Schritt lädt man die Zertifikate hoch, die zuvor mit Easy-RSA erstellt wurden. Oder man erzeugt neue Zertifikate für die geplanten Anwendungen bzw. Subdomains. Einfacher ist es mit einem Wildcard Zertifikat.

Proxy-Host für Portainer einrichten

Nach all diesen Vorbereitungen kann man mit der Einrichtung von Proxy-Hosts beginnen. In diesem Beispiel ist der erste Proxy Host für Portainer.

Er bekommt den Domain Namen portainer.its-my.lan.

Für Scheme http auswählen, da Docker intern über unverschlüsselte Ports weiterleitet. Im Eingabefeld „Forward Hostname“ trägt man den Containernamen „portainer“ ein. An dieser Stelle könnte auch die interne Docker-IP stehen. Als Weiterleitungsport trägt man 9000 ein. Zur Sicherheit auch „Block Common Exploits“ aktivieren.

Anschließend auf die Einstellungen für SSL klicken.

In der Liste wählt man das zuvor hochgeladene Wildcard Zertifikat aus.

Danach aktiviert man den HTTP/2 Support und sichert die Einstellungen für den Proxy Host.


An diesem Punkt steigt die Spannung. Denn man kann jetzt prüfen, ob eine Verbindung zu Portainer möglich ist. Anstatt mit der IP sollte es aber jetzt mit einer verschlüsselten Verbindung und mit dem Domain Namen funktionieren:

https://portainer.its-my.lan

Der Weg der Anfrage läuft zuerst zum lokalen DNS-Server, von dort zur Workstation mit dem Nginx Proxy Manager und von dort zum Docker Container. Also gut, der erste Proxy läuft.

Proxy Host für Nginx Proxy Manager einrichten

Nach dieser Methode erstellt man den zweiten Proxy Host, für Nginx jetzt selbst. Das ist ein ganz wichtiger Schritt, um Nginx Proxy Manager abzusichern.

Er bekommt den Domain Namen myproxy.its-my.lan.

Aber nicht vergessen, den passenden CNAME (z.B. myproxy) auch im DNS einzutragen!
Den Host richtet man wieder mit seinem Container Namen (z.B. npm) ein. Weiterleitungsport ist in diesem Fall die 81. Nun noch das Zertifikat (Wildcard) auswählen, und dann die Einstellungen speichern.


Schon wieder ein spannender Moment. Jetzt kann man prüfen, ob eine Verbindung zum Proxy Manager möglich ist. Wieder sollte es, anstatt mit der IP, jetzt mit einer verschlüsselten Verbindung und mit dem Domain Namen funktionieren:

https://myproxy.its-my.lan

Ein Sicherheitsproblem

Bei dieser Installation besteht momentan noch ein Sicherheitsproblem, denn die Hintertüren stehen noch sperrangelweit offen. Schutz durch Verschlüsselung ist nur gewährleistet mit einer Verbindung über die Domäne. Aber gleichzeitig sind Zugriffe auf den Server noch über seine IP-Adresse und die exponierten Ports möglich.

Im Terminal kann man dies z.B. mit netstat überprüfen.

netstat -tapne

In der Liste erkennt man unter anderem die Server IP und die geöffneten Ports 9000 und 81. Dort werden Angriffe auf den Server ansetzen, zum Beispiel Brute-Force-Attacken oder Man-in-the-Middle-Angriffe.

Lösung: Exponierte Ports schließen

Direkt nach der Ersteinrichtung muss man die Container neu starten, ohne dabei diejenigen Ports zu exponieren, die man nicht mehr benötigt. Auf der Ebene vom Docker Netzwerk sind sie weiterhin geöffnet. Und Nginx Proxy Manager, das ist seine Aufgabe, leitet alle Anfragen direkt dort hinein.

Zur Verbesserung der Systemsicherheit diesen Schritt nicht vergessen!

Folglich muss man die Einstellungen und die Container für beide, Portainer und Proxy Manager, erneuern. Das ist nicht so kompliziert, denn alle bisherigen Einstellungen sind in den ausgelagerten Volumes gespeichert. Dort sind sie konserviert. Mit anderen Worten, man muss die Container nur mit anderen Parametern neu starten.

Hier muss man aufpassen. Zur Erinnerung: Portainer wurde über das Terminal erstellt. Im Gegensatz dazu wurde der Proxy aber als Stack in Portainer erzeugt.

Das bedeutet, die Änderungen für Portainer macht man wieder im Terminal. Und wenn Portainer danach wieder läuft, kann man die Änderungen für den Proxy Manager innerhalb von Portainer vornehmen.

Also, im Terminal zuerst den Container von Portainer stoppen:

docker stop portainer

Den Container danach entfernen:

docker rm portainer

Von Docker nicht mehr benötigte Docker Images könnte man im Terminal löschen. Aber das kann man auch später erledigen, mit Portainer, wenn er wieder läuft. Überflüssige Docker Images sind damit viel leichter zu erkennen.

Vor der Aktualisierung von Portainer, sollte man sich an das spezielle Docker Netzwerk erinnern, welches man für Portainer und für den Proxy eingerichtet hatte.

docker network ls

In der Liste sieht man bridge, host, none, und zuletzt proxynw. Der Netzwerkname proxynw ist ein weiterer Parameter in dem Befehl, um den Container zu starten. Aber die Angaben zu Port 9000 lässt man weg.

Folglich lautet der Befehl:

docker run -d -p 8000:8000 --network proxynw --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

Da auf der Workstation mehrere IP-Adressen auf einem Interface eingerichtet sind, muss man den Befehl in diesem Fall noch genauer anpassen:

docker run -d -p 192.168.32.150:8000:8000 --network proxynw --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

Sollte man vergessen haben, die IP-Adresse mit dem Port zu verbinden, kann man es auch in Portainer nachträglich einstellen:

Eine kurze Erklärung

Docker erstellt unter der IP-Adresse 192.168.32.150 im Docker-Netzwerk proxynw einen neuen Container mit dem Namen portainer von der aktuellsten Portainer Version (Community Edition). Der Container startet immer automatisch. Aber nur der unbedenkliche Port 8000 ist noch exponiert.


Zeit für einen erneuten Test.

Eine Verbindung zu Portainer sollte nur noch über die Domäne möglich sein. Aber Anfragen mit der IP-Adresse 192.168.32.150:9000 werden jetzt abgewiesen.

Das sieht gut aus. Jetzt muss man auch noch den exponierte Port 81 vom Proxy Manager schließen.

Dazu meldet sich der Administrator in Portainer an.

https://portainer.its-my.lan

In den Einstellungen von dem Stack für den Nginx Proxy Manager kann man die Zeile mit dem Port 81 auskommentieren.

    ports:
      - '192.168.32.150:80:80'
#      - '192.168.32.150:81:81'
      - '192.168.32.150:443:443'
    environment:
...

Durch den Klick auf „Update the stack“ startet man den Proxy-Container neu. Aber diesmal, ohne Port 81 zu öffnen.

Auch das kontrolliert man anschließend. Anfragen mit der IP-Adresse http://192.168.32.150:81/ sind nun ebenfalls nicht mehr möglich und werden abgewiesen.

Damit ist der unsichere Management-Port von Nginx Proxy Manager ebenfalls geschlossen. Eine Anmeldung am Admin Interface ist jetzt nur noch über eine sichere Verbindung, über die Domain möglich:

https://myproxy.its-my.lan

Remote Cluster verwalten

Die Anwendung von Portainer zeigte die Einrichtung von Containern an einem lokalen Endpunkt. Aber das großartige ist, dass man Remote Instanzen als Endpunkt anlegen kann. Es gibt Schnittstellen zu Portainer Agenten, Docker API, Kubernetes Clustern und zu Azure ACI. Mit Portainer lassen sich Schwärme von Containern in entlegenen Clustern verwalten. Das ist Thema eines anderen Tutorials.

Zusammenfassung

Die exponierten Management-Ports zu schließen ist ein unerlässlicher Schritt, um die Sicherheit zu verbessern. Wenn man diese Konzepte bereits bei der Entwicklung innerhalb des LAN berücksichtigt, ist es umso wahrscheinlicher, dass man die Schutzmaßnahmen bei Projekten auf öffentlichen Servern nicht vergisst.

Die Einrichtungsschritte bleiben die gleichen. Die einzigen Unterschiede, abgesehen von der IP-Adresse des öffentlichen Servers, bestehen bei DNS und Zertifikaten. Alle DNS-Einstellungen müssten in einem öffentlichen DNS-Server stehen. Und für die Zertifikate würde man z.B. Let’s Encrypt nutzen.

Im Übrigen, die Verwaltung von Zertifikaten ist mit dem Nginx Proxy Manager unglaublich einfach! Zwei Klicks, fertig. Sogar die regelmäßige Aktualisierung bzw. Erneuerung der Zertifikate funktioniert automatisch.

Abschließende Hinweise

In einem privaten Netzwerk, LAN oder Intranet sind derartige Schutzvorrichtungen nicht zwingend erforderlich aber auch nicht auf die Schnelle zu realisieren. Sich mit den Prinzipien und Verfahren vertraut zu machen, ist aber sinnvoll und vorteilhaft. Deshalb gibt Teil 1 der Dokumentation Hinweise und zeigt Lösungswege, wie man Technologien aus dem öffentlichen Internet im lokalen Netz nutzen kann. Themenschwerpunkt sind professionelle Dienste in einem privaten Netzwerk, DNS-Server, eigene Zertifizierungsstelle, beziehungsweise Certificate Authority (CA), TLS-Zertifikate usw.

Noch nie gab es so großartige Software, wie heute. Man sollte sie nutzen und das Internet damit zu einem sichereren Ort machen.

Quellenangaben

Titelfoto (barbeitet) stammt von Solen Feyissa auf Unsplash