Running on Windows with a gMSA
This page describes how to run the Curiosity Workspace Windows service and the CLI connector (curiosity-cli monitor / monitor-with-permissions) under a Group Managed Service Account (gMSA), and what Active Directory and host-side setup is required.
A gMSA is a domain account whose password is generated and rotated by Active Directory itself (every 30 days by default). Services log on with the account name only — there is no password to type into a service definition, store in a script, or rotate by hand. This matters for two Curiosity scenarios:
- The Workspace service (
curiosity, installed byconfigure-windows-service.bat) runs asLocalSystemby default. A gMSA lets it run under a least-privilege domain identity instead — required when the workspace itself must reach domain resources such as an SMB path forMSK_GRAPH_STORAGEor a PEM certificate on a share. - The CLI connector syncing a file share needs a domain identity to read the share, and — for the
-with-permissionsvariants — to resolve the NTFS ACL SIDs against Active Directory. Running the connector service as a gMSA replaces the--username/--password/--domainimpersonation flags, so no domain credential appears in the service configuration at all.
Requirements
| Requirement | Notes |
| --- | --- |
| Active Directory domain | Domain functional level Windows Server 2012 or later. |
| KDS root key | Created once per forest; gMSA passwords are derived from it. |
| Domain-joined host | The machine running the Workspace and/or CLI connector must be joined to the domain. |
| Windows Server 2012+ on the host | Client SKUs also support gMSAs, but a server SKU is typical. |
| RSAT Active Directory PowerShell module | Needed on the host to install and test the account. |
| AD permissions | Creating the gMSA requires rights to create msDS-GroupManagedServiceAccount objects (typically Domain Admins or a delegated OU admin). |
Create the gMSA in Active Directory
Run these on a domain controller (or any machine with the AD PowerShell module and sufficient rights).
If your forest has never used gMSAs, create the KDS root key first:
Get-KdsRootKey # anything listed? then skip the next line
Add-KdsRootKey -EffectiveImmediately
KDS root key propagation
-EffectiveImmediately still means a 10-hour wait before domain controllers will issue gMSA passwords, to allow AD replication. In a single-DC lab you can bypass the wait with Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) — do not do this in production.
Create a security group for the hosts allowed to retrieve the account's password, add the machine account(s), then create the gMSA:
New-ADGroup -Name "CuriosityHosts" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "CuriosityHosts" -Members "WORKSPACE01$" # the host's computer account
New-ADServiceAccount -Name "svc-curiosity" `
-DNSHostName "svc-curiosity.corp.example.com" `
-PrincipalsAllowedToRetrieveManagedPassword "CuriosityHosts"
Reboot the host after adding its computer account to the group — group membership is only picked up on the machine's next Kerberos ticket.
You can also point -PrincipalsAllowedToRetrieveManagedPassword at a single computer account ("WORKSPACE01$") instead of a group; the group form scales to several connector hosts sharing one account.
Prepare the host
On the machine that will run the service(s):
# RSAT AD PowerShell module (server SKU)
Install-WindowsFeature RSAT-AD-PowerShell
# Link the account to this host and verify the password can be retrieved
Install-ADServiceAccount -Identity "svc-curiosity"
Test-ADServiceAccount -Identity "svc-curiosity" # must return True
If Test-ADServiceAccount returns False, the host cannot retrieve the managed password — see Troubleshooting.
Grant the account the Log on as a service right: secpol.msc → Local Policies → User Rights Assignment → Log on as a service → add CORP\svc-curiosity$. (Configuring the account through the services.msc UI grants this automatically; sc.exe does not on all Windows versions, so set it explicitly.) In domains where this right is controlled by Group Policy, add the account to the corresponding GPO instead — a local grant is overwritten on the next policy refresh.
The trailing `$`
A gMSA is referenced everywhere as DOMAIN\name$ — with a trailing dollar sign and an empty password. Forgetting the $ is the most common configuration mistake.
Run the Workspace service as the gMSA
Install the Workspace as a Windows service first (see Windows Installation), then change the service identity:
sc.exe stop curiosity
sc.exe config curiosity obj= "CORP\svc-curiosity$" password= ""
Before starting it again, make sure the account can read and write everything the service touches:
| Path | Access | Notes |
| --- | --- | --- |
| Install directory (binaries) | Read + execute | The installer defaults to %USERPROFILE%\AppData\Local\Curiosity Workspace\ of the installing user — grant the gMSA read access there, or install to a machine-wide path such as C:\Curiosity\app. |
| MSK_GRAPH_STORAGE data directory | Full control | Move it out of a user profile (e.g. D:\Curiosity\data) if it isn't already. |
| Log directory (MSK_LOG_PATH) | Modify | |
| TLS certificate files (MSK_CERT_FILE, MSK_CERT_FILE_PRIVATE_KEY) | Read | Only if TLS is terminated in the workspace itself. |
icacls "C:\Curiosity\app" /grant "CORP\svc-curiosity$:(OI)(CI)RX"
icacls "D:\Curiosity\data" /grant "CORP\svc-curiosity$:(OI)(CI)F"
Machine-scope MSK_* environment variables (see Windows Installation) apply to services regardless of the account they run as, so no configuration changes are needed there. Then:
sc.exe start curiosity
sc.exe query curiosity
Run the CLI connector as the gMSA
The typical connector is monitor-with-permissions wrapped in a Windows service (via NSSM or sc.exe), continuously syncing a file share and its Active Directory ACLs into the workspace.
1. Install the CLI machine-wide
dotnet tool install --global installs into the invoking user's profile (%USERPROFILE%\.dotnet\tools), which the gMSA cannot see. Install to a fixed path instead:
dotnet tool install Curiosity.CLI --tool-path C:\Curiosity\cli
The binary is then C:\Curiosity\cli\curiosity-cli.exe for any account on the machine.
2. Grant the gMSA access
| Resource | Access | Notes |
| --- | --- | --- |
| The monitored share (e.g. \\fileserver\Shared) | Read | Both the share permission and the NTFS permission must allow the gMSA (effective access is the more restrictive of the two). Grant read on the whole tree you want indexed. |
| --permissions-cache file location (e.g. C:\Curiosity\acl-cache.json) | Modify | Keep the path stable across runs. |
| Active Directory read | Default | Resolving ACL SIDs to users/groups only needs standard authenticated-user read access to the directory — no extra grants in a default AD. |
Because the service itself runs as the domain identity, the CLI's Windows-only --username / --password / --domain impersonation options are not needed — leave them out.
3. Create the service
With NSSM:
nssm install CuriosityMonitor "C:\Curiosity\cli\curiosity-cli.exe"
nssm set CuriosityMonitor AppParameters monitor-with-permissions ^
--server https://my-workspace.example.com/ ^
--token %CURIOSITY_TOKEN% ^
--path \\fileserver\Shared ^
--permissions-cache C:\Curiosity\acl-cache.json ^
--fetch-server-state true
nssm set CuriosityMonitor AppEnvironmentExtra CURIOSITY_TOKEN=<library-token>
nssm set CuriosityMonitor ObjectName CORP\svc-curiosity$ ""
nssm start CuriosityMonitor
ObjectName CORP\svc-curiosity$ "" is the gMSA equivalent of an account + password pair — the empty string is the password. With plain sc.exe the same is sc.exe config CuriosityMonitor obj= "CORP\svc-curiosity$" password= "".
Token handling under a gMSA
The service needs a workspace Library Token (create one under Manage → Tokens → Library, ideally for a dedicated service user with minimal rights). Two ways to provide it:
Environment variable in the service definition (shown above with
AppEnvironmentExtra) — simplest; the token lives only in the service configuration, readable by administrators.store-token+--token auto— the encrypted token file is written to the running user's%APPDATA%, so it must be created as the gMSA. A gMSA cannot log on interactively; run the one-off command through a scheduled task instead:$a = New-ScheduledTaskAction -Execute "C:\Curiosity\cli\curiosity-cli.exe" ` -Argument "store-token -s https://my-workspace.example.com/ -t <library-token>" $p = New-ScheduledTaskPrincipal -UserId "CORP\svc-curiosity$" -LogonType Password Register-ScheduledTask -TaskName "curiosity-store-token" -Action $a -Principal $p Start-ScheduledTask -TaskName "curiosity-store-token" Unregister-ScheduledTask -TaskName "curiosity-store-token" -Confirm:$falseAfterwards the service can use
--token autoand no token appears in the service definition. (-LogonType Passwordis correct for gMSAs — Windows fetches the managed password itself.)
Troubleshooting
| Symptom | Likely cause |
| --- | --- |
| Test-ADServiceAccount returns False | The host's computer account is not in the PrincipalsAllowedToRetrieveManagedPassword group, the host was not rebooted after being added, or the KDS root key is not yet effective (10-hour wait). |
| Service fails to start with error 1069 (logon failure) | Missing trailing $ in the account name, a non-empty password was configured, or the account lacks the Log on as a service right. |
| Access is denied reading the share | Check both the share permission and the NTFS ACL for the gMSA; also confirm the share path is a UNC path, not a drive letter mapped for another user (drive mappings are per-logon and invisible to the service). |
| Can't find token for url with --token auto | The token was stored under a different account's %APPDATA% — re-run store-token as the gMSA (see above) or pass the token explicitly. |
| ACL sync produces no permissions | Confirm you run the Windows build of the CLI and the -with-permissions command variant; the non-Windows builds do not support permission sync. |
See also
- Windows Installation — base install, service setup, configuration.
monitor-with-permissionsandupload-folder-with-permissions— the connector commands.- CLI installation — install, update, token creation.
- Security — hardening the deployment.
- Microsoft: Group Managed Service Accounts overview — upstream reference.