Windows Admin Center SSO - 夜莺博客

Windows Admin Center SSO

Original article: Windows Admin Center SSO — theDXT (Daniel Keer)

If you’ve installed Windows Admin Center (WAC) on a domain joined server and you connect to another domain joined system you’ll see a message similar to this.

Image 3

Having to login multiple times is annoying so here’s how to make the Single Sign On work with WAC using Kerberos constrained delegation.

Connect to a domain controller as a domain admin.

Edit this script to match what you need.

$SERVER = "SERVER YOU WANT TO ENABLE SSO ON"
$WAC = "WAC SERVER NAME"

Set-ADComputer -Identity (Get-ADComputer $SERVER) -PrincipalsAllowedToDelegateToAccount (Get-ADComputer $WAC)

Run the script.

After that you can connect to that system from WAC using SSO. (You may need to reboot your WAC server for the changes to take effect if you’ve already hit the error).

Background: why Windows Admin Center asks twice

Windows Admin Center is a two-hop architecture, and that is the whole reason the prompt appears. Your browser opens a session against the WAC gateway, which runs as a service on a management server. The gateway then talks to the managed node over WinRM and SMB — TCP 5985 for HTTP or 5986 for HTTPS, plus TCP 445 for file operations and the certificate, registry and services tools.

On the first hop your browser authenticates with Kerberos through Negotiate, so the gateway receives a service ticket for itself. To make the second hop it needs credentials it can present as you to the target server. Windows can do that in exactly two ways. It can take the Kerberos ticket you were issued and forward it — that is delegation, which has to be explicitly configured because it lets one machine impersonate a user against another. Or it can ask for your credentials again and hold them in memory so it can replay them, which is what CredSSP does. CredSSP works out of the box and is the reason the gateway can offer you a working fallback, but it means typing your password into the browser and leaving it in the gateway process, which most security teams would rather avoid.

When neither path is available, WAC has nothing to send on the second hop, so the UI quietly falls back to prompting you per connection — the message in the screenshot above. The fix is to give the target computer an explicit list of principals that are allowed to delegate to it. That list lives in the msDS-AllowedToActOnBehalfOfOtherIdentity attribute of the target computer object and is what PowerShell exposes as PrincipalsAllowedToDelegateToAccount. This is resource-based constrained delegation: the permission is granted on the resource, by the resource's owner, and the delegating machine never needs to be marked as trusted for delegation in the classic sense.

Prerequisites

  • Windows Admin Center in gateway mode, installed on a server that is a member of the same domain (or a trusted domain) as the targets.
  • Domain functional level 2012 or later. PrincipalsAllowedToDelegateToAccount was introduced with Windows Server 2012; on an older level the attribute cannot be written.
  • Rights to modify the target computer objects. Domain Admin is the easy answer, but a delegated OU-level permission to write the relevant attribute on computer objects is enough and is better practice.
  • The RSAT Active Directory PowerShell module on whichever machine you run the commands from. On a workstation:
    Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
    Import-Module ActiveDirectory
    

    On a server, the feature name is shorter:

    Install-WindowsFeature RSAT-AD-PowerShell
    
  • Healthy Kerberos prerequisites. Both machines must resolve each other's FQDN forward and reverse, and their clocks must agree within five minutes. Delegation failures caused by DNS or clock skew are far more common than genuine configuration mistakes.
  • Use the FQDN in the browser, not the IP address. Kerberos binds to a service principal name, and browsing to https://10.0.0.5 gives the browser nothing to ask a ticket for, so it silently uses NTLM and delegation can never happen.
  • WinRM enabled on the target. Confirm from the WAC server with Test-WSMan -ComputerName target.contoso.com, and enable it with Enable-PSRemoting -Force on the target if it is off.

Step by step

Step 1 — find the two computer objects and confirm the module works

Import-Module ActiveDirectory

