Die Version des Reverse Proxy mit OneLogin wird um einen vorgelagertem Load Balancer und einem zweiten Reverse Proxy erweitert:
Docker Compose
version: '3.8' services: loadbalancer: build: ./loadbalancer hostname: loadbalancer volumes: - ${PWD}/loadbalancer/conf/loadbalancer_httpd.conf:/usr/local/apache2/conf/httpd.conf - ${PWD}/loadbalancer/conf/loadbalancer.conf:/usr/local/apache2/conf/loadbalancer.conf ports: - 80:80 reverseproxy_1: build: ./reverseproxy hostname: reverseproxy_1 volumes: - ./reverseproxy/public_html:/usr/local/apache2/htdocs - ${PWD}/reverseproxy/conf/reverseproxy_httpd.conf:/usr/local/apache2/conf/httpd.conf - ${PWD}/reverseproxy/conf/reverseproxy.conf:/usr/local/apache2/conf/reverseproxy.conf reverseproxy_2: build: ./reverseproxy hostname: reverseproxy_2 volumes: - ./reverseproxy/public_html:/usr/local/apache2/htdocs - ${PWD}/reverseproxy/conf/reverseproxy_httpd.conf:/usr/local/apache2/conf/httpd.conf - ${PWD}/reverseproxy/conf/reverseproxy.conf:/usr/local/apache2/conf/reverseproxy.conf showheaders: build: ./showheaders hostname: showheaders
Ich hatte zuerst versucht, den Reverse Proxy über scale zu vervielfältigen, aber das funktionierte nicht, da jeder RP den selben Hostnamen zugewiesen bekommt.
Laut Forenkommentaren soll man das Problem wohl mittels Scripte oder Docker Swarm lösen können, für dieses kleine Projekt war es hingegen völlig ausreichend, den Block für den RP zu duplizieren.
Load Balancer
Neu hinzugekommen ist der den beiden RPs vorgeschaltete Load Balancer.
Die Regel, nach der das Loadbalancing erfolgt, ist hier nicht relevant und wird nicht explizit gesetzt.
Der erste Versuch, bei dem die Anfragen abwechselnd auf den RPs verteilt werden funktioniert für die public Pages.
[...] <Proxy "balancer://myreverseproxy"> BalancerMember http://reverseproxy_1:80 BalancerMember http://reverseproxy_2:80 </Proxy> ProxyPass / balancer://myreverseproxy/ ProxyPassReverse / balancer://myreverseproxy/ [...]
Die geschützten Seiten ließen sich nicht öffnen.
Der Login bei OneLogin funktioniert, aber nicht das öffnen der Seite. Anscheinend harmoniert der OneLogin Flow nicht mit diesem Setup, es scheint so, als ob die Antwort der Anfrage von RP1 an OneLogin von RP2 erhalten wird, dieser aber nichts damit anfangen kann und eine neue Authentifizierungsanfrage an OneLogin schickt, deren Antwort wiederum von RP1 erhalten wird , dieser aber nichts damit anfangen kann und eine neue Authentifizierungsanfrage an OneLogin schickt, deren Antwort wiederum von RP2 erhalten wird , dieser aber nichts damit anfangen kann und eine neue Authentifizierungsanfrage an OneLogin schickt, deren Antwort wiederum von RP1 erhalten wird, [...]
Es ist also notwendig, das wir immer auf dem selben RP landen. Das Load Balancing darf nur einmal am Anfang statt finden.
Um das zu erreichen, setzten wir einen Header, der die Route zum RP enthält und setzten die Session sticky.
[...] ## Header for LoadBalancer Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED #define loadbalancer for Applicationserver <Proxy "balancer://myreverseproxy"> BalancerMember http://reverseproxy_1:80 route=reverseproxy_1 BalancerMember http://reverseproxy_2:80 route=reverseproxy_2 ProxySet stickysession=ROUTEID </Proxy> ProxyPass / balancer://myreverseproxy/ ProxyPassReverse / balancer://myreverseproxy/ [...]
Test
Über die Logausgaben in dem Terminalfenster, in dem Docker Compose gestartet wurde, kann man gut nachvollziehen, welche Server aufgerufen werden:
In der ShowHeaders Anwendung können wir sehen, welche ROUTEID gesetzt wurde und über den x-forwarded-host können wir die Route nachvollziehen.
In obigem Beispiel sind wir über RP2 gekommen. Wenn wir den ROUTID Cookie auf RP1 ändern, wird die nächste Anfrage über RP1 gerouted.
GitHub
Die Dateien zu diesem Post sind im OneLogin-GitHub-Projekt unter version3 zu finden.
Getrennte Netze
Im nächsten Schritt möchte ich verschiedene Netzwerke und Server verwenden.
Der User kommt aus dem Internet und geht über den Load Balancer in die DMZ, in der er über die RPs Zugang zu den Public Servern hat und nach Authentifizierung über OneLogin (Internet) gelangt er in das Interne Netz wo er Zugang auf den ShowHeaders und die Privaten Server hat.
Vorbereitet wird auch schon die Authorisierung über die RPs und OneLogin: Falls der Benutzer die Rolle user hat, bekommt er Zugang auf den User Server, falls er die Rolle admin hat, bekommt er Zugang auf den Admin Server.
In der Docker Compose Datei werden all die Server in der Services Sektion angelegt und den jeweiligen Netzwerken zugewiesen, in der darauf folgenden Networks Sektion definiert werden:
version: '3.8' services: loadbalancer: build: ./loadbalancer hostname: loadbalancer volumes: - ${PWD}/loadbalancer/conf/loadbalancer_httpd.conf:/usr/local/apache2/conf/httpd.conf - ${PWD}/loadbalancer/conf/loadbalancer.conf:/usr/local/apache2/conf/loadbalancer.conf networks: public_network: dmz_network: ports: - 80:80 reverseproxy_1: build: ./reverseproxy hostname: reverseproxy_1 volumes: - ./reverseproxy/public_html:/usr/local/apache2/htdocs - ${PWD}/reverseproxy/conf/reverseproxy_httpd.conf:/usr/local/apache2/conf/httpd.conf - ${PWD}/reverseproxy/conf/reverseproxy.conf:/usr/local/apache2/conf/reverseproxy.conf networks: dmz_network: private_network: [...] admin: image: httpd:2.4 hostname: admin volumes: - ./admin/public_html:/usr/local/apache2/htdocs networks: private_network: networks: public_network: external: true dmz_network: external: false private_network: external: false
Das Public Netzwerk muss angelegt werden, anschließend kann Docker Compose gestartet werden:
docker network create public_network docker-compose up
Test
Wie zuvor: Über die Logausgaben in dem Terminalfenster, in dem Docker Compose gestartet wurde, kann man gut nachvollziehen, welche Server aufgerufen werden.
Vor dem Login werden über Load Balancer und RPs die Seiten der beiden Public Server angezeigt.
Nach dem Login werden auch die Private und ShowHeaders Seiten angezeigt.
Außerdem werden auch die Seiten der User und Admin Server angezeigt. Das sollte nur erfolgen, wenn der eingeloggte Benutzer auch die entsprechenden Rollen hat, wird aber momentan noch nicht abgefragt. Die Umsetzung wird weiter unten beschrieben, sobald ich herausgefunden habe, wie sie zu implementieren ist.
GitHub
Die Dateien zu diesem Post sind im OneLogin-GitHub-Projekt unter version4 zu finden.
Authorisierung
Der Zugang zu den Seiten der User und Admin Server soll nur mit entsprechenden Rollen erfolgen.
Die Implementierung ist noch offen.
UPDATE: Inzwischen konnte ich mit einem Experten für OneLogin sprechen und wurde aufgeklärt, dass es seitens OneLogin gar nicht vorgesehen ist, dass die Anwendungs-Rollen in OneLogin gepflegt werden.
Folglich kann keine Authorisierung durch den RP mit OneLogin erfolgen.