ADFS Service Zertifikat aktualisieren

Diese Seite ist zum Teil auch Frustbewältigung, weil ein Wechsel des Service Zertifikats auf einem produktiven ADFS 2012R2-Server mir eine Nachtschicht beschert hat, und fast alles schief gegangen ist, was brechen kann. Wobei ich die eigentliche Server dabei gar nicht das Problem waren. Bei der Konfiguration hat es gleich mehrfach geknallt und ich war nahe dran über Nacht die Authentifizierung an Office 365 von ADFS auf Pass-Through Authentifizierung (PTA) mit Seamless Single Sign On umzustellen.

Ausgangssituation

Wie viele andere Firmen, die Office 365 schon länger nutzen, betreibt auch Net at Work einen ADFS-Server, auf den Anwender bei der Anmeldung durch Office 365 verwiesen werden. Sie können sich so intern direkt per Kerberos vom ADFS-Server ein Ticket für die Cloud nutzen und werden nicht nach einem Kennwort gefragt. Beim Zugriff aus dem Internet wird der ADFS Proxy, der Bestandteil eines DirectAccess-Server und WAP-Proxy ist, genutzt. Soweit ist das kein besonders komplexes Szenario und mal abgesehen von der eingeschränkten "Hochverfügbarkeit" seit Jahren robust im Einsatz.

Um die Zugriffe entsprechende abzusichern, sind natürlich entsprechende Zertifikate installiert. Das sind hier schon einige Zertifikate

  1. WebServer von extern
    Hier ist ein offizielles Zertifikat installiert, damit Clients von Extern eine HTTPS-Verbindung zum ADFS-Proxy aufbauen können
  2. ADFS Proxy Auth
    Dieses "Self Signed" Zertifikat wird vom ADFSProxy erstellt, damit er sich damit gegenüber dem ADFS-Server authentifizieren kann.
  3. ADFS Service Zertifikat
    Auch der ADFS-Server hat ein Webserver-Zertifikat, damit interne Clients auf den gleichen ADFS-Namen zugreifen können. WIr nutzen das gleiche öffentliche Zertifikat wie extern.
  4. ADFS Signing Zertifikat
    Die vom ADFS ausgestellten Tickets müssen natürlich digital signiert werden. Dies passiert mit einem eigenen "Self Signed"-Zertifikat, welches die vertrauenswürdigen Stellen über die Federation Metadata holen.
  5. ADFS Encryption Zertifikat
    Auch dieses Self-Signed Zertifikat gibt es auf dem ADFS-Server

Eine ausführlichere Beschreibung finden Sie u.a. auf ADFS Zertifikate.

Der Change

Die Zertifikat 2,4 und 5 kann ADFS selbst erneuern, so dass Sie hier in der Regel nichts machen müssen. Ansonsten sind folgende Seiten hilfreich:

In diesem Fall ging es aber darum das öffentliche Zertifikat zu tauschen, welches nach 1-2 Jahren ja immer wieder abläuft. Klassisch bedeutet dies, dass man das neue Zertifikat in den "Local Computer"-Store für Zertifikate mitsamt dem privaten Schlüssel importiert und dann per "Set-ADFSCertificate" zuweist. So habe ich mir das auch gedacht und mit einer kurzen Unterbrechung von wenigen Minuten gerechnet. Leider hat der Prozess dann etwas länger gedauert und den Root-Cause kann ich bis heute nicht genau bestimmen. Vielleicht ist es ja einfach eine versteckte Altlast, die man später einmal durch eine Neuinstallation beseitigt.

Fakt war, dass nach dem Einspielen der neuen Zertifikate der ADFS-Server und auch die Dienste zwar liefen aber die Funktion nicht mehr gegeben war. Die Eventlogs haben munter rote Meldungen geliefert.

Rechte auf den privaten Key

Mit dem installieren eines Zertifikats Nr. 3 samt private Key auf dem ADFS-Server ist es leider nicht getan. Da die ADFS-Dienste nicht als "Local System" laufen, kommen Sie per Default nicht an den Schlüssel heran. Man muss hier schon noch mal in der MMC für Zertifikate die Rechte vergeben.

Das ist insoweit schon ungewöhnlich, da ein IIS das z.B. nicht braucht.

Bindungen prüfen

Sie können ein Zertifikat natürlich über die ADFS-GUI tauschen.

