Docker mit NGINX-Proxymanager, UFW, Fail2Ban, MariaDB und Nextcloud — Teil 3

Willkommen zum dritten Teil meiner Docker-Serie. Bitte lest unbedingt auch die vorhergehenden Teile!

Der NPM ist nun via Full-Qualified-Domain-Name und einem offiziellem SSL Zertifikat von Let’s Encrypt erreichbar. Der nächste Schritt wäre nun, auch Portainer mittels offiziellem SSL Zertifikat und über HTTPS (ohne Port 9443) erreichbar zu machen.

Portainer erhält ein zusätzliches Netzwerk

Da unser NPM sich in einem 10.0.0.x Netzwerk befindet, Portainer aber noch immer mit der Docker-Standard-IP 172.17.0.x läuft, muss unser Netzwerk (10.0.0.x — bei mir mit Namen „it-yourself“) mit Portainer verbunden werden.

Dies ist mit wenigen Klicks erledigt.

  • Einloggen in Portainer
  • Auswahl von Containers (links)
  • Danach Portainer wählen (den Container)
  • Ganz nach unten scrollen
  • Bei Connected Networks das Dropdownmenü öffnen und das selbst erstellte Netzwerk auswählen (it-networker bei mir)
  • Abschließend auf Join network klicken

Von nun an, ist der Portainer mit 2 Netzwerken verbunden. Der Standardbridge (172.17.0.x) und dem benutzerdefinierten Netzwerk (10.0.0.x).

NPM – SSL Zertifikat erstellen und Host eintragen

Wir müssen jetzt via NPM einerseits ein SSL-Zertifikat erstellen und andererseits einen Hosteintrag für portainer.it-networker.at (ihr nehmt natürlich euren Sub(domainnamen) den ihr gewählt habt).