Get-ADComputer -Identity 'WAC01'   | Select-Object Name, DistinguishedName
Get-ADComputer -Identity 'SRV01'   | Select-Object Name, DistinguishedName

Use the real computer names here, not the FQDN of the service, and confirm you are pointed at a writable domain controller. If you are working across domains, add -Server dc01.contoso.com and, when the account running the shell is not in the target domain, -Credential (Get-Credential).

Step 2 — capture the current state first

Always record what the attribute contained before you touch it. This makes the change reversible in one command and gives you something to point at when someone asks who widened the delegation scope.

Get-ADComputer -Identity 'SRV01' -Properties PrincipalsAllowedToDelegateToAccount |
    Select-Object Name,
        @{ n = 'DelegatesTo'; e = { ($_.PrincipalsAllowedToDelegateToAccount.Name -join ', ') } }

An empty DelegatesTo means nothing can currently delegate to this server, which is the state that produces the extra login prompt.

Step 3 — grant the delegation (the original script)

$SERVER = "SERVER YOU WANT TO ENABLE SSO ON"
$WAC = "WAC SERVER NAME"

Set-ADComputer -Identity (Get-ADComputer $SERVER) -PrincipalsAllowedToDelegateToAccount (Get-ADComputer $WAC)

Two things to understand about this one line. First, the cmdlet writes to the target computer, so the access required is on $SERVER, not on $WAC. Second, the parameter replaces the whole list rather than appending to it, which is what you want for a first-time configuration and exactly what you must not do by accident on a server that already delegates to something else.

Step 4 — apply it to a list of servers

$wac     = Get-ADComputer -Identity 'WAC01'
$servers = Get-Content -Path .\servers.txt

$results = foreach ($s in $servers) {
    if ([string]::IsNullOrWhiteSpace($s)) { continue }
    try {
        Set-ADComputer -Identity $s -PrincipalsAllowedToDelegateToAccount $wac -ErrorAction Stop
        [pscustomobject]@{ Server = $s; Status = 'Granted' }
    } catch {
        [pscustomobject]@{ Server = $s; Status = "Failed: $($_.Exception.Message)" }
    }
}

$results | Format-Table -AutoSize
$results | Export-Csv -NoTypeInformation -Path .\sso-delegation.csv

A per-server try/catch matters here. Without it a single misspelled name, or one server whose object is protected, ends the loop and leaves you guessing which of the remaining servers were configured.

Step 5 — add a second gateway without clobbering the first

Because the parameter replaces the list, add a new delegate by reading the existing one, combining, and writing back. Passing a single object to a server that already delegates elsewhere will silently remove the previous entry.

$target  = Get-ADComputer 'SRV01' -Properties PrincipalsAllowedToDelegateToAccount
$current = @($target.PrincipalsAllowedToDelegateToAccount)
$add     = @(Get-ADComputer 'WAC02')

$new = @($current + $add | Sort-Object DistinguishedName -Unique)
$new | Select-Object Name, DistinguishedName

Set-ADComputer -Identity $target -PrincipalsAllowedToDelegateToAccount $new

To revoke, build the list the same way and subtract:

$remove = (Get-ADComputer 'WAC02').DistinguishedName
$keep   = @($current | Where-Object { $_.DistinguishedName -ne $remove })
Set-ADComputer -Identity $target -PrincipalsAllowedToDelegateToAccount $keep

To clear the attribute entirely and return the server to its original behaviour, pass $null:

Set-ADComputer -Identity 'SRV01' -PrincipalsAllowedToDelegateToAccount $null

Step 6 — restart the gateway and clear stale tickets

Delegation is evaluated when a ticket is issued, and tickets last for hours. If you hit the original error before making the change, the gateway and your client are both still holding Kerberos tickets that were issued under the old rules, which is why a restart is often required to see any difference.

# Confirm the service name on your build before restarting it
Get-Service | Where-Object DisplayName -like '*Admin Center*'

Restart-Service -Name ServerManagementGateway

