6.6 KiB
Service account & Active Directory
The service runs as LocalSystem out of the box. That's right for local-only scripts and read-only AD queries (LocalSystem authenticates to the network as the machine account, which Authenticated Users includes by default). It is wrong for hooks that need to modify AD — passwords, group memberships, computer objects.
This page covers the four real-world choices and how to switch.
The four options
| Account | Network identity | When to use |
|---|---|---|
LocalSystem (default) |
Computer account DOMAIN\MACHINE$ on a domain-joined host; nothing on a workgroup host |
Default. Local file ops, simple PowerShell, read-only AD queries. Most powerful local account — any hook running under it has full local rights. |
LocalService |
None | Don't. Cannot talk to a domain controller. Listed only to rule it out. |
NetworkService |
Same machine account as LocalSystem | Slightly less local privilege than LocalSystem, same network identity. Rarely the right pick. |
Domain user (DOMAIN\svc-webhookserver) |
That user | Use when hooks need write access to AD and you can't use a gMSA. You own password rotation. |
gMSA (DOMAIN\svc-webhookserver$) |
That gMSA | Recommended for AD-write workloads. AD generates and rotates the password automatically every 30 days. Requires domain functional level 2012+. |
Switching the service account at install time
Pass -ServiceAccount to install-service.ps1 (or to the deploy / dev launcher):
# Domain user
& "C:\Program Files\WebhookServer\scripts\install-service.ps1" `
-BinaryPath "C:\Program Files\WebhookServer\WebhookServer.Service.exe" `
-ServiceAccount "CONTOSO\svc-webhookserver" -Password "..."
# gMSA - note trailing $ and no -Password
& "C:\Program Files\WebhookServer\scripts\install-service.ps1" `
-BinaryPath "C:\Program Files\WebhookServer\WebhookServer.Service.exe" `
-ServiceAccount 'CONTOSO\svc-webhookserver$'
Or do it manually with sc.exe if the service is already installed:
sc.exe stop WebhookServer
sc.exe config WebhookServer obj= 'CONTOSO\svc-webhookserver$'
sc.exe start WebhookServer
gMSA setup (recommended for AD writes)
A gMSA is a Group Managed Service Account. Active Directory generates and stores its password and rotates it every 30 days; the host machine account retrieves the password as needed. You never see or store it. This is the cleanest pattern for production.
One-time domain setup
If your domain has never used gMSAs, create the KDS root key (only needed once per domain):
# from a Domain Admin PowerShell, on any DC
Add-KdsRootKey -EffectiveImmediately
# in production wait 10 hours for replication; in a lab, override:
# Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10))
Create the gMSA
# from a DC, with AD PowerShell module loaded
New-ADServiceAccount -Name svc-webhookserver `
-DNSHostName webhook01.contoso.local `
-PrincipalsAllowedToRetrieveManagedPassword "DOMAIN\WebhookHosts"
PrincipalsAllowedToRetrieveManagedPassword is the security group containing the computer accounts allowed to use the gMSA. Add your webhook host(s) to that group:
Add-ADGroupMember -Identity 'WebhookHosts' -Members 'WEBHOOK01$'
# the host needs to reboot OR have its kerberos ticket flushed for the new group membership to apply
Install the gMSA on the host
On the webhook server machine itself:
# from elevated PowerShell, AD PowerShell module installed (RSAT)
Install-ADServiceAccount svc-webhookserver
Test-ADServiceAccount svc-webhookserver # should return True
If Test-ADServiceAccount returns False, check:
- Host is in the
WebhookHostsgroup (or whoever's inPrincipalsAllowedToRetrieveManagedPassword) - Host has been rebooted since being added to the group
- KDS root key has had time to propagate (10 hours by default)
Configure the service to use it
# from elevated PowerShell on the webhook host
sc.exe stop WebhookServer
sc.exe config WebhookServer obj= 'CONTOSO\svc-webhookserver$'
sc.exe start WebhookServer
Note the trailing $. There is no password parameter for gMSAs. The trailing $ is what tells the SCM "look up this account in AD as a managed service account, retrieve its password automatically."
Grant AD permissions
Give the gMSA only what it needs. For a typical "reset user passwords" workload:
# Delegate "Reset password and force change at next logon" on a specific OU
$ou = "OU=Standard Users,DC=contoso,DC=local"
dsacls $ou /I:S /G "CONTOSO\svc-webhookserver$:CA;Reset Password;user"
dsacls $ou /I:S /G "CONTOSO\svc-webhookserver$:WP;pwdLastSet;user"
…or use the GUI Delegation of Control wizard in Active Directory Users and Computers.
Domain user (fallback when gMSA isn't available)
# 1. Create the user (one time)
New-ADUser -Name "svc-webhookserver" -SamAccountName "svc-webhookserver" `
-AccountPassword (Read-Host -AsSecureString "password") -Enabled $true `
-PasswordNeverExpires $true -CannotChangePassword $true
# 2. Grant "Log on as a service" right on the host:
# secpol.msc -> Local Policies -> User Rights Assignment -> Log on as a service
# Add CONTOSO\svc-webhookserver
# 3. Configure the service:
sc.exe config WebhookServer obj= "CONTOSO\svc-webhookserver" password= "..."
You own password rotation. When you change the password in AD, also update the service via sc.exe config WebhookServer password= "newpw" and restart it.
What changes for hooks when you switch the service account
- Service mode hooks now run as the new account. PowerShell
whoamifrom inside a hook will show the new identity. - InteractiveUser hooks stop working if you switch off LocalSystem. Only SYSTEM can call
WTSQueryUserToken. If you need both AD-write hooks and UI-on-desktop hooks, pick one of:- Keep service as LocalSystem and use SpecificUser mode for AD-write hooks
- Switch service to a gMSA / domain user and drop UI hooks (or move them to a separate Webhook Server instance running as LocalSystem)
- SpecificUser hooks continue to work regardless. They use a separate
LogonUsertoken per call.
Verifying the switch worked
After changing the service account, restart the service and add a quick diagnostic endpoint:
slug: whoami
auth: none
executor: Windows PowerShell
inline command: whoami; whoami /groups
Hit it and verify the output matches the account you configured. The first line should be domain\svc-webhookserver (or domain\machine$ for LocalSystem on a domain-joined host).