Skip to content

Windows Group Policy

On Windows, dotvault can be fully configured via Group Policy using the Windows Registry. This allows centralised management of dotvault settings across a domain without deploying YAML config files.

How it works

When HKLM registry keys exist at SOFTWARE\Policies\goodtune\dotvault, dotvault loads all configuration from the registry and ignores the YAML config file entirely. Only machine-level policy (HKLM) is read — HKCU is intentionally skipped because it is user-writable and therefore cannot be trusted for enforced configuration.

The --config flag is blocked under Group Policy by default

When a policy is present, dotvault refuses a --config path/to/config.yaml override and exits with an error — a managed machine cannot be pointed at an arbitrary config from the command line. To allow the override (for development or troubleshooting on a specific machine), set a BypassSystemConfig REG_DWORD of 1 directly under SOFTWARE\Policies\goodtune\dotvault (the bypass_system_config: true YAML equivalent). With the flag set, an invocation with --config loads the named file and ignores the registry; without it, --config is rejected. The flag is part of the policy, so it stays under the administrator's control rather than the user's.

Authoring the registry values

dotvault does not ship an ADMX administrative template. Instead, admins author the registry values directly under SOFTWARE\Policies\goodtune\dotvault and deploy them via Group Policy Preferences > Registry (or any registry-deployment tool: SCCM, Intune, a .reg import, etc.).

The supported authoring workflow is to write the configuration as YAML and convert it to a .reg file with dotvault reg-import:

dotvault reg-import config.yaml --output dotvault-policy.reg

This emits a canonical Windows Registry Editor Version 5.00 file (UTF-16LE with BOM, matching regedit.exe) targeting HKLM\SOFTWARE\Policies\goodtune\dotvault. Import it into the policy hive, or load it into a GPO's registry preferences. The reverse direction — pulling an existing policy hive back into YAML for review — is dotvault reg-export:

dotvault reg-export dotvault-policy.reg --output config.yaml

Both commands round-trip the entire configuration without loss — including observability header values (see the credential note below) — so the YAML and .reg forms are interchangeable. The web UI's Effective Configuration screen exposes the same conversion via download buttons.

Registry schema

Every YAML field has a registry equivalent. The tables below give the value names; reg-import writes exactly these, and the live loader reads exactly these.

Top-level settings (policy root key)

Registry value Type Description
BypassSystemConfig REG_DWORD Allow the --config command-line override on this machine (0/1; default 0). Lives directly under the policy root key, not in a subkey.

Vault settings (Vault\ subkey)

Registry value Type Description
Vault\Address REG_SZ Vault server URL (required)
Vault\CACert REG_SZ Path to CA certificate
Vault\TLSSkipVerify REG_DWORD Skip TLS verification (0/1)
Vault\KVMount REG_SZ KVv2 mount path
Vault\UserPrefix REG_SZ Per-user path prefix
Vault\AuthMethod REG_SZ oidc, ldap, token, mtls, or mtls+tpm
Vault\AuthRole REG_SZ Vault auth role
Vault\AuthMount REG_SZ Vault auth mount path
Vault\OIDCCallbackPort REG_DWORD Fixed local TCP port for the OIDC CLI redirect_uri (0 = built-in default of 8250)
Vault\Policies REG_MULTI_SZ Least-privilege policy set the working token is downscoped to (empty = carry every granted policy)
Vault\NoDefaultPolicy REG_DWORD Strip the implicit default policy from the working token (0/1)
Vault\DisableTokenRenewal REG_DWORD Disable RenewSelf (0/1)
Vault\TokenSocket REG_SZ Path to a peer dotvault web-API Unix socket to borrow a token from

Sync settings (Sync\ subkey)

Registry value Type Description
Sync\Interval REG_SZ Go duration string (e.g. 15m)

Web UI settings (Web\ subkey)

Registry value Type Description
Web\Enabled REG_DWORD Enable web UI (0/1)
Web\Listen REG_SZ Listen address (loopback only)
Web\LoginText REG_SZ Login-page markdown (multi-line via hex(1))
Web\SecretViewText REG_SZ Secret-view markdown (multi-line via hex(1))

Observability settings (Observability\ subkey)

Registry value Type Description
Observability\Enabled REG_DWORD Enable the OTLP metrics exporter (0/1)
Observability\Endpoint REG_SZ OTLP collector endpoint
Observability\Protocol REG_SZ grpc or http/protobuf
Observability\Insecure REG_DWORD Disable transport TLS (0/1)
Observability\ExportInterval REG_SZ Export interval (e.g. 30s, 1m)
Observability\Headers\<name> REG_SZ OTLP header value (see note)

The block drives both signals (metrics and logs) against the same collector. For http/protobuf, Endpoint must be a base URL like https://otel.example — the exporters append /v1/metrics and /v1/logs themselves; a URL that already ends in a signal-specific path routes both signals to the wrong route.

Observability headers carry credentials

OTLP headers typically hold bearer tokens (Datadog / Grafana Cloud / Honeycomb, etc.). Config conversion is lossless in every direction, so reg-export and reg-import do round-trip header values verbatim (each as a REG_SZ value under Observability\Headers) — which means a generated .reg artefact contains the live tokens. Treat it as a secret: store it at restricted permissions and don't check it in. If you would rather keep tokens out of the policy hive and out of any exported artefact, leave headers empty and set them via the per-user EnvironmentFile (OTEL_EXPORTER_OTLP_HEADERS) instead — the SDK falls through to those env vars.