Auch das ist in wenigen Schritten erledigt.

  • Einloggen in den NPM
  • Menü SSL Certificates
  • Add SSL Certificate -> Letsencrypt (rechts)
  • Domain im „Domain Names“ Feld angeben. (nicht Return drücken, sondern unterhalb der eingabe auf „Add <……>“ klicken
  • Email-Address for Letsencrypt eintragen
  • Den „Terms of Service“ zustimmen
  • Auf Save klicken
  • Nach rund 30 Sekunden erscheint nun auch dieses SSL Zertifikat in der Übersicht

Einen Hosteintrag erstellen

Wieder befinden wir uns im NPM-Backend.

  • Auswahl von Hosts -> Proxyhost
  • Rechts auf „Add Proxy Host“ gehen
  • Domain Names: Eure Sub(Domain) bei mir portainer.it-networker.at
  • Scheme: HTTPS
  • Forwart Hostname/IP: IP oder Containername von Portainer. Bestenfalls immer den Namen nehmen. In meinem Fall: portainer
  • Forward Port: 9443
  • Block Common Exploits
  • Reiter SSL: Auswahl des zuvor erstellten SSL Zertifikates für Portainer.
  • Force SSL
  • Save

Testlauf

Nach Eingabe von https://portainer.it-networker.at (ohne Port) gelangen wir jetzt direkt zum Portainer-Login. Wie immer müsst ihr hier natürlich eure Sub(domain) nehmen.

Absicherung und eine kurze Zusammenfassung

Von außen ist nur unser NPM auf Port 80 und 443 erreichbar. Wir prüfen das mittels den aktuellen UFW-Firewallregeln. Wichtig ist, dass alle Regeln die ALLOW FWD als Action hinterlegt haben sich ausschließlich auf den Zugriff auf die Docker-Container beziehen. Standardregeln – Action: ALLOW IN, beziehen sich auf den Host und nicht auf die Container.

Nachdem wir uns via ssh auf unseren Server eingeloggt haben, tippen wir:

ufw status verbose

Abgesehen von einer ALLOW IN Regel, die uns den Zugriff auf SSH erlaubt, sollte es hier nur 2 weitere Regeln geben.

  • 10.0.0.3 ist in dem Fall mein NPM-Container (bei euch könnte der Container eine andere IP haben)
  • ALLOW FWD = Action
  • Anywhere = From
  • Also: Erlaube den Zugriff von überall her auf Port 80 und 443 des Containers mit der IP 10.0.0.3

Mehr sollte in unseren Firewallregeln nicht enthalten sein!

Zugriffssteuerung per NPM

Der NPM erlaubt es uns, den Zugriff auf die angebotenen Services einzuschränken. Dies gelingt mit sogenannten Access-Lists, die direkt im NPM angelegt werden können.

Einschränkung

Es ist NICHT möglich, Seiten die bereits eine Benutzerauthentifizierung druchführen zusätzlich via NPM-Accesslists mit User/Passwort zu schützen.  Eine Einschränkung auf IP-Adressen ist möglich. (Funktioniert nur dann, wenn man eine statische öffentliche IP hat!)

Der Grund hierfür ist:

Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the Authorization header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the Authorization header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the internet standard and almost all apps do not support multiple values in the Authorization header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.

Quelle: https://nginxproxymanager.com/faq/#do-i-have-to-use-docker

Das heißt soviel wie, dass man – sofern eine Website hat – die bereits eine Autorisierung mittels Benutzername und Passwort durchführt, nicht noch eine zweite Authorisierung mit Benutzername und Passwort (in dem Fall von NPM aus) erfolgen kann. Man hätte dann nämlich mehrfache sogenannte Authorization Headers, die bei jeder Anfrage mitgeschickt werden müssten. Dies widerspricht den Internetstandards und funktioniert somit nicht!

Sofern ihr also nicht die Möglichkeit habt, die Anfragen zu kritischen Bereichen euerer Infrastruktur zumindest auf eure statische öffentliche IP einzuschränken, wäre dies, wenn man auf Nummer sicher gehen will, eventuell per VPN zu lösen.

Zugriff auf die IP Adresse einschränken

Durch einen Klick auf das Menü Access Lists und folgend die Auswahl von „Add Access List“ kann der Zugriff auf angelegte Hosts eingeschränkt werden. Dies geschieht entweder mittels Username / Passwort (wenn möglich! siehe oben!), oder direkt via eurer öffentlichen IP. Natürlich können beide Einschränkungen auch kombiniert werden. Hier hat man dann eine Differenzierung vorzunehmen. Gemeint ist mit Differenzierung der Parameter Satify Any, im Zuge der Erstellung einer Access-List.

Wie oben ersichtlich, will ich eine IP Zugriffsliste erstellen. Der Parameter Satisfy Any ist deaktiviert. Was bedeutet das?

Angenommen, ihr würdet hier nur einen Benutzer&Passwort anlegen und die IP-Settings auf den Standardeinstellungen belassen. IP Seitig wären dann alle IPs auf „Deny“ = verweigern. Selbst wenn ihr Usernamen und Passwort korrekt angebt, könnt ihr euch deshalb nicht einloggen. (Es müssen beide Kriterien zutreffen)

Setzt man aber den Parameter Satisfy Any auf ON (Eingeschaltet), so reicht es, wenn entweder Username und Passwort angegeben werden, oder die IP Regel stimmt.

Das heißt also: Sobald die User/Passwortkombination ok ist, funktioniert der Einstieg.

Wir wollten aber eine Einschränkung auf IP-Addresse vornehmen und belassen den Schalter „satisfy any“ auf aus / off.

  • Im Reiter „Access“ fügen wir im Feld „allow“ unsere öffentliche statische IP hinzu.
  • Und klicken auf Save

Die angelegte Access-List kann dann einem Host hinzugefügt werden.

  • Im Reiter Hosts -> Proxyhost des NPM, bearbeiten wir einen bereits angelegten Host (=Drei Punkte rechts des Hosteintrages anklicken -> EDIT).
  • Gleich im ersten erscheinenden Fenster (Edit Proxy Host) ist nun unten unsere Access-Liste zu wählen. (Dropdown-Menü)

 

  • Abschließend mit „Save“ speichern

Schon ist der Zugriff auf unseren NPM-Container auf unsere IP eingeschränkt. Somit kann niemand (mit anderer IP) auf die Seiten zugreifen.

Hier  geht’s zu Teil 4…

Schreibe einen Kommentar

* Zustimmung zur Datenspeicherung lt. DSGVO

*

Ich bin damit einverstanden