Windows Hello for Business cloud trust is the latest addition to deployment methods that can be used for Windows Hello for Business.
Windows Hello for Business cloud trust
Windows Hello for Business is Microsofts passwordless logon solution that uses an asymmetric key pair for authentication instead of using username and password. The private key is securely stored in the Trusted Platform Module (TPM), preventing the private key from getting leaked. All the technical complexity of the logon process is completely transparent to the user, she only has to unlock the credentials stored in the TPM using either a PIN or some kind biometrics. This brings this method en pair with what users are used from their smartphones.
Depending on the deployed Windows Hello for Business method used the authentication process is different. In case of hybrid cloud trust Entra ID (Azure AD) is the initial point of contact for the client.
Hybrid Entra ID (Azure AD) join authentication using Entra ID (Azure AD) Kerberos (cloud trust)
The user unlocks the credentials stored in the TPM
The Cloud AP requests a nonce from Entra ID (Azure AD)
This nonce is signed with the private key part of the credentials and send back to Entra ID (Azure AD)
Entra ID (Azure AD) checks the used key against an set of public keys stored as part of the user object
If this check is successful it will check is the nonce is also valid and
Sends back the Primary Refresh Token (PRT) to the client. But not only the PRT is provided but also a partial Kerberos TGT
The PRT is then stored securely in the TPM
To get access to on-premises resources the client uses the partial Kerberos TGT to send an TGS-REQ to an on-premises Domain Controller
The domain controller validates the TGS-REQ and returns a full krbtgt as part of an TGS-REP
This krbtgt can then be used to request additional TGT for different services when needed.
This description is already very technical, but let’s pop open the hood even more and see how this is all possible.
And while we are at it I will show you, how you can create your own “Entra ID (Azure AD) Kerberos” to provide the full krbtgt ticket to every eligible client, even when no domain controller is in direct line of sight of the computer.
Why use a KDC proxy?
One of the most difficult tasks when using Active Directory is to protect your domain controllers. Legacy Windows Clients need to have line of sight access to at least one of your domain controllers. This is required to provide services like Kerberos and SMB for group policies and logon scripts.
Legacy architecture on-premises
With modern clients, managed through Intune, those requirements got fewer and were reduced to Kerberos (TCP+UDP/88). But still some kind of direct communication was still needed.
This is were the KDC proxy comes into play. This service is a broker service between the client and domain controller. The communication is encrypted using TLS and limited to one port (default TCP/443).
This service receives Kerberos communication encapsulated in TLS encrypted HTTP. The client must use the Kerberos Key Distribution Center (KDC) Proxy Protocol [MS-KKDCP] to send messages to this service.
Modern architecture with Entra ID (Azure AD) and Intune
Because TLS is used as underlying protocol the same security features apply (e.g. forward secrecy).
Of course, the services target with the Kerberos TGT still need to be exposed to the client.
Notiz
This service is by no means tight to any cloud service and can be used to provide Kerberos over the Internet even in legacy environments. In those scenarios the support for Kerberos change password messages will help to keep the password of the user in sync.
Lab setup
Windows Hello for Business cloud trust
To enable Windows Hello for Business cloud trust you must create multiple objects in your on-premises and cloud environment. Microsoft automated this process using the Set-AzureADKerberosServer cmdlet.
The following commands must be executed on a client with line of sight to an domain controller and internet access.
Install-Module-NameAzureADHybridAuthenticationManagement-AllowClobber$domain=Get-ADDomain|Select-Object-ExpandPropertyDNSRoot# UPN of an Azure Active Directory global administrator$userPrincipalName="administrator@contoso.onmicrosoft.com"Set-AzureADKerberosServer-Domain$domain-UserPrincipalName$userPrincipalName
If you have more than one domain you will need to create one Entra ID (Azure AD) Kerberos object for each domain.
This cmdlet creates an disabled on-prem user called krbtgt_AzureAD, note that the samAccountName will be different krbtgt_[0-9]{5}.
It also creates a computer account named AzureADKerberos which represents the Read-Only domain controller object.
So if you had a familiar feeling when reading the username you are right. Microsoft reuses some of the technology already built into Windows Server 2008.
The krbtgt_AzureAD account is connected to the computer object using the msds-KrbTgtLinkBl attribute.
But the real “magic” part of this account creation is the generated password. The account password, or to be more accurate the hash, is not only set to the krbtgt_AzureAD user account but also is send to Entra ID (Azure AD). The cloud directory stores this hash with a mapping of the domain it is valid in.
Creation of objects for Entra ID (Azure AD) Kerberos
Notiz
Of course, as with all Kerberos krbtgt users, this accounts password has to be changed regularly. Do not use your process you have in place for other krbtgt account. The cmdlet offers the parameter -RotateServerKey which must be used to keep the cloud entry in sync as well.
KDC proxy
You can use any current version of Windows to provide KDC proxy capabilities. The service is part of the core OS but must be configured and enabled.
You will need to deploy a TLS certificate on this server before you can start. Use a publicly signed certificate to make sure every client trusts this service even when Intune has not yet deployed custom root certificates.
The next steps are quite easy, and I have documented them in the following script.
Warnung
The script assumes a certificate containing the subject name kdcproxy. Please change this to apply to your environment.
# Generate a new GUID for the application$GUID=New-Guid|Select-Object-ExpandPropertyGuid# Get certificate thumbprint that should be used$Thumbprint=Get-ChildItem'Cert:\LocalMachine\My\'|?Subject-match"kdcproxy"|Select -ExpandPropertyThumbprint# Grant permissions to the Network Service account to the Url https://+:443/KdcProxy netshhttpaddurlaclurl=https://+:443/KdcProxyuser="NT AUTHORITY\Network Service"# Create a certificate binding on all ip addressesAdd-NetIPHttpsCertBinding-ipport0.0.0.0:443-CertificateHash$Thumbprint-CertificateStoreName"MY"-ApplicationId$GUID-NullEncryption$false# Disable client authentication New-ItemProperty-PathHKLM:\SYSTEM\CurrentControlSet\Services\KPSSVC\Settings-NameHttpsClientAuth-TypeDword-Value0x0-Force# Enable password authentication, we discuss this laterNew-ItemProperty-PathHKLM:\SYSTEM\CurrentControlSet\Services\KPSSVC\Settings-NameDisallowUnprotectedPasswordAuth-TypeDword-Value0x0-Force# Create an incoming firewall ruleNew-NetFirewallRule-DisplayName"Allow KDC proxy TCP/443"-DirectionInbound-ProtocolTCP-LocalPort443# Set the KDC proxy service to automaticSet-Service-StartupTypeAutomatic-Namekpssvc# Start the KDC proxy Start-Servicekpssvc
KDC proxy settings
Registry setting
Type
Example
Description
Needed
HttpsClientAuth
Dword
0
Use the client certificate for client authentication
Yes
DisallowUnprotectedPasswordAuth
Dword
0
Allow the usage of password as authentication method
No*
HttpsUrlGroup
MultiString
+:8443:KdcProxy
Change the port and Url of the KDC service
No
* This setting is relevant for a specific use case. Please bear with to decide if you want this enabled or not.
Client
The client used in this setup is 100% Entra ID (Azure AD) joined. No hybrid trust is used, and the client has no network connection to the domain controller. It is only connected to the internet.
Windows Hello for Business
Deploy the custom template with ./Device/Vendor/MSFT/PassportForWork/<TENANTID>/Policies/UseCloudTrustForOnPremAuth set to True (Type Boolean) and enable Windows Hello for Business.
Warnung
Replace TENANTID with you own tenant id.
If you want to make those changes on a test device, you can also set this using gpedit.msc
Administrative Templates > Windows Component
Setting
Value
Use Windows Hello for Business
Enabled
Use cloud trust for on-premises authentication
Enabled
Gefahr
Always enforce the usage of TPM in real case scenarios to avoid attacks on the secrets used. This applies to Intune and group policies.
KDC proxy
Create a device configuration profile for Windows 10+ devices, select “Settings catalog (preview)” and search for Kerberos.
Use “Administrative Templates” -> System -> Kerberos and set the following settings
Setting
Value
Disable revocation checking for the SSL certificate of KDC proxy servers
Disabled
Specify KDC proxy servers for Kerberos clients
Enabled
Name: int.c4a8korriban.com
Value: <https kdcproxy.c4a8korriban.com:8443 />
Change the name of the dns suffix to your domain name. You can also use * as a catch all or .domain.com as a wildcard.
You can also set the exact same setting using group policies.
Initial logon process
End User experience
The user logs into the device using her username and password.
Directly after the logon screen she will be prompted to setup Windows Hello for Business.
Setup Windows Hello for Business
Set PIN for Windows Hello for Business
Immediately after the login the user checks for Kerberos tickets using klist. And voila the krbtgt is already here.
Kerberos ticket on Entra ID (Azure AD) joined device
Notiz
As you can see in the above screenshot the value of Kdc Called is not the domain controller but the FQDN of the KDC proxy.
Azure AD
Immediately after the Windows Hello for Business registration of the users, the Windows Hello for Business public key will show up in Entra ID (Azure AD). Check the ‘Authentication methods’ blade for the user.
Windows Hello for Business in the authentication methods blade
Active Directory
In a Hybrid Entra ID (Azure AD) joined Key Trust Deployment the client could not immediately log out and log in using Windows Hello for Business.
This is because the Entra ID (Azure AD) Connect has not yet sync the public key. Only one of the currently two registered Windows Hello for Business keys is present in the msDS-KeyCredentialLink attribute. But this is totally irrelevant for this use case, because the certificate is not used to authenticate to on-prem resources as we will see in a bit.
msDS-KeyCredentialLink registered to the user
After the sync is completed, both keys are present in the on-premises Active Directory as well.
msDS-KeyCredentialLink synced after setup
Notiz
Because this behavior is the same as when you use the Hybrid Entra ID (Azure AD) joined Key Trust Deployment of WHfB the migration scenario between those two is quite easy. Just follow the prerequisites and reconfigure the existing clients.
KDC proxy
On the KDC proxy server you will see multiple events, two for each Kerberos request send from the client.
The first one with event Id 400 is just a confirmation that An HTTP request was received.
The next event with id 307 contains which domain controller was used for this request.
Rediscovered KDC 10.0.10.10(\\DC01.int.c4a8korriban.com) for domain INT.C4A8KORRIBAN.COM
Kerberos deep dive
When looking at the Kerberos communication on the wire, you will see the default behavior for a password login. The only exception being that no additional TGS is requested directly after the login because the Entra ID (Azure AD) joined machine does not rely on Kerberos based services and therefor does not have the need for any Ticket Granting Tickets (TGT).
AS-REQ - AS-REP using username + password
AS-REQ
The authentication service request is sent to the domain controller requesting service krbtgt/int.c4a8korriban.com
KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED
Because the the initial AS-REQ is missing any kind of pre-auth information this request fails and the KDC requests some kind of pre authentication and sends the salt to use for pre-auth
AS-REQ
Now the client resends the AS-REQ using the encrypted current timestamp for pre-auth.
Left: AS-REQ missing PA-ENC-TIMESTAMP - Right: AS-REQ including PA-ENC-TIMESTAMP
AS-REP
After verifying the information provided, the authentication reply for krbtgt/int.c4a8korriban.com is returned containing the privilege attribute certificate (PAC).
Involved in this communication were the secrets of krbtgt and takeshi.kovacs, the end user.
Secrets used for AS-REQ - AS-REP using username + password
DisallowUnprotectedPasswordAuth
When DisallowUnprotectedPasswordAuth is set to 0 the KDC proxy will allow the user to retrieve a krbtgt using username and password.
To enhance security you should set this setting to 1 or delete the registry key all together. The KDC proxy will block every AS-REQ that sends an unprotected pa-timestamp. When using Windows Hello for Business or FIDO this is not the case, as I will show you later.
Thank you
A big shout out to Steve Syfuhs (@stevesyfuhs) for providing me with information about the mechanism behind DisallowUnprotectedPasswordAuth.
In the KDC proxy event log you will see the following information when this happens.
The account (Domain: int.c4a8korriban.com, User: takeshi.kovacs) is rejected due to the usage of an unarmored Kerberos message
The client itself receive the following error, when using klist get krbtgt
Logon failure: The machine you are logging onto is protected by an authentication firewall.
When looking at the network traffic you can see the initial AS-REQ is send to the domain controller and an AS-REP is send back to the client.
Kerberos communication when DisallowUnprotectedPasswordAuth = 1 and username + password is used
But after this the KDC proxy will block the next AS-REQ requests send by the client that are based on the initial communication with an HTTP error code 403 - Forbidden.
HTTP/2 communication when DisallowUnprotectedPasswordAuth = 1 and username + password is used
HttpsClientAuth
HttpsClientAuthmust be set to 0 otherwise the all connections will fail, even when the Windows Hello for Business certificate is replicated to the on-prem AD.
This is because the root certificate of this certificate (e.g. MS-Organization-P2P-Access [2022]) is not trusted by the KDC proxy server and a validation is not possible.
Windows Hello for Business login
Now let’s logoff and use Windows Hello for Business to login again and check the kerberos tickets with klist.
Kerberos tickets after Windows Hello for Business login
Again the KDC proxy was used to provide the TGT to the user.
Notiz
The KERBEROS.MICROSOFTONLINE.COM ticket is present because this user is also configured to use Entra ID (Azure AD) Kerberos. Kerberos in the cloud everywhere.
Azure AD
The Cloud Authentication Provider (CloudAP) was used to login to the computer. Windows Hello for Business unlocked the private key in the TPM of the machine to sign the nonce while logging in and Entra ID (Azure AD) provided an PRT and in addition to that, an TGT for krbtgt/int.c4a8korriban.com was part of the response. You cannot see this ticket using klist and as long as you have TPM enabled you also cannot extract it.
Active Directory
The on-premises Active Directory had nothing to do with the login process until the client requested a krbtgt. You will see event id 4769 originating from the internal IP address of the KDC proxy requesting a service ticket for krbtgt.
A Kerberos service ticket was requested from the DC
KDC proxy
Since the KDC proxy eventlog is not very helpful, I decided to record and decrypt the TCP packets using Wireshark and mitmproxy.
HTTP/2 data flow
As you can see the communication is based on HTTP/2 and there are two main interactions.
Each representing a TGT exchange containing the Kerberos data.
The client sends, using the HTTP POST method, two DATA frames to the KDC proxy. This is a Kerberos TGS-REQ.
HTTP2 POST request to /KdcProxy
After receiving this information the KDC proxy will reply with a status code 200 and two DATA frames. This is a Kerberos TGS-REP.
Kerberos ticket within the data flow
Sadly I could not convince Wireshark to decode the Kerberos data within the HTTP/2 packet to compare them to the packets send from the KDC proxy to the DC. But as the protocol documentation states:
KKDCP does not alter the syntax of any Kerberos messages.
Nice to know
Sadly the magic in the second packet does not refer to the magical experience, but its the description Wireshark uses for HTTP/2 connection preface.
Kerberos deep dive
When you look at the Kerberos tickets send to the domain controller, you will note that this conversation does not start using a AS-REQ ticket but a TGS-REQ instead. This is because the client already was provided with a valid Kerberos ticket from Entra ID (Azure AD), therefore it is not necessary to begin using an authentication service request.
Kerberos tickets using Windows Hello for Business login
Notiz
I cheated a little bit and used klist purge and klist get krbtgt for the result in the screenshot. The initial login using Windows Hello for Business is a bit messier. I will discuss this in the next section for anybody interested in all the details.
TGS-REQ
This kerberos packet is sent to the domain controller with the intent to request a full krbtgt for the user (TGS-REQ) as well as the NTLM hash of the user (KERB-KEY-LIST-REQ), using the already existing krbtgt that the user received from Entra ID (Azure AD). Partial TGT send to the DC in exchange for a full TGT and NTLM hash
The existing krbtgt is issued for the user by server login.microsoftonline.com and contains no groups. cname value in TGS-REQ encrypted by krbtgt_24125No group membership and server login.microsoftonline.com
This ticket is encrypted by the user krbtgt_24125@INT.C4A8KORRIBAN.COM which is the user generated the Set-AzureADKerberosServer cmdlet that acts as a read only domain controller. Because Entra ID (Azure AD) knows the password (not in cleartext) of this user, it uses it to encrypt the enc-part data.
TGS-REP
The on-premises domain controller exchanges the partial krbtgt for an full krbtgt including the group memberships. Because the on-premises DC also is aware of the secret of krbtgt_24125 it can validate the data send in the request. TGT-REP with 102 group memberships
This reply also includes the requested NTLM hash. KERB-KEY-LIST-REP contains the NTLM hash of the user
This ticket is encrypted by: krbtgt@INT.C4A8KORRIBAN.COM This ticket is encrypted by: krbtgt@INT.C4A8KORRIBAN.COM
TGS-REQ
The client now has a full TGT but is missing the PAC-OPTIONS information that are normally part of the AS-REP. So it sends another request to get this information as well.
PAC-OPTIONS-REQ requested as part of the TGS-REQ
This ticket is encrypted by: krbtgt@INT.C4A8KORRIBAN.COM
TGS-REP
The resulting reply contains almost all the same information but includes the PAC-OPTIONS and is missing the KERB-KEY-LIST-REP (NTLM Hash) PAC-OPTIONS in second TGS-REP
This ticket is encrypted by: krbtgt@INT.C4A8KORRIBAN.COM
The full story
Login using Windows Hello for Business
As you can see the initial Kerberos communication is a lot chattier that just klist get krbtgt. The exact reason for this is unclear to me, but I guess it has something to do with the different authentication packages that LSA asks if they can perform some action with the provided credentials. Steve Syfuhs goes into great detail on this behavior in his blog post What Happens When you Type Your Password into Windows?
REQ
REP
PA-data
Comment
Result
TGS-REQ
TGS-REP
pA-TGS-REQ pA-KERB-KEY-LIST-REQ
The request is encrypted by the RODC krbtgt_24125, the response by krbtgt
Kerberos ticket and NTLM hash received
TGS-REQ
TGS-REP
pA-TGS-REQ pA-PAC-OPTIONS
The request is encrypted by the krbtgt, the response by krbtgt
Kerberos ticket and PAC options received
AS-REQ
AS-REP
Unknown: 150 pA-PAC-REQUEST
The PA-data type 150 is not documented but somehow understood by the KDC proxy and even with DisallowUnprotectedPasswordAuth disabled the ticket is forwarded to the DC.
The request fails with eRR-PREAUTH-REQUIRED
AS-REQ
AS-REP
pA-PK-AS-REQ pA-PK-OCSP-RESPONSE pA-PAC-REQUEST
The user certificate is used for PKINIT authentication*
The request fails with eRR-CLIENT-NAME-MISMATCH because the certificate is unknown
Those requests are repeated multiple times. Four times for TGS-REQ <> TGS-REP and two times for AS-REQ <> AS-REP.
* Screenshots of the certificate used in the PKINIT flow request.
Certificate used to sign the AS-REQ
User certificate in Windows
With domain controller certificate
Should you come from a intact key trust implementation and the domain controller used in the flow has a valid certificate the behavior around PKINIT changes. This is most likely because the key trust mechanism kicks in.
Successful PKINIT
REQ
REP
PA-data
Comment
Result
AS-REQ
AS-REP
Unknown: 150 pA-PAC-REQUEST
The PA-data type 150 is not documented but somehow understood by the KDC proxy and even with DisallowUnprotectedPasswordAuth disabled the ticket is forwarded to the DC.
The request fails with eRR-PREAUTH-REQUIRED
AS-REQ
AS-REP
pA-PK-AS-REQ pA-PK-OCSP-RESPONSE pA-PAC-REQUEST
The user certificate is used for PKINIT authentication*
PK-AS-REP is returned successfully
Those requests are repeated the same as in the first scenario.
FIDO2
When using a FIDO security key to log into this computer the flow deviates a little bit from the Windows Hello for Business login. Initially no TGT is requested after you log in but it can be requested using klist get krbtgt or will be automatically requested as soon as an Kerberos based resource is accessed.
The actual Kerberos flow when triggered by klist get krbtgt is exactly as described above.
FIDO used for login and krbtgt requested manually
When accessing a website this behavior is triggered in the background and in additional to the TGT a TGS for the web service is requested.
Access to a kerberos website
Troubleshooting
If you encounter problems requesting the full krbtgt please check if you receveived a cloud tgt using klist cloud_debug. The “Cloud Primary (Hybrid logon) TGT available” count must be 1 or greater.
Should this be not the case try to refresh you Primary Refresh Token dsregcmd /refreshprt because the last one might still be cached and without the needed partial tgt. Reboot the computer afterwards and try to get a new Kerberos TGT klist get krbtgt.
Reset Windows Hello for Business
When you test different scenarios with Windows Hello for Business it comes in handy to have an easy option to remove the key pair completely.
Login using the user you want to delete the Windows Hello for Business registration for and execute
certutil.exe-DeleteHelloContainer
Windows Hello container deleted
This will delete the certificates related to Windows Hello for Business and after you log off, you will need to use username and password to login again.
Don’t forget to remove the public key from the user object in Entra ID (Azure AD) as well. Navigate to the user and remove Windows Hello for Business in the ‘Authentication methods’ blade.