PRTG SingleSignOn mit NTLM/Kerberos

Der Zugang zur PRTG-Konsole ist per App, Windows GUI aber primär auch per Browser möglich. Die Anmeldung an der Webseite per Browser ist leider nur über ein Formular möglich. Das ist relativ "sicher" , wenn die Verbindung selbst per SSL gesichert ist, da im Hintergrund ein Ticket als Cookie ausgestellt wird, welches bei einem Logout wieder zerstört wird. Das ist ein übliches Vorgehen und verhindert u.a. dass jemand einen Session Replay machen kann oder über den "Zurück"-Button des Browsers wieder eine Session aufnehmen kann. Aber eine automatische Anmeldung im internen LAN per NTLM oder Kerberos hat Paessler leider nicht vorgesehen und auch wenn es oft in den Foren nachgefragt wird, sind andere Themen wohl noch wichtiger. Schade, denn die integrierte Anmeldung macht es Anwender einfacher und erspart die Eingabe von Kennworten. Aber nachdem ich gesehen habe, wie die Anmeldung funktioniert, habe ich mir einen Workaround überlegt.

PRTG Anmeldung

Wen ich auf die Webseite von PRTG gehe, dann begrüßt mich ein Formular-Maske zur Eingabe von Benutzername und Kennwort. Wer auf Sicherheit Wert legt, sollte hier natürlich eine Verbindung per HTTPS erzwingen um die Eingaben auf dem Kabel zu verschlüsseln.

Ich bin sicher nicht der Einzige, der sich hier neben der AD-Integration auch ein "Signle SIgnOn" per Kerberos oder NTLM gewünscht hat. Leider ist dies nicht in Sicht. Das ist duchaus verständlich da eine Webseite immer nur "entweder" eine anonymes Formular ODER eine HTTP-Authentifizierung anbieten kann. Aber was hindert mich, daneben eine eigene Lösung zu bauen.

Wenn ich die Daten im Formular eingegeben und mit "LOGIN" bestätigt habe, sehe ich in Fiddler folgende Requests. Interessant ist hier der "POST Checklogin.htm", mit dem die Anmeldedaten übermittelt und dann ein Cookie empfangen wird.

Dahinter verbirgt sich dahinter ein HTTP-Port mit dem Benutzername und dem Kennwort als Payload.

Die Antwort nach einer erfolgreichen Anmeldung ist ein 302 Redirect auf "/home" und einem Cookie. Alle folgende Requests enthalten diesen Session-Cookie. Der WebServer selbst macht also gar keine HTTP-Authentifizierung sondern nimmt anonyme Anfragen an aber prüft die Gültigkeit des Cookies. Bislang habe ich nur eine Ausnahme gesehen: Zugriffe auf den Pfad "/icons" erfolgen komplett anonym. Dort liegt z.B. die "Favicon_red.png" herum.

 Im Code findet sich auch ein kleines Gimmick: Paessler sucht Entwickler. Ob diese Anzeige jemand findet?

Eine zweite Variante habe ich gesehen, als ich die windowsbasierte Enterprise-Konsole genutzt habe und dort "Open in Web Browser" aufgerufen habe:

Im Hintergrund startet er einen Aufruf auf die folgende URL

GET https://prtg/public/checklogin.htm?login=prtgadmin&passhash=xxxxxxxx HTTP/1.1

Die Antwort ist dann einfach ein 302 Redirect mit einem Cookie, der für die weitere Authentifizierung genutzt wird:

HTTP/1.1 302 Moved Temporarily
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 0
Date: Wed, 16 May 2018 08:52:01 GMT
Expires: 0
Cache-Control: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Server: PRTG/18.2.40.1683
Location: /home
Set-Cookie: OCTOPUS182401683=ezI4RTM1Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2NkUwOERFQX0%3D; Path=/; HttpOnly

Interessant ist dabei natürlich, dass die Windows GUI den PassHash zu dem aktuellen Konto ausgelesen haben muss. Natürlich kann man den PRTG-Server heute schon dazu bringen, die Authentifizierung gegen das Active Directory auszuführen. Das ist hier aber kontraproduktiv, da ich mit Kerberos oder NTLM das AD-Kennwort gar nicht habe. Ich nutze stattdessen den PassHash zum Benutzer. Auch ein AD-Konto hat einen PassHash, der seit der Version 18.3.43.2317 vom 14.8 auch in der Verwaltung anzeigen können. Leider kann der PassHash laut Paessler nicht per API o.ä. direkt von meinem Programm ausgelesen werden.

 

xx BIld zum PassHash

 

Damit habe ich mir nun zwei Dinge überlegt, die funktionieren sollten:

  • Reverse Proxy
    Ich könnte einen kompletten Reverse Proxy per ASPX oder PowerShell bauen, der auf der Seite zum Client die integrierte Anmeldung anfordert und anhand der Authentifizierung dann z.B. aus einer Konfigurationsdatei einen passenden PRTG-Benutzer samt Kennwort ausliest und damit die Anmeldung "on behalf" durchführt. Der Dienst würde aber die ganze zeit "dazwischen" hängen und müsste auch mehrere parallele Sessions bedienen. Das ist dann eher eine Herausforderung für einen Teilzeitentwickler. Per APSX oder PHP könnte so etwas aber einfach zu bewerkstelligen sein.
  • Anmeldeportal
    Die Alternative wäre, wenn ein eigener Anmeldeprozess auf z.B. einem anderen Port lauscht und nur die Anmeldung durchführt aber danach einen Redirect auf die eigentliche PRTG-Seite macht. Wenn der Cookie dabei gesetzt ist, sollte PRTG auch damit zufrieden sein. Im Prinzip ähnelt das der Anmeldung an Office 365 über einen ADFS-Service wobei hier der Hostname und die URL immer der PRTG-Server bleibt. Allerdings werde ich den Port natürlich ändern müssen. Cookies sind aber wohl nicht Port-spezifisch sondern pro Domain.

... by default, cookie scope is limited to all URLs on the current host name - and not bound to port or protocol information. and some lines later There is no way to limit cookies to a single DNS name only [...] likewise, there is no way to limit them to a specific port.
Browser Security Handbook, Part 2  https://code.google.com/archive/p/browsersec/wikis/Part2.wiki#Same-origin_policy_for_cookies

Die Funktion eines Reverse Proxy ist mir zuerst eingefallen. Die zweite Option mit dem Anmelden samt Umleitung ist mir erst später gekommen. Ich beschreibe beide hier beide Optionen etwas genauer aber umgesetzt habe ich letztlich die zweite Option.

Option1: Reverse Proxy mit Authentication

Wenn es mir gelänge, einen Reverse Proxy so zu erweitern, dass er vorne vom Client eine automatische Authentifizierung (Kerberos, NTLM, Zertifikat o.ä.) erwarte und dann mit einem "Benutzerkennwort" auf den PRTG-Server zugreift, dann habe ich schon gewonnen.

habenAlternativ können Sie schon den PRTG-Server mit dem AD verbinden aber zusätzlich die "App-Kennworte" hinterlegen. Das ist eine zusätzliche Schutzfunktion von PRTG, damit Sie z.B. auf ihrem Mobilgerät oder Browser nicht das "AD-Kennwort" sondern ein PRTG-Only-Kennwort verwenden können. Leider lässt sich diese Information nicht per API auslesen. Es ist dennoch interessant PRTG-Only-User anzulegen und die Benutzernamen samt Kennwort hoffentlich sicher auf dem Reverse Proxy zu hinterlegen. Dieser könnte dann folgendes machen:

Anfragen auf "icons" werden immer 1:1 durchgegeben. Danach wird geprüft, ob die der Zugriff authentifiziert erfolgt. Wenn ja beginnt die Suche nach dem Anwender und die Anmeldung um einen Cookie zu bekommen. Ansonsten wird auf den Cookie geschaut, der enthalten sein muss. Fehlt dieser, muss der Client mit einem 403 zu einer Authentifizierung gezwungen werden.

Mit etwas Glück sollte der Anwender sich so am vorgeschalteten Reverse Proxy per NTLM/Kerberos anmelden und in der Folge auf PRTG zugreifen können. Die "Authentifizierung" wird natürlich vorgelagert und die Liste der User mit Kennworten muss manuell gepflegt werden. Leider kenne ich keine API die Benutzer mit den lokalen Kennworten aus PRTG auszulesen.