Remote configuration (RemoteConfig\ subkey)

Registry value Type Description
RemoteConfig\URL REG_SZ Remote configuration endpoint (https required except loopback hosts)
RemoteConfig\RefreshInterval REG_SZ Re-fetch cadence (e.g. 15m; default: the sync interval; floor 1m)
RemoteConfig\CACert REG_SZ Path to a CA bundle pinning the service's TLS certificate
RemoteConfig\Headers\<name> REG_SZ Extra dimension header sent with every fetch (e.g. X-Dotvault-Env)

When URL is set, the registry-delivered policy becomes the base configuration and the daemon merges the remotely fetched dynamic sections (rules, enrolments, sync) on top — see Remote Configuration. A GPO base may deliberately carry zero rules when the remote service supplies them all. Unlike observability headers, these values are non-secret dimension labels; like every section, they round-trip losslessly through reg-export / reg-import.

Rules (Rules\{RuleName} subkeys)

Each rule is a subkey under Rules\{RuleName}:

SOFTWARE\Policies\goodtune\dotvault\Rules\gh\VaultKey         (REG_SZ)    "gh"
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\TargetPath       (REG_SZ)    "~/.config/gh/hosts.yml"
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\TargetFormat     (REG_SZ)    "yaml"
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\TargetTemplate   (REG_SZ)    "github.com:\n  oauth_token: \"{{.oauth_token}}\""
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\Description      (REG_SZ)    "GitHub CLI credentials"

Optional OAuth subkey for rules with service onboarding:

SOFTWARE\Policies\goodtune\dotvault\Rules\gh\OAuth\EnginePath (REG_SZ)
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\OAuth\Provider   (REG_SZ)
SOFTWARE\Policies\goodtune\dotvault\Rules\gh\OAuth\Scopes     (REG_MULTI_SZ)

Enrolments (Enrolments\{Name} subkeys)

Each enrolment is a subkey under Enrolments\{Name}:

SOFTWARE\Policies\goodtune\dotvault\Enrolments\gh\Engine                    (REG_SZ)        "github"
SOFTWARE\Policies\goodtune\dotvault\Enrolments\gh\Settings\client_id        (REG_SZ)        "178c6fc778ccc68e1d6a"
SOFTWARE\Policies\goodtune\dotvault\Enrolments\gh\Settings\scopes           (REG_MULTI_SZ)  "repo\0read:org\0gist"
SOFTWARE\Policies\goodtune\dotvault\Enrolments\gh\Settings\https_proxy      (REG_SZ)        "http://squid.example.com:3128"

The https_proxy value (or its http_proxy alias) is optional. When unset, the engine consults the machine's IE / WinHTTP proxy configuration — including any deployed PAC script — once per outbound request. Set it explicitly here only when you want this enrolment pinned to a specific proxy regardless of the system-level policy.

SSH agent (Agent\ subkey)

The scalar transport settings live directly under Agent\; the ordered key sources are subkeys under Agent\Keys\{N} where {N} is the zero-based list index:

SOFTWARE\Policies\goodtune\dotvault\Agent\Enabled        (REG_DWORD)
SOFTWARE\Policies\goodtune\dotvault\Agent\UnixPath       (REG_SZ)
SOFTWARE\Policies\goodtune\dotvault\Agent\WindowsPipe    (REG_SZ)
SOFTWARE\Policies\goodtune\dotvault\Agent\Keys\0\Source      (REG_SZ)        "vault-ca"
SOFTWARE\Policies\goodtune\dotvault\Agent\Keys\0\Mount       (REG_SZ)        "ssh-client-signer"
SOFTWARE\Policies\goodtune\dotvault\Agent\Keys\0\Role        (REG_SZ)        "dotvault-user"
SOFTWARE\Policies\goodtune\dotvault\Agent\Keys\0\Principals  (REG_MULTI_SZ)

Authoring these by hand is fiddly; prefer reg-import from a YAML config.

Example: deploying via GPO

A typical deployment workflow:

  1. Author the configuration as YAML and convert it with dotvault reg-import config.yaml --output dotvault-policy.reg.
  2. Create a new GPO linked to the target OU (e.g. "Developer Workstations").
  3. Deploy the registry values under SOFTWARE\Policies\goodtune\dotvault via Group Policy Preferences > Registry (import the .reg, or recreate the values from it).
  4. Deploy the binary via SCCM, Intune, or a similar tool.
  5. Create a scheduled task (via GPO Preferences or a script) to run dotvaultw.exe at user logon.

Verifying the configuration

On a managed machine, verify that dotvault is reading from the registry:

dotvault status

To dump the effective policy back to YAML for review:

dotvault reg-export dotvault-policy.reg

To test with a YAML config file instead (bypassing the registry), the policy must first opt in by setting BypassSystemConfig to 1 under the policy root key. Once it is set:

dotvault status --config C:\path\to\test-config.yaml

Without BypassSystemConfig, that command exits with an error explaining the override is not permitted.