Then purge the cached tickets on the gateway and on your own workstation, and close every existing WAC browser session — an open tab keeps using its old ticket even after a refresh.

klist
klist purge

Verify it worked

Read the attribute back and confirm the gateway is listed:

Get-ADComputer -Identity 'SRV01' -Properties PrincipalsAllowedToDelegateToAccount |
    Select-Object -ExpandProperty PrincipalsAllowedToDelegateToAccount |
    Select-Object Name, DistinguishedName

Then prove delegation independently of the browser. From the WAC server, open a PowerShell session as a normal user and connect to the target over WinRM. This second hop uses exactly the same delegation path WAC relies on, so if it works, the delegation is correct and any remaining prompt is a client-side caching problem rather than a directory problem.

whoami
Enter-PSSession -ComputerName SRV01.contoso.com
hostname
Exit-PSSession

Finally, confirm the sign-in actually used Kerberos on the target. On SRV01, check the Security log for an 4624 event with logon type 3 and authentication package Kerberos, filtering to the account you used:

Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4624 } -MaxEvents 200 |
    Where-Object { $_.Message -match 'Kerberos' -and $_.Message -match 'Logon Type:\s+3' } |
    Select-Object -First 5 TimeCreated, Message

In the WAC UI itself, reconnect to the server and open a tool that needs the second hop — Files, for example. No prompt plus a working tool is the end-to-end proof. If the session connects but the tools error out, the delegation is not being used and the browser is still on NTLM.

Common problems

Still prompted after the change. Work through it in this order: is the browser address the FQDN rather than an IP; has the WAC service been restarted; has klist purge been run on both the gateway and the client; is DelegatesTo actually populated on the target; and is the account you are signed in with a domain account rather than a local one.

“The operation is not supported on this object” or access denied when writing the attribute. You are editing a protected object, or your account has no write permission on it. Objects with adminCount = 1 — anything that has been a Domain Admin, or is inside the default protected OUs — have their access control list re-stamped by AdminSDHolder every hour, so a temporary grant will not stick.

Domain controllers. A DC's computer account is deliberately marked Account is sensitive and cannot be delegated, so it cannot be impersonated outward and the technique above does not apply cleanly to managing a DC. Where you must manage DCs from WAC, accept the explicit-credentials path for those connections, or scope the WAC gateway to member servers only.

“The clock skew is too great.” Kerberos issues tickets with a limited lifetime, and a gap of more than five minutes between the two machines invalidates them. Check that both hosts are synchronising with the domain hierarchy — w32tm /query /status — rather than with an external pool.

WinRM is not listening. Delegation cannot be used if the transport itself is unavailable. Test-WSMan from the WAC server is the fastest way to rule this out, and the firewall rule group Windows Remote Management must be enabled on the target.

The change has no effect on the third hop. Kerberos delegation is single-hop. If a tool on the target then tries to reach a further server, the impersonated identity will not follow it, and that is by design rather than a misconfiguration.

Can I delegate to a group instead of each gateway? Yes — if you have multiple WAC gateways, create a group, make the gateway computer accounts members, and pass the group object in place of a single Get-ADComputer. Adding a new gateway then means adding it to the group once.

Is this the same as “Trust this computer for delegation to any service”? No, and it is deliberately narrower. Unconstrained delegation lets the gateway impersonate any user against any service that trusts it, which is why it is treated as a high-risk configuration. Resource-based constrained delegation names one delegating principal and one target, and is scoped to the protocol transition WAC actually needs.

Where does this sit next to Entra ID and modern auth? This is an on-premises Kerberos control and is unrelated to cloud sign-in. If your servers are being joined to Entra ID, or you are asking users to sign in with a second factor at the Windows logon screen, the delegation configuration still applies and still has to be maintained alongside it.

More reading

If you want to know more you can read Microsoft’s document on it here. The same document covers the CredSSP fallback and the group policy requirements for the gateway, which are worth reading before you decide to standardise on delegation.

Related posts on this site: