Windows Hello for Business Cloud Trust and KDC proxy
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.
Source: Microsoft Docs
- 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 fullkrbtgt
as part of anTGS-REP
- This
krbtgt
can then be used to request additionalTGT
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.
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.
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.
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 -Name AzureADHybridAuthenticationManagement -AllowClobber
$domain = Get-ADDomain | Select-Object -ExpandProperty DNSRoot
# 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.
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.
kdcproxy
. Please change this to apply to your environment.# Generate a new GUID for the application
$GUID = New-Guid | Select-Object -ExpandProperty Guid
# Get certificate thumbprint that should be used
$Thumbprint = Get-ChildItem 'Cert:\LocalMachine\My\' | ? Subject -match "kdcproxy" | Select -ExpandProperty Thumbprint
# Grant permissions to the Network Service account to the Url https://+:443/KdcProxy
netsh http add urlacl url=https://+:443/KdcProxy user="NT AUTHORITY\Network Service"
# Create a certificate binding on all ip addresses
Add-NetIPHttpsCertBinding -ipport 0.0.0.0:443 -CertificateHash $Thumbprint -CertificateStoreName "MY" -ApplicationId $GUID -NullEncryption $false
# Disable client authentication
New-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\KPSSVC\Settings -Name HttpsClientAuth -Type Dword -Value 0x0 -Force
# Enable password authentication, we discuss this later
New-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\KPSSVC\Settings -Name DisallowUnprotectedPasswordAuth -Type Dword -Value 0x0 -Force
# Create an incoming firewall rule
New-NetFirewallRule -DisplayName "Allow KDC proxy TCP/443" -Direction Inbound -Protocol TCP -LocalPort 443
# Set the KDC proxy service to automatic
Set-Service -StartupType Automatic -Name kpssvc
# Start the KDC proxy
Start-Service kpssvc
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.
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 |
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.
Immediately after the login the user checks for Kerberos tickets using klist
. And voila the krbtgt is already here.
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.
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.
After the sync is completed, both keys are present in the on-premises Active Directory as well.
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.
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
The authentication service request is sent to the domain controller requesting servicekrbtgt/int.c4a8korriban.com
- KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED
Because the the initialAS-REQ
is missing any kind ofpre-auth
information this request fails and the KDC requests some kind of pre authentication and sends thesalt
to use forpre-auth
AS-REQ
Now the client resends theAS-REQ
using the encrypted current timestamp forpre-auth
.AS-REP
After verifying the information provided, the authentication reply forkrbtgt/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.
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.
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
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.
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
.
HttpsClientAuth
HttpsClientAuth
must 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
.
Again the KDC proxy was used to provide the TGT to the user.
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
.
KDC proxy
Since the KDC proxy eventlog is not very helpful, I decided to record and decrypt the TCP packets using Wireshark and mitmproxy.
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
.
After receiving this information the KDC proxy will reply with a status code 200
and two DATA
frames. This is a Kerberos TGS-REP
.
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.
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.
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 fullkrbtgt
for the user (TGS-REQ
) as well as the NTLM hash of the user (KERB-KEY-LIST-REQ
), using the already existingkrbtgt
that the user received from Entra ID (Azure AD).
The existingkrbtgt
is issued for the user by serverlogin.microsoftonline.com
and contains no groups.
This ticket is encrypted by the userkrbtgt_24125@INT.C4A8KORRIBAN.COM
which is the user generated theSet-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 theenc-part
data.TGS-REP
The on-premises domain controller exchanges the partialkrbtgt
for an fullkrbtgt
including the group memberships. Because the on-premises DC also is aware of the secret ofkrbtgt_24125
it can validate the data send in the request.
This reply also includes the requested NTLM hash.
This ticket is encrypted by:krbtgt@INT.C4A8KORRIBAN.COM
TGS-REQ
The client now has a fullTGT
but is missing thePAC-OPTIONS
information that are normally part of theAS-REP
. So it sends another request to get this information as well. This ticket is encrypted by:krbtgt@INT.C4A8KORRIBAN.COM
TGS-REP
The resulting reply contains almost all the same information but includes thePAC-OPTIONS
and is missing theKERB-KEY-LIST-REP
(NTLM Hash)
This ticket is encrypted by:krbtgt@INT.C4A8KORRIBAN.COM
The full story
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.
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.
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.
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.
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
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.
Additional links
- Windows Hello Cloud Trust
- How Entra ID (Azure AD) Kerberos Works
- What Happens When you Type Your Password into Windows?
- Kerberos FAST Armoring
- Kerberos Explained in a Little Too Much Detail
- Deep dive: How Entra ID (Azure AD) Kerberos works
- Hybrid Cloud Trust Deployment
- Hybrid Entra ID (Azure AD) join authentication using a key
- Hybrid Entra ID (Azure AD) joined Key Trust Deployment
- Enable passwordless security key sign-in to on-premises resources by using Entra ID (Azure AD)
- What is a Primary Refresh Token?
- Registering SSP/AP DLLs
- Kerberos.NET
- [MS-KKDCP]: Kerberos Key Distribution Center (KDC) Proxy Protocol
- [MS-KILE]: Pre-authentication Data
- [MS-KILE]: Key List Request
- [MS-PAC]: Privilege Attribute Certificate Data Structure
- [MS-PKCA]: Public Key Cryptography for Initial Authentication (PKINIT) in Kerberos Protocol
- RFC7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
- HTTP/2 and How it Works