Das hatte ich auch versucht aber danach konnte sich kein Client, d.h. auch kein einfacher IE mehr mit dem Server verbinden. Die Meldungen deuteten darauf hin, dass auf dem Service kein SSL-Handshake mit TLS 1.0/1.1./1.2 zustande kommen kann. Also habe ich einmal Wireshark gestartet und den TLS Handshake angeschaut. Tatsächlich kam vom Client ein "Client Hello", was der ADFS-Server umgehend mit einem TCP-RESET abgewürgt hat. Da muss also SSL-technisch noch was daneben liegen.

Eine Suche im Internet ergab schon die ein oder anderen Treffer, die allerdings umsichtig zu betrachten sind. Solche Informationen können durchaus auch "verwaltet" sein oder durch Updates schon den gegenteiligen Effekt ausüben

Insofern habe ich erst mal geprüft, ob eine Neuzuweisung per PowerShell etwas bewirkt

Install-WebApplicationProxy `
   -CertificateThumbprint xxxxxxxxxxxxxxxxxxxxxxx `
   -FederationServiceName adfs.msxfaq.de

Im Eventlog war die Meldung immer noch da:

Log Name:      System
Source:        Microsoft-Windows-HttpEvent
Event ID:      15021
Level:         Error
Keywords:      Classic
Computer:      ADFS.msxfaq.de
Description: 
  An error occurred while using SSL configuration for endpoint adfs.msxfaq.de:443.
  The error status code is contained within the returned data.

Nun ist der ADFS 2012 oder höher keine IIS-Applikation mehr, sondern bedient sich selbst dem HTTP-Stack. Also kommt NetSH zum Einsatz. Hierbei ist gut zu sehen, dass ADFS einige "Listener" am Start hat:

C:\>netsh http show sslcert