Diese Option könnte sicher als ASPX oder PHP-Anwendung sehr einfach parallel zur laufenden PRTG-Installation umgesetzt werden. Sie muss allerdings MultiThreading unterstützen, damit ein Request den anderen nicht blockt.

Option2: Umleitung

Aufgrund der Einschränkungen eines kompletten Reverse Proxy ist die Lösung mit einer Umleitung vielleicht sogar besser. Allerdings können der PRTG-Webserver und mein Anmelde-Service natürlich nicht auf dem gleichen Port laufen. Daher habe ich den Anmeldedienste erst mal auf einem anderen Port angelegt, so dass er PRTG nicht stört. Die Planung ist, dass ich erst mal per Browser auf z.B. http://<server>:9444 gehe und der Service eine Anmeldung per NTLM/Kerberos erzwingt. Für die Authentifizierungsinformationen bräuchte ich nicht mal SSL. In der Antwort steht dann aber ein Redirect auf die PRTG-Seite samt dem Cookie und dafür wäre SSL schon besser.

Dieser Weg erscheint mir viel einfacher und weniger belastend, zumal die spätere Kommunikation zu PRTG selbst nicht mehr über eine Middleware geht.

Wenn die Anwender aber nun "Windows Anwender auf dem Active Directory" sind, dann erwartet PRTG natürlich das Windows Kennwort, welche sich aber nicht habe und gerade nicht vom Anwender abfordern möchte. Für meine Konstruktion müssen Sie leider auf Windows Benutzer verzichten und in PRTG die Anwender als "lokale Anwender "anlegen. Nur dann können Sie das Kennwort festlegen und nebenbei auch PassHash nutzen.

Die Anwender müssen aber das Kennwort für den PRTG-Benutzer gar nicht kennen und sollen es auch nicht kennen. Das Kennwort muss nur mein Skript kennen. Theoretisch könnte das Skript also auch die Benutzer gleich dynamisch anlegen. Aber ich hoffe ja immer noch dass Paessler mal Kerberos implementiert. So schwer sollte es ja nicht sein, Kerberos auf einen anonymen Zugriff ohne Cookie auszuliefern und dann das Ticket auf Gültigkeit zu parsen.

Proof of Concept mit PowerShell

Ich habe diese zweite Option als PowerShell-Script implementiert, da Sie quasi neben PRTG laufen kann und man sich die Installation von IIS, ASPX etc. spart.

Selbst Microsoft geht davon weg, dass Dienste immer "im IIS drin" sich integrieren können. Zudem der IIS schon lange nicht mehr der komplette WebServer ist sondern nur noch der Aufsatz auf den HTTP-Listener, der quasi im Betriebssystem vorhanden ist. Auch ADFS installiert keinen IIS mehr und auch per PowerShell ist es gar nicht schwer einen HTTP-Listener zu bauen. Das geht sogar per Authentifizierung und als PowerShell-Programmierer habe ich damit natürlich meine ersten Gehversuche gemacht. Ich brauche also:

  • Ein PowerShell-Script, als HTTP-Listener
    Schon beim HTTP-Listener kann ich eine Authentifizierung fordern, so dass ich das gar nicht selbst weiter implementieren muss. Der darunter liegende HTTP-Stack übernimmt das alles und das Skript bekommt den Request erst, wenn der Benutzer angemeldet ist.
  • List der Benutzer und Anmeldedaten
    Es gibt keinen Weg zum Auslesen des PassHash. Sie mjüssen als Administrator daher diese Information für die Benutzer manuell aus der WebGUI ermitteln und in die Konfigurationsdatei eintragen. Ich behelfe ich mir mit einer Datei, in der der Windows Anmeldenamen auf einen PRTG-Benutzernamen samt Passhash umgeleitet wird.
  • Sende 301 Redirect an den Client
    Nachdem der HTTP-Listener den User authentifiziert hat und das PowerShell-Script den dazu passenden PRTG-Benutzer samt Passhash ermittelt hat, sendet das Skript nun einfach einen HTTP Redirect (301) mit der zusammengesetzten URL an den Client
  • Client sendet den Request an PRTG
    Der Browser, der sich eben noch an meinem PowerShell-Script angemeldet hat, springt nun direkt die PRTG-URL an. Mein Script ist nicht mehr involviert. Die PRTG-Instanz prüft die Daten der URL und der Anwender ist auch in PRTG authentifiziert, bekommt einen Cookie und kann wie gewohnt weiter arbeiten. Allerdings ist das Thema "Timeout" nicht abgefangen, d.h. wenn der Anwender 15 Minuten (Default) nichts macht, dann wird der Cookie ungültig und der Anwender bekommt ein Anmeldefenster.

