Version 2 aus dem Beispiel Reverse Proxy mit OneLogin soll zu Testzwecken in der Cloud zum Laufen gebracht werden.
Bei dem PoC handelt es sich um einen Apache HTTP-Server mit simpler Public Page und OneLogin Authentifizierung für den Zugriff auf die Private Page: der ShowHeaders Anwendung in einem Apache Tomcat-Server. Beide Server laufen in Docker Containern, die über Docker Compose gestartet werden.
Cloud Server einrichten
Auf dem Server muss Docker etc. eingerichtet werden:
sudo su yum install docker -y systemctl umask docker systemctl start docker docker version curl -L https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose chmod +x /usr/bin/docker-compose docker-compose --version # # Output: # Docker Compose version v2.2.3 yum install git -y mkdir /app cd /app git clone https://github.com/DerIngo/DockerOneLoginApacheSample.git vim /app/DockerOneLoginApacheSample/version2/reverseproxy/conf/reverseproxy.conf
Fehler
Auf dem lokalen Entwicklerlaptop läuft der PoC und entsprechend soll er auch in der Cloud gestartet werden:
sudo su cd /app/DockerOneLoginApacheSample/version2 docker-compose up
Zuerst sieht alles wie gewohnt aus, bis Maven ShowHeaders bauen soll:
root@showheaders:/usr/local/tomcat/ShowHeaders# mvn package [INFO] Scanning for projects... [INFO] [INFO] ------------------------< deringo:ShowHeaders >------------------------- [INFO] Building ShowHeaders 0.0.1-SNAPSHOT [INFO] --------------------------------[ war ]--------------------------------- Downloading from central: https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat-catalina/8.5.53/tomcat-catalina-8.5.53.pom [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.956 s [INFO] Finished at: 2022-06-07T12:28:46Z [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal on project ShowHeaders: Could not resolve dependencies for project deringo:ShowHeaders:war:0.0.1-SNAPSHOT: Failed to collect dependencies at org.apache.tomcat:tomcat-catalina:jar:8.5.53: Failed to read artifact descriptor for org.apache.tomcat:tomcat-catalina:jar:8.5.53: Could not transfer artifact org.apache.tomcat:tomcat-catalina:pom:8.5.53 from/to central (https://repo.maven.apache.org/maven2): Transfer failed for https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat-catalina/8.5.53/tomcat-catalina-8.5.53.pom: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
Es kann eine Dependency nicht aufgelöst werden und im Text findet sich dieser Satz: "PKIX path building failed". Also irgendwas mit Zertifikaten, wie mir die Erfahrung sagt.
Nach einer Recherche ist klar: In dem Cloud Setup wird der ausgehende Traffic durch einen Proxy geleitet und dessen Zertifikate sind nicht in den Standard-Zertifikaten enthalten.
Simple Lösung: Validierung aushebeln
Die schnellste Lösung: Einfach auf jedwede Validierung verzichten.
Aus Stackoverflow:
You can disable SSL certificate checking by adding one or more of these command line parameters:
-Dmaven.wagon.http.ssl.insecure=true
- enable use of relaxed SSL check for user generated certificates.-Dmaven.wagon.http.ssl.allowall=true
- enable match of the server's X.509 certificate with hostname. If disabled, a browser like check will be used.-Dmaven.wagon.http.ssl.ignore.validity.dates=true
- ignore issues with certificate dates.
Official documentation: http://maven.apache.org/wagon/wagon-providers/wagon-http/
Here's the oneliner for an easy copy-and-paste:
-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true
Umsetzung
In dem Dockerfile von ShowHeaders wird der Maven Aufruf um obige Parameter ergänzt:
WORKDIR ShowHeaders # aus RUN mvn package # wird RUN mvn package -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true
und schon kann das Image wieder erfolgreich gebaut werden.
Der gleiche Fehler
Die Images werden gebaut, die Container starten und die Public Page wird korrekt angezeigt auf http://localhost:80/public
Aber: die Private Page auf http://localhost:80/private wird nicht angezeigt, bzw. wird nicht mal das OneLogin Login angezeigt.
Das Problem findet sich in der OpenID Konfiguration für OneLogin:
OIDCProviderMetadataURL https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration
Per HTTPS soll die Außenwelt erreicht werden, doch auch hier ist wieder der Proxy dazwischen.
Der Aufruf mittels http wird direkt auf https umgeleitet.
Die Validierung kann hier nicht so einfach ausgehebelt werden, falls überhaupt.
Lösung: Zertifikat(e) hinzufügen
Lösungsansatz: Zertifikatskette herunterladen und dem Truststore hinzufügen.
Der erste Ansatz, wie an die Zertifikate gelangt werden kann fand sich auf StackExchange:
openssl s_client -showcerts -servername deringo-dev.onelogin.com -connect deringo-dev.onelogin.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem
Das funktioniert prinzipiell, dauert aber sehr lange. Außerdem wird in einem ausführlichen Kommentar darauf hingewiesen, dass die Intermediate Certificates so nicht gezogen würden.
Eine ausführliche Anleitung findet sich auf Baeldung, deren Ansatz ist wesentlich schneller (von mir nicht auf Intermediate C. getestet):
openssl s_client -connect deringo-dev.onelogin.com:443 -showcerts mycert.pem
Den Inhalt der heruntergeladenen Zertifikatsdatei in Plain Text anzeigen lassen:
openssl x509 -in mycert.pem -noout -text
Auf der Seite sind noch viele weitere Beispiele.
Die Zertifikate importieren:
cp mycert.pem /usr/local/share/ca-certificates/mycert.crt update-ca-certificates
Umsetzung
Das Dockerfile des Reverse Proxies:
FROM httpd:2.4 RUN apt update && apt install -y \ libapache2-mod-auth-openidc \ ca-certificates RUN openssl s_client -connect deringo-dev.onelogin.com:443 -showcerts mycert.pem && \ cp mycert.pem /usr/local/share/ca-certificates/mycert.crt && \ update-ca-certificates RUN cp /usr/lib/apache2/modules/mod_auth_openidc.so /usr/local/apache2/modules/RUN mv conf/httpd.conf conf/container_httpd.conf CMD ["httpd-foreground"]
Anschließend das Image neu bauen:
docker-compose build reverseproxy
Test
Leider kann momentan nur auf der Konsole getestet werden:
curl localhost/private/
Aber der Docker Output sieht nicht gut aus: "SSL certificate problem: unable to get local issuer certificate":
version2-reverseproxy-1 | [Tue Jun 07 13:48:25.115383 2022] [auth_openidc:error] [pid 9:tid 140428228966144] [client 172.21.0.1:57644] oidc_util_http_call: curl_easy_perform() failed on: https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration (SSL certificate problem: unable to get local issuer certificate) version2-reverseproxy-1 | [Tue Jun 07 13:48:25.115513 2022] [auth_openidc:error] [pid 9:tid 140428228966144] [client 172.21.0.1:57644] oidc_provider_static_config: could not retrieve metadata from url: https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configurationversion2-reverseproxy-1 | 172.21.0.1 - - [07/Jun/2022:13:48:25 +0000] "GET /private/ HTTP/1.1" 500 531 version2-reverseproxy-1 | 172.21.0.1 - - [07/Jun/2022:13:48:27 +0000] "GET /private/ HTTP/1.1" 302 478
Allerdings, nach einem Neustart sieht es doch gut aus in der Konsole:
curl localhost/private/302 Found Found
The document has moved here.
Anschließend wieder gestoppt, Reverse Proxy Image neu bauen lassen, Container wieder gestartet: Beim ersten curl kommt der "SSL certificate problem: unable to get local issuer certificate"-Fehler, bei weiteren curls der "The document has moved"-Hinweis.
Schauen wir mal, wie das im Container aussieht:
Vorbereitung:
# frisch starten: docker-compose down -v docker-compose build reverseproxy docker-compose up # vor dem ersten Aufruf: Ab in den Container: docker exec -it version2-reverseproxy-1 bash
Im Container:
# Im Container: apt install curl # 1. Aufruf curl https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above. # 2. Aufruf curl https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above. # 3. Aufruf curl https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration {"acr_values_supported":["onelogin:nist:level:1:re-auth"],"authorization_endpoint":"https://deringo-dev.onelogin.com/oidc/2/auth","claims_parameter_suppor[...]
Ich habe es noch ein paar mal ausprobiert, ungefähr jedes zweite bis dritte Mal hat es funktioniert.
Offensichtlich ist da noch ein LoadBalancer zwischen. 🤦♂️🤦♂️🤦♂️
Recherche
Im Container:
apt install iputils-ping ping deringo-dev.onelogin.com
Mehrmaliges pingen gab zwei verschiedene IPs zurück.
apt install nmap nmap deringo-dev.onelogin.com Starting Nmap 7.80 ( https://nmap.org ) at 2022-06-07 14:18 UTC Nmap scan report for deringo-dev.onelogin.com (52.29.255.229) Host is up (0.0052s latency). Other addresses for deringo-dev.onelogin.com (not scanned): 52.29.255.230 rDNS record for 52.29.255.229: ec2-52-29-255-229.eu-central-1.compute.amazonaws.com Not shown: 994 filtered ports PORT STATE SERVICE 21/tcp open ftp 53/tcp open domain 80/tcp open http 443/tcp open https 554/tcp open rtsp 1723/tcp open pptp
Aha! Es gibt zwei IPs zu dem Domainnamen und anscheinend ist OneLogin in den AWS.
Nochmal ein anderer Test; Wie ist das denn, wenn ich nicht im Container, sondern direkt vom Host curle:
curl https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration
Und siehe da: Auf dem Host funktioniert jeder Aufruf!
Mal schauen, ob wir die Certs finden:
locate *.crt unter Anderen: /etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt
Ab in den Container damit:
docker cp /etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt version2-reverseproxy-1:/tmp
im Container hinzufügen & testen:
cp /tmp/ZscalerCloudChain.crt /usr/local/share/ca-certificates/ZscalerCloudChain.crt update-ca-certificates curl https://deringo-dev.onelogin.com/oidc/2/.well-known/openid-configuration
Jeder Aufruf funktioniert, diesmal sieht es wirklich gut aus.
Umsetzung
Das Dockerfile des Reverse Proxies:
FROM httpd:2.4 RUN apt update && apt install -y \ libapache2-mod-auth-openidc \ ca-certificates COPY /etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt /usr/local/share/ca-certificates/ZscalerCloudChain.crt RUN update-ca-certificates RUN cp /usr/lib/apache2/modules/mod_auth_openidc.so /usr/local/apache2/modules/ RUN mv conf/httpd.conf conf/container_httpd.conf CMD ["httpd-foreground"]
Anschließend das Image neu bauen:
docker-compose build reverseproxy
Ich fasse es nicht:
Step 3/6 : COPY /etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt /usr/local/share/ca-certificates/ZscalerCloudChain.crt 1 error occurred: * Status: COPY failed: file not found in build context or excluded by .dockerignore: stat etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt: filedoes not exist, Code: 1
"you can only use files in your Dockerfile that are within the build context. Usually, this is .
, so the Dockerfile's directory. " Copy file with absolute path to Docker Container using a Dockerfile - Stack Overflow
Nächster Versuch:
FROM httpd:2.4 RUN apt update && apt install -y \ libapache2-mod-auth-openidc \ ca-certificates COPY ./ZscalerCloudChain.crt /usr/local/share/ca-certificates/ZscalerCloudChain.crt RUN update-ca-certificates RUN cp /usr/lib/apache2/modules/mod_auth_openidc.so /usr/local/apache2/modules/ RUN mv conf/httpd.conf conf/container_httpd.conf CMD ["httpd-foreground"]
cp /etc/pki/ca-trust/source/anchors/ZscalerCloudChain.crt /app/DockerOneLoginApacheSample/version2/reverseproxy/ZscalerCloudChain.crt docker-compose build reverseproxy docker-compose up
Test
curl localhost/private/
Keine Fehler im Log! 🎉
Test im Browser mit Login
Steht noch aus, aktuell ist der Server nur über Console zu erreichen.
UPDATE: Inzwischen wurde der Zugriff per Browser auf den Server freigeschaltet (bzw. eine fehlerhafte Netzwerkkonfiguration gefixt) und die Public Seiten sind zugänglich.
Bei Aufruf der Private Seiten kommt allerdings eine Fehlermeldung:
Die Lösung wird im nächsten Post erarbeitet.
2 replies on “Man In The Middle (ZScaler)”
[…] den Erkenntnissen des letzten Posts folgt, dass die Möglichkeit vorgesehen werden muss, eine vertrauenswürdige Zertifikatskette […]
[…] hatte schon mal in einem anderen Setup das gleiche Problem: Man In The Middle (ZScaler) aber mit anderen Anforderungen und anderer […]