SSL Certificate bindings:
-------------------------

    Hostname:port                : localhost:443
    Certificate Hash             : xxxxxxxxxxxxxxxx
    Application ID               : {5d89a20c-beab-4389-9447-324788eb944a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : (null)
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled

    Hostname:port                : adfs.msxfaq.de:443
    Certificate Hash             : xxxxxxxxxxxxxxx
    Application ID               : {5d89a20c-beab-4389-9447-324788eb944a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : AdfsTrustedDevices
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled

    Hostname:port                : adfs.msxfaq.de:49443
    Certificate Hash             : xxxxxxxxxxxxx
    Application ID               : {5d89a20c-beab-4389-9447-324788eb944a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : (null)
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Enabled

Bei der Überprüfung der "Certificate Hash"-Werte ist mir dann aufgefallen, dass die alle gar nicht gleich waren, obwohl sie gleich sein sollten. Hier hat zumindest in meiner Umgebung die PowerShell und die GUI versagt. Ich musste daher die Bindungen von Hand eintragen.

netsh http delete sslcert hostnameport=localhost:443
netsh http add sslcert hostnameport=localhost:443 certhash=xxxx  appid='{5d89a20c-beab-4389-9447-324788eb944a}' certstorename=my
 
netsh http delete sslcert  hostnameport=adfs.msxfaq.de:443
netsh http add sslcert hostnameport=adfs.msxfaq.de:443 certhash=‎xxxx  appid='{5d89a20c-beab-4389-9447-324788eb944a}' certstorename=my
 
netsh http delete sslcert  hostnameport=adfs.msxfaq.de:49443
netsh http add sslcert hostnameport=adfs.msxfaq.de:49443 certhash=xxxx  appid='{5d89a20c-beab-4389-9447-324788eb944a}' certstorename=my

Damit war diese Einstellung schon einmal gerettet und interne Clients konnten sich wieder anmelden.

Achtung:
Diese Zeilen addieren einen Fehler, der die Funktion des ADFS-Proxy blockiert. darauf gehe ich weiter unten ein. Bitte die Seite komplett lesen-

ADFSProxy

Das zweite Sorgenkind war nun der ADFS-Proxy, der auf Anfragen von Extern ein "503 Service not available" geliefert hat. Am Anfang, als der ADFS-Server selbst nicht lieft, konnte ich mir das noch erklären. Wenn der ADFS-Proxy sich nicht zum ADFS-Server verbinden kann, dann kann er auch nichts tun. Die fehlerhaften SSL-Bindungen auf dem ADFS-Server haben auch jeden TLS Handshake zum direkt nach dem "Client Hello" mit einem RESET beendet.

Auch die Statusabfrage des ADFSProxy meldet ein Problem aber ohne weitere aussagekräftige Details:

Get-WebApplicationProxyHealth
 
Component          : AD FS Proxy
RemoteAccessServer : ADFSPROXY
HealthState        : Error
Heuristics         : {Id: 1001, ErrorDesc: AD FS Proxy: AD FS Proxy service is down., ErrorCause: An unknown error had
                     occured, ErrorResoln: Please refer to TechNet library in http://technet.com/ServiceADFS,
                     OperationStatus: Unknown error, Status: Error}
TimeStamp          : 7/3/2018 12:56:34 AM
 
Component          : Web Application Proxy Core
RemoteAccessServer : ADFSPROXY
HealthState        : Error
Heuristics         : {Id: 1002, ErrorDesc: Web Application Proxy: Web Application Proxy service is down., ErrorCause:
                     An unknown error had occured, ErrorResoln: Please refer to TechNet library in
                     http://technet.com/ServiceWAP, OperationStatus: Unknown error, Status: Error}
TimeStamp          : 7/3/2018 12:56:34 AM

Die Befehle kann man sicher gut ins Monitoring einbauen . Das war aber noch ehe ich auf dem ADFS-Server die Fehler bei der Zertifikatszuweisung korrigiert habe. Aber auch nach deren Behebung konnte der ADFS-Proxy nicht arbeiten. Eine Ursache ist sicher der Tausch des Zertifikats, dem der Proxy-Server nicht mehr vertraut. Da hilft es in der Regel die Vertrauensstellung wieder einzurichten. Manchmal ist einfach der Wurm drin und ich habe mich entschieden, die Proxy-Verbindung einfach noch mal "Frisch" zu machen. Dazu habe ich auf dem ADFS-Server erst einmal alle Proxy-Server entfernt:

Im nächsten Schritt habe ich dann den Proxy auf dem ADFS-Proxy/DirectAcces-Servet wieder addiert. Wenn Sie die über die "Remote Access"-GUI machen wollen, dann müssen Sie erst einen Registrierungsschlüssel setzen, damit der Assistent die Einrichtung wieder zulässt.

Windows Registry Editor Version 5.00

[HKLM\Software\Microsoft\ADFS]
"ProxyConfigurationStatus"=dword:1

Normalweise steht dort eine 2 = "bereits konfiguriert" drin und verbirgt damit den Assistenten. Allernativ können Sie natürlich auch die PowerShell nutzen:

Install-WebApplicationProxy `
    -CertificateThumbprint xxxxxxxxxxxxxxxxxxxxx `
    -FederationServiceName adfs.netatwork.de | fl

In meinem Beispiel hat dieser Befehl nach 5 Minuten dann mit einem Fehler aufgegeben. Auch dazu gibt es einige "Treffer" im Internet

Ich habe trotzdem erst mal vermieden, allzu viele Einstellungen in den Zielen durchzuführen

Windows Registry Editor Version 5.00

[HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:1

Das muss ja auch anders gehen und lief vorher auch anders. Nach einiger Suche bin ich dann auf den Artikel gestoßen:

Diesen Artikel würde ich als Goldgrube für ADFS und ADFSProxy bezeichnen, da er sehr viele Fehlerbilder und Zusammenhänge erklärt.

Sie erinnern sich vielleicht noch, wie ich weiter oben auf dem ADFS-Server die Bindungen der Zertifikate mit NETSH korrigiert habe. Damit konnten zwar dann die internen Anwender wieder arbeiten aber der ADFSProxy war ausgeschlossen, weil der Proxy sich zwar mir einem Client-Zertifikat beim ADFS-Server gemeldet hat, aber der ADFS-Server in seinem "Default Store" nach dem Zertifikat gesucht hat. Das ADFS-ProxySetup legt das Zertifikat aber in einem anderen Speicher ab. Fragen Sie mich bitte nicht, warum aber deswegen müssen Sie auf dem ADFS-Server die Konfiguration anpassen, damit er auch dort nachschauen. Schauen Sie sich dazu die Ausgabe von NETSH hinsichtlich des Parameters "Ctl Store Name" im Vorher/Nachher-Vergleich an:

REM Auszug aus der alten Bindung
netsh http show sslcert
 
SSL Certificate bindings:
-------------------------
 
    Hostname:port                : localhost:443
    Certificate Hash             : xxxxx
    Application ID               : {5d89a20c-beab-4389-9447-324788eb944a}
    Certificate Store Name       : my
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : (null)
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled

Die Korrektur ist per ADFS-PowerShell möglich

REM Erneut zuweisen des gleichen Zertifikats
 Set-AdfsSslCertificate -Thumbprint xxxxxx

Korrektur der Änderung

netsh http show sslcert
 
SSL Certificate bindings:
-------------------------
    Hostname:port                : adfs.netatwork.de:443
    Certificate Hash             : xxxxxx
    Application ID               : {5d89a20c-beab-4389-9447-324788eb944a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : AdfsTrustedDevices
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled

Nach dem Update mit "Set-ADFSCertificate" wurde der Wert von "Ctl Store Name" von "(null)" auf "AdfsTrustedDevices" geändert. Nun schaut der ADFS-Server wieder im richtigen Speicher nach ich kann auf dem ADFS-Proxy die Einrichtung über den Assistenten oder per PowerShell noch einmal versuchen. Diesmal ist der ADFS-Server innerhalb weniger Sekunden aktiviert und nimmt auch sofort den Dienste auf.

Zwischenstand

Der Server läuft wieder, auch wenn es später geworden ist und der ein oder andere Anwender in der Zeit nicht auf Dienste zugreifen konnte, zu denen er ein neues ADFS-Ticket anfordern muss. Auf der anderen Seite lernt man leider nur durch solche hartnäckigen Störungen, wie Produkte und Dienste letztlich funktionieren. Auf der anderen Seite zeigt es wieder mal, dass auch einfache Überwachungsfunktionen, die primär die Erreichbarkeit eines Dienste per TCP oder HTTP prüfen oder kontrollieren, ob die Dienste gestartet sein, nicht tief genug greifen.

Vielleicht ist es langsam auch Zeit, Umgebungen mit genau einem ADFS-Server und Proxy in die Richtung Pass-Through Authentifizierung (PTA) mit Seamless Single Sign On zu migrieren, um die Komplexität selbst betriebener ADFS-Services zu reduzieren. Das bedeutet ja nicht, dass ADFS damit gleich abgeschaltet wird. Es wird sicher noch andere Cloud-Dienste wie z.B. SalesForce etc. geben, die per ADFS die Authentifizierung von Kunden integrieren. Wobei auch hier Azure AD Authentifizierung und Provisioning natürlich auch interessant sind.

Nachtrag

Fünf tage später konnte ich mich dann wieder nicht mehr anmelden. Ich bin per Browser auf das Portal, habe meinen Usernamen eingegeben, wurde zum ADFS-Server verwiesen und nach der Anmeldung und Rücksprung zu Office 365 stand ich wieder auf der Anmeldemaske ohne einen Fehlercode. Also wieder einmal "Fiddler" und schauen. Nachdem die Anmeldeseite den Kontentyp ermittelt hat, ist mein Client zum ADFS-Server gesprungen und wurde mit dem Ticket zurück geschickt.

Das können Sie hier schön am "Form Post" des Pakets 18 sehen.

Interessant ist dann die Antwort auf diesen POST:

Der Microsoft Service liefert eine n200 OK, weil er die Anfrage an sich erfolgreich verarbeitet hat. Über einen weiteren FORM POST wird dieser Fehler dann auf die Landing-URL von Office 365 gesendet. Microsoft kann diesen Code damit auswerten aber leider sehe ich als Anwender keinen Hinweis auf der nun wieder erschienenen Seite zur Anmeldung. Ich darf als Anwender einfrach wieder einen Benutzernamen eingeben oder auswählen. Das könnte Microsoft sicher besser machen, indem der Admin des Tenant ebenfalls informiert wird.

Das Problem ist natürlich schnell zu lösen, indem Sie auf dem ADFS-Server folgende drei Zeilen eingeben. (Natürlich mit ihrer Domains)

Connect-MsolService
Set-MsolADFSContext -Computer nawadfs.netatwork.de
Update-MsolFederatedDomain -DomainName netatwork.de

Damit exportiere ich das Signing-Zertifikat der lokalen ADFS-Installation neu in die Cloud.

Weitere Links