diff --git a/PLAN.md b/PLAN.md index 563a315..7188928 100644 --- a/PLAN.md +++ b/PLAN.md @@ -229,6 +229,35 @@ Order in the request pipeline matters: **IP check runs before auth.** That avoid This covers GitHub, Stripe, Slack, generic CI patterns by tweaking the four fields. +## Service account + +The service itself runs fine under any account — this section is about which account makes sense for the **scripts** the service launches, since they inherit its identity. + +| Account | Network identity | When to use | +|---|---|---| +| `LocalSystem` (default) | Computer account `DOMAIN\MACHINE$` on a domain-joined host; nothing on a workgroup host | Default. Local-only scripts, or read-only AD queries on a domain-joined machine. Most powerful local account — any webhook script effectively runs as SYSTEM. | +| `LocalService` | None — no network credentials | **Don't.** Cannot talk to AD or any other remote resource that requires Windows auth. Listed only to rule it out. | +| `NetworkService` | Computer account, same as LocalSystem | Slightly less local privilege than LocalSystem; same network identity. Rarely worth the switch. | +| Domain user (`DOMAIN\svc-webhookserver`) | That user | Need write/admin operations against AD (password resets, group changes, OU creates). You own password rotation. | +| **gMSA** (`DOMAIN\svc-webhookserver$`) | That gMSA | **Recommended for AD-write workloads.** AD generates and rotates the password automatically. Requires domain functional level 2012+ and `Install-ADServiceAccount` on the host. | + +Install commands by account type: + +```powershell +# LocalSystem (default) +sc.exe create WebhookServer binPath= "C:\path\WebhookServer.Service.exe" start= auto + +# Domain user +sc.exe create WebhookServer binPath= "..." obj= "DOMAIN\svc-webhookserver" password= "..." start= auto + +# gMSA — note the trailing $ and no password= +sc.exe create WebhookServer binPath= "..." obj= "DOMAIN\svc-webhookserver$" start= auto +``` + +`scripts/install-service.ps1` will accept a `-ServiceAccount` parameter that defaults to `LocalSystem` and accepts a domain user or gMSA name. README will document the gMSA setup once for users who need AD writes from their hooks. + +The service code itself makes no assumptions about the account — DPAPI uses `LocalMachine` scope so secret decryption works under any local identity. + ## Secret storage (DPAPI) Endpoint `Secret` is stored in JSON as `{ "encrypted": "" }`. Decrypt only inside the service when needed. The GUI submits secrets in plaintext over the named pipe (local-machine, ACL-restricted), service encrypts before writing. diff --git a/README.md b/README.md index abd9b41..3788222 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,31 @@ sc.exe create WebhookServer binPath= "C:\Program Files\WebhookServer\WebhookServ sc.exe start WebhookServer ``` -`scripts/install-service.ps1` will wrap this once implemented. +`scripts/install-service.ps1` will wrap this once implemented and will accept a `-ServiceAccount` parameter. + +## Service account & Active Directory + +The service runs as `LocalSystem` by default — fine for local-only scripts and read-only AD queries (it authenticates to the domain as the computer account). If your webhook scripts need to **modify** AD (password resets, group changes, etc.), run the service under an account with the right delegated rights: + +- **Recommended: gMSA** — Active Directory generates and rotates the password automatically. + ```powershell + # on a DC, once + New-ADServiceAccount -Name svc-webhookserver -DNSHostName host.domain.local ` + -PrincipalsAllowedToRetrieveManagedPassword "DOMAIN\WebhookHosts" + # on the webhook host + Install-ADServiceAccount svc-webhookserver + sc.exe create WebhookServer binPath= "..." obj= "DOMAIN\svc-webhookserver$" start= auto + ``` + Note the trailing `$` and the absence of `password=`. + +- **Plain domain user** — works on older domains, but you own password rotation: + ```powershell + sc.exe create WebhookServer binPath= "..." obj= "DOMAIN\svc-webhookserver" password= "..." start= auto + ``` + +Don't use `LocalService` — it has no network identity and cannot talk to a domain controller. + +> Heads up: any account the service runs under is the account your hook scripts run under. `LocalSystem` is the most powerful local account on the machine — treat webhook script contents as privileged. ## Configuration @@ -78,7 +102,6 @@ The service reads `C:\ProgramData\WebhookServer\config.json`. Edit it through th ## Out of scope for v1 - Importing/exporting config across machines (DPAPI LocalMachine scope ties decryption to the host). -- Outbound webhook delivery / retry queues. - Per-endpoint rate limiting. - Multi-user RBAC for the GUI. - Auto-update.