Das hört sich alles doch sehr einfach an. Es ist aber nur ein Proof of Concept und nicht für den Dauereinsatz gedacht. Auch beim Thema Sicherheit sollten Sie darauf achten, dass die PRTG-Seite nur per HTTPS erreichbar ist, damit niemand anhand der URL den Passhash auslesen kann. Es ist sicher eine Vereinfachung für "ReadOnly" User im 1st-Level oder Gelegenheits-Admins. Für den PRTG-Admin ist es aber mehr Arbeit, da er die Benutzer als PRTG-Benutzer mit einem Kennwort anlegen und dann in der Konfigurationsdatei hinterlegen muss.

Leider ist hat ein PRTG-Benutzer, der über das Active Directory authentifiziert ist, meines Wissens keinen Passhash. Aber vielleicht implementiert Paessler irgendwann ja NTLM/Kerberos oder alternativ ADFS/OAUTH2. Dann wird das Skript hier überflüssig.

prtg-sso.20180811.zip

Das Skript wird wie folgt eingesetzt:

  • Auspacken
    Legen Sie z.B. auf dem PRTG-Server ein Verzeichnis an und entpacken Sie das PS1-Script und die CSV-Datei. Ändern Sie auf der PS1-Datei ggfls. die Ausführungsblockade, da es ja ein Download aus dem Internet war
  • Skript-Parameter ändern
    Hier steht die URL zu meinem Labor-PRTG-Server drin. Die müssen Sie ändern.
    Auch der HTTP-Port (ich nutze aktuell KEIN SSL) muss frei sein
  • CSV-Datei anlassen
    In der CSV-Datei müssen Sie auf jeden Windows Anmeldenamen einen PRTG-Usernamen mit Passhash eintragen.
  • PowerShell als Admin starten
    Dann sollte auch die Firewall kein Problem darstellen
  • Client:HTTP-Zugriff
    Starten Sie nun einen Browser auf einem Client und geben Sie die URL mit dem Hostnamen und dem Port an, Wenn alles funktioniert, dann sollte das PowerShell den Browser zur Anmeldung per NTLM/Kerberos auffordern und dann den Client auf die richtige PRTG-URL umleiten und Sie sind drin.

Das hier ist wirklich ein Demo-Skript. Für einen produktiven Einsatz sollten das Skript auch ohne interaktive Shell des Admin laufen, Error-Handling umsetzen und aktuell ist es auch nur sequentiell. Es macht aber keinen Sinn diese Funktion in PowerShell umzusetzen. Dann würde ich besser eine ASPX-Seite oder PHP einsetzen.

Hier noch ein paar Links zu HTTP-Listener unter Powershell

Lösung mit dem IIS

Für einen dauerhaften und flexiblen Betrieb ist natürlich ein PowerShell-Skript nicht unbedingt skalierbar. Da kommt mit aber der IIS gerade recht, der über ASPX einfach Anfragen von Clients annehmen und  mit Daten aus einem nachgelagerten Backend beziehen kann. Man muss also nur ein paar Zeilen "Code" zusammenführen und entsprechende Beispiele finden Sie auch im Internet.

Es scheint gar nicht so schwer zu sein einen IIS als Reverse-Proxy zu verwenden auch wenn man nicht auf IIS ARR (Application Request Routing) oder WAP - Web Application Proxy aufbauen will.

Ich habe den Code noch nicht zu ASPX oder PHP konvertiert. Das wäre doch mal ein Projekt für einen Azubi oder FiSi o.ä.?  Oder Paessler ist schneller und implementiert die Funktion in ihr Produkt. Mir würde schon ADFS/OAUTH2 reichen. Das wäre dann Auch eine Lösung für die Cloud.

Weitere Links