Epic: Windows support for Network Devices — dg.exe as a Windows Service
Background
Customers with AD-joined Windows fleets need a machine-owned, always-on tunnel: up before logon, kept after logoff, invisible to the user, with an ACL allowlist for the pre-logon phase and a per-device opt-out. Network Devices already provide the right identity model — admin-managed, machine-enrolled (no user account or user enrollment flow), usable as an ACL source, fixed IP assigned by the admin — but the CLI client (dg) that drives them ships only for Linux (deb/rpm/tar.gz; requires root, resolvconf, ip, and systemd). Service Locations are Windows-only but user-enrolled, configured per location rather than per device, and cannot change policy at logon. The gap is a Windows dg client that runs as a system service.
Goal
A Windows machine can be enrolled as a Network Device — by the admin, before the machine is handed to a user — and hold its tunnel from boot, across logon/logoff and network changes, without any user interaction or visible UI, receiving config updates automatically.
Design decisions
- Separate deliverables.
dg.exe (CLI for network devices on Windows) ships as its own MSI, independent of the Desktop Client. A machine may have either or both installed.
- Separate Windows Service.
dg.exe runs under its own service (Defguard Network Device, LocalSystem, Automatic start). It is distinct from the existing Windows service the Desktop Client uses for Service Locations; the two do not share configuration or state.
- Config-file driven enrollment.
dg.exe looks for a JSON config file (default %ProgramData%\defguard\dg.json) containing at minimum enrollment_url and enrollment_token. On first start the service enrolls using it; after enrollment the file holds the resulting network configuration and device key.
- MSI behaviour. The MSI accepts enrollment parameters as properties (
ENROLLMENT_URL, ENROLLMENT_TOKEN, optional CONFIG_PATH). If passed, the MSI writes the JSON config from them and the service enrolls on first start. If no parameters are passed, the MSI installs the binary and service only and the service assumes a config file is already in place (pre-staged by imaging, GPO file copy, or Intune).
- Bulk operations on Network Devices (Core UI + API): bulk create (from a list of names, one location, IP auto/explicit), bulk re-enrol (regenerate tokens), download tokens (CSV/JSON of device → token), bulk delete.
- Provisioning flow for the customer. Admin bulk-creates devices → downloads tokens → feeds each machine's token to the MSI (
msiexec … ENROLLMENT_TOKEN=…) via imaging/GPO/Intune, or pre-stages the JSON config and installs the MSI without args.
Scope
- Windows build of
dg.exe (x64; ARM64 optional) using WireGuard-NT/wintun; DNS servers and search domains applied via Windows APIs.
Defguard Network Device Windows Service: starts before user logon, survives logoff, reconnects on network/interface change, independent of the Service Locations service.
- MSI installer implementing the config-file/parameter behaviour above; silent install supported; installer creates and starts the service.
- Config polling on Windows at parity with Linux (Enterprise: periodically fetch and apply the latest network config).
- CLI surface available to a local administrator for intervention:
dg enroll, dg status, dg start|stop, dg logs, plus standard sc/services.msc control and Windows Event Log output.
- Bulk operations for network devices in Core (create, re-enrol, download tokens, delete), UI and REST.
- Documentation: Windows CLI section, imaging/GPO/Intune deployment guide, admin intervention runbook, device-tunnel + user-tunnel coexistence guidance.
Out of scope
MFA for network devices; device posture checks for network devices; Desktop Client UI for network devices; macOS dg. Consequently a pre-logon location based on network devices cannot require MFA or posture.
Known limitations (to state in docs and to the customer)
- Per-device ACL assignment. Network devices are not groupable; in Firewall rules the admin either uses the "all network devices" toggle or selects devices one by one. For a fleet with differentiated policies this is manual. Follow-up: network-device groups/tags (see D4).
- No user association. A network device is a machine identity; Core does not know who uses it. Ownership must be tracked via the device Description field and the customer's CMDB/asset inventory. Activity logs show the device, not a person.
- No MFA, no posture on the network-device location (see Out of scope). The pre-logon tunnel is therefore protected only by the device key and the ACL allowlist.
Pre-shipping enrollment and admin control (answers to review questions)
Can the admin enroll the device before shipping it to the user? — Yes, by design. Enrollment is machine-based and token-based; no user session or account is involved. In the imaging/pre-staging step the admin installs the MSI with that machine's token (or pre-stages the JSON config), the service enrolls, and the device key and network config are stored on disk. The token is single-use and consumed at enrollment, so the shipped machine carries no reusable secret; it connects at first boot at the customer site as soon as it has internet access. Constraint: enrollment requires reachability to Defguard Edge and a correct clock at pre-staging time.
Can the admin control the binary when auto-enrollment failed? — Yes, with two channels.
- Local/out-of-band:
dg.exe remains a normal CLI. A local administrator (console, imaging bench, or existing endpoint-management remote shell) can inspect dg status and the Event Log, fix or replace %ProgramData%\defguard\dg.json, re-run dg enroll -u … -t … with a fresh token (bulk re-enrol → download tokens), and restart the service via dg start or sc start DefguardNetworkDevice.
- Remote via management tooling: because a failed enrollment means no Defguard tunnel exists yet, remote intervention relies on the customer's existing tooling (Intune/SCCM/GPO scripts running as SYSTEM) to push a new config file or re-run the MSI. The MSI must be idempotent so re-running it with new parameters replaces the config and re-triggers enrollment.
- The service must fail loudly and recoverably: clear Event Log error with reason (token expired, Edge unreachable, clock skew), automatic retry with back-off while the config is unchanged, and immediate retry when the config file changes.
Acceptance criteria
- AC1
msiexec /i dg.msi /qn ENROLLMENT_URL=… ENROLLMENT_TOKEN=… on a clean Windows 10/11 Pro and Server 2019/2022 machine results in an enrolled, connected network device with no user session ever opened.
- AC1b
msiexec /i dg.msi /qn with a pre-staged %ProgramData%\defguard\dg.json produces the same result; with neither parameters nor config file the service starts, logs "no configuration", and retries when a config file appears.
- AC2 After reboot the peer handshakes and the assigned IP responds from the gateway side before the logon screen is dismissed; the tunnel stays up after logon and after logoff.
- AC3 Switching networks (Wi-Fi ↔ wired, new DHCP lease) re-establishes the tunnel within 60 s with no restart.
- AC4 Changing the location's Allowed IPs or DNS in Core is applied on the device within the polling interval, with no logged-in user.
- AC5 No tray icon, window, or toast is shown; the tunnel is not listed in the Desktop Client if installed alongside; both services coexist without interfering.
- AC6 The device appears in the location's Network overview and is selectable as an ACL source; a Default-Deny location with an allowlist rule restricts it to exactly those destinations (verified with
nft counters on the gateway).
- AC7 A device pre-enrolled on an imaging bench, powered off, and booted at a different site connects at first boot without intervention.
- AC8 With an expired token, the service logs a clear error and, after the admin replaces the config with a fresh token (locally or via a SYSTEM script) and restarts the service, enrollment succeeds — no reinstall required.
- AC9 Bulk create of N devices returns N tokens; "download tokens" yields a file usable directly by the deployment scripts; bulk re-enrol invalidates old tokens; bulk delete removes peers from the gateway.
- AC10 Machine identity is a software-stored WireGuard key pair; no TPM / secure-enclave requirement.
- AC11 A machine with no network device created (opt-out) is unaffected by the deployment.
Dependencies / linked tickets
- D1 Bulk network-device operations in Core (create, re-enrol, download tokens, delete) — UI and REST.
- D2 Confirm or implement an ACL rule whose destination is the client subnet, so Support engineers' network devices can reach machines inbound under Default Deny (today the gateway drops unsolicited traffic and only accepts established/related return traffic).
- D3 Documented routing/DNS precedence when a device tunnel (
0.0.0.0/0) and a user tunnel (split) coexist on one machine.
- D4 Network-device groups or tags selectable as ACL sources, to avoid one-by-one assignment.
Open questions
- Q1 Token distribution at fleet scale: MSI property fed by the deployment tool vs pre-staged JSON via GPO file copy vs AD computer attribute — which to document as the primary path.
- Q2 Should the network-device service refuse to start, or only warn, if the Desktop Client already owns a full-tunnel location?
- Q3 Driver distribution: bundle WireGuard-NT in the MSI or require WireGuard for Windows to be present?
- Q4 Retry policy defaults (interval, max attempts) for failed enrollment; whether to expose them in
dg.json.
Estimate hint
Client-side: Windows build + service + MSI ≈ one sprint each; bulk operations in Core ≈ one sprint; docs ≈ 3 days. D2/D4 are Core/Gateway work tracked separately.
Target architecture (for context)
Windows machine
├─ dg.exe (Windows Service "Defguard Network Device", SYSTEM, boot) ── machine identity ──▶ Location "DEVICES"
│ config: %ProgramData%\defguard\dg.json
│ Allowed IPs 0.0.0.0/0 (full tunnel), Firewall = Default Deny + allowlist rules
└─ Defguard Desktop Client (separate MSI, separate service, user session, optional) ── user identity ──▶ Location "USERS"
Allowed IPs = internal subnets only, user/group ACLs
Until Scope items 1–3 ship, the only Windows path is the "Manual WireGuard Client" option for network devices: export the .conf and run it with WireGuard for Windows in tunnel-as-service mode — no config polling, no re-enrollment, and each machine's key/config must be distributed out-of-band.
Proposed admin process (target state)
Steps 1–3 are done once; steps 4–5 are done per batch of machines.
0. Prerequisites
- Enterprise license (config polling); Firewall/ACL module (Business or Enterprise).
- Gateway on Linux with nftables (kernel ≥ 5.10), running with masquerading enabled (
--masquerade / DEFGUARD_MASQUERADE=true) or with NAT configured manually — required for the full tunnel. If Docker runs on the gateway host, set DEFGUARD_FW_PRIORITY=-1.
- Inventory: hostnames that must be always-on; hostnames that are exceptions (Cisco VPN) and must not get a device; an owner/asset record per hostname (Core will not know who uses the device).
1. Create the DEVICES location
- Gateway VPN address/mask sized for one IP per machine, e.g.
10.90.0.1/22; public gateway DNS name and UDP port.
- Allowed IPs
0.0.0.0/0 (full tunnel so corporate web filtering applies).
- DNS: internal DNS servers plus the AD search domain.
- Keep-alive interval set (e.g. 25 s) so NAT'd machines stay reachable inbound.
- MFA off and no posture requirement (not supported for network devices). Location type: regular (not a Service Location).
- Firewall: Default Deny.
2. Define the phase-1 allowlist
Create reusable Destinations for DomainControllers, AVServers, WSUS, PKI with exact IPs/CIDRs, ports and protocols (e.g. DC: TCP/UDP 53, 88, 135, 389, 445, 464, 636, 3268–3269 and the RPC dynamic range; WSUS: TCP 8530/8531; PKI: TCP 80/443 to CA/OCSP/CRL hosts; AV: vendor ports).
3. Create ACL rules scoped to DEVICES
Devices-Phase1 — source: all network devices (avoids one-by-one selection; if some devices need a different policy, select them individually or wait for D4); destinations: the four objects above.
Support-Inbound — source: Support engineers' network devices; destination: 10.90.0.0/22 on RDP 3389 / WinRM 5985–5986 / SMB 445 as needed (depends on D2).
- Optional
Devices-Egress — destination: the web-filter/egress appliance range, if the filter is an explicit target rather than the default route.
Deploy pending changes and verify on the gateway with nft list table inet DEFGUARD-<iface>.
4. Bulk-create Network Devices and download tokens
Network devices → Bulk create: upload/paste the hostname list, choose DEVICES, let Core assign IPs (or supply them), set Description = asset tag / owner. Then Download tokens to get a hostname,ip,enrollment_url,token file. Record the IPs in the CMDB — this is the address Support connects to. Skip exception machines.
5. Pre-stage / deploy dg.exe
Choose one:
- Imaging bench (pre-ship): for each machine run
msiexec /i dg.msi /qn ENROLLMENT_URL=<url> ENROLLMENT_TOKEN=<token>; the MSI writes dg.json, creates and starts the service, and enrollment completes on the bench (needs Edge reachability and NTP). Power off and ship. The machine connects at first boot at the user's site.
- Already-deployed fleet: push the MSI via GPO/Intune with the same properties resolved per machine from the token file, or copy
dg.json per machine first and push msiexec /i dg.msi /qn without properties.
Verify: at the logon screen the machine's fixed IP answers from the corporate side; no UI is visible.
6. Keep the USERS location for interactive sessions
The existing user-identity location remains (Desktop Client, separate MSI and service), with Allowed IPs limited to internal subnets (split tunnel) so the device tunnel keeps the default route. User/group ACL rules live only on USERS.
7. Verify
| Requirement |
Check |
| Up before logon, kept after logoff, invisible |
Reboot to the logon screen: ping/RDP to the fixed IP from a Support host succeeds; no client UI; log off and re-check. |
| Full tunnel + web filtering |
Browse an external site from the machine; traffic appears in the corporate filter logs; device listed in the location's Network overview. |
| File shares |
\\fileserver\share reachable only when a rule allows it; blocked otherwise. |
| Phase-1 allowlist |
Before logon only DC/AV/WSUS/PKI reachable; other destinations dropped (nft counters). |
| Inbound Support |
RDP/WinRM from a Support engineer's network device to the fixed IP. |
| Per-device exception |
Exception machine has no network device and connects only via Cisco / Desktop Client. |
| Pre-shipped enrollment |
Machine enrolled on the bench connects at first boot elsewhere with no intervention. |
| No TPM |
Key pair generated by dg.exe, stored on disk; Core never holds the private key. |
8. Operate and intervene
- Config changes (new WSUS server, new Allowed IPs): edit the Destination/location → Deploy; machines pick it up via polling.
- Failed enrollment: check Event Log /
dg status; Bulk re-enrol the affected devices → Download tokens → replace dg.json (locally or via SYSTEM script) → dg start or sc start DefguardNetworkDevice. No reinstall needed.
- Rotate keys: bulk re-enrol → redeploy tokens as above.
- Decommission: Bulk delete; peers are removed from the gateway; uninstall the MSI via GPO/Intune.
- Monitor: Network overview per location shows active network devices; cross-reference with the CMDB for ownership.
Epic: Windows support for Network Devices —
dg.exeas a Windows ServiceBackground
Customers with AD-joined Windows fleets need a machine-owned, always-on tunnel: up before logon, kept after logoff, invisible to the user, with an ACL allowlist for the pre-logon phase and a per-device opt-out. Network Devices already provide the right identity model — admin-managed, machine-enrolled (no user account or user enrollment flow), usable as an ACL source, fixed IP assigned by the admin — but the CLI client (
dg) that drives them ships only for Linux (deb/rpm/tar.gz; requires root,resolvconf,ip, and systemd). Service Locations are Windows-only but user-enrolled, configured per location rather than per device, and cannot change policy at logon. The gap is a Windowsdgclient that runs as a system service.Goal
A Windows machine can be enrolled as a Network Device — by the admin, before the machine is handed to a user — and hold its tunnel from boot, across logon/logoff and network changes, without any user interaction or visible UI, receiving config updates automatically.
Design decisions
dg.exe(CLI for network devices on Windows) ships as its own MSI, independent of the Desktop Client. A machine may have either or both installed.dg.exeruns under its own service (Defguard Network Device,LocalSystem, Automatic start). It is distinct from the existing Windows service the Desktop Client uses for Service Locations; the two do not share configuration or state.dg.exelooks for a JSON config file (default%ProgramData%\defguard\dg.json) containing at minimumenrollment_urlandenrollment_token. On first start the service enrolls using it; after enrollment the file holds the resulting network configuration and device key.ENROLLMENT_URL,ENROLLMENT_TOKEN, optionalCONFIG_PATH). If passed, the MSI writes the JSON config from them and the service enrolls on first start. If no parameters are passed, the MSI installs the binary and service only and the service assumes a config file is already in place (pre-staged by imaging, GPO file copy, or Intune).msiexec … ENROLLMENT_TOKEN=…) via imaging/GPO/Intune, or pre-stages the JSON config and installs the MSI without args.Scope
dg.exe(x64; ARM64 optional) using WireGuard-NT/wintun; DNS servers and search domains applied via Windows APIs.Defguard Network DeviceWindows Service: starts before user logon, survives logoff, reconnects on network/interface change, independent of the Service Locations service.dg enroll,dg status,dg start|stop,dg logs, plus standardsc/services.msccontrol and Windows Event Log output.Out of scope
MFA for network devices; device posture checks for network devices; Desktop Client UI for network devices; macOS
dg. Consequently a pre-logon location based on network devices cannot require MFA or posture.Known limitations (to state in docs and to the customer)
Pre-shipping enrollment and admin control (answers to review questions)
Can the admin enroll the device before shipping it to the user? — Yes, by design. Enrollment is machine-based and token-based; no user session or account is involved. In the imaging/pre-staging step the admin installs the MSI with that machine's token (or pre-stages the JSON config), the service enrolls, and the device key and network config are stored on disk. The token is single-use and consumed at enrollment, so the shipped machine carries no reusable secret; it connects at first boot at the customer site as soon as it has internet access. Constraint: enrollment requires reachability to Defguard Edge and a correct clock at pre-staging time.
Can the admin control the binary when auto-enrollment failed? — Yes, with two channels.
dg.exeremains a normal CLI. A local administrator (console, imaging bench, or existing endpoint-management remote shell) can inspectdg statusand the Event Log, fix or replace%ProgramData%\defguard\dg.json, re-rundg enroll -u … -t …with a fresh token (bulk re-enrol → download tokens), and restart the service viadg startorsc start DefguardNetworkDevice.Acceptance criteria
msiexec /i dg.msi /qn ENROLLMENT_URL=… ENROLLMENT_TOKEN=…on a clean Windows 10/11 Pro and Server 2019/2022 machine results in an enrolled, connected network device with no user session ever opened.msiexec /i dg.msi /qnwith a pre-staged%ProgramData%\defguard\dg.jsonproduces the same result; with neither parameters nor config file the service starts, logs "no configuration", and retries when a config file appears.nftcounters on the gateway).Dependencies / linked tickets
0.0.0.0/0) and a user tunnel (split) coexist on one machine.Open questions
dg.json.Estimate hint
Client-side: Windows build + service + MSI ≈ one sprint each; bulk operations in Core ≈ one sprint; docs ≈ 3 days. D2/D4 are Core/Gateway work tracked separately.
Target architecture (for context)
Until Scope items 1–3 ship, the only Windows path is the "Manual WireGuard Client" option for network devices: export the
.confand run it with WireGuard for Windows in tunnel-as-service mode — no config polling, no re-enrollment, and each machine's key/config must be distributed out-of-band.Proposed admin process (target state)
Steps 1–3 are done once; steps 4–5 are done per batch of machines.
0. Prerequisites
--masquerade/DEFGUARD_MASQUERADE=true) or with NAT configured manually — required for the full tunnel. If Docker runs on the gateway host, setDEFGUARD_FW_PRIORITY=-1.1. Create the
DEVICESlocation10.90.0.1/22; public gateway DNS name and UDP port.0.0.0.0/0(full tunnel so corporate web filtering applies).2. Define the phase-1 allowlist
Create reusable Destinations for
DomainControllers,AVServers,WSUS,PKIwith exact IPs/CIDRs, ports and protocols (e.g. DC: TCP/UDP 53, 88, 135, 389, 445, 464, 636, 3268–3269 and the RPC dynamic range; WSUS: TCP 8530/8531; PKI: TCP 80/443 to CA/OCSP/CRL hosts; AV: vendor ports).3. Create ACL rules scoped to
DEVICESDevices-Phase1— source: all network devices (avoids one-by-one selection; if some devices need a different policy, select them individually or wait for D4); destinations: the four objects above.Support-Inbound— source: Support engineers' network devices; destination:10.90.0.0/22on RDP 3389 / WinRM 5985–5986 / SMB 445 as needed (depends on D2).Devices-Egress— destination: the web-filter/egress appliance range, if the filter is an explicit target rather than the default route.Deploy pending changes and verify on the gateway with
nft list table inet DEFGUARD-<iface>.4. Bulk-create Network Devices and download tokens
Network devices → Bulk create: upload/paste the hostname list, choose
DEVICES, let Core assign IPs (or supply them), set Description = asset tag / owner. Then Download tokens to get ahostname,ip,enrollment_url,tokenfile. Record the IPs in the CMDB — this is the address Support connects to. Skip exception machines.5. Pre-stage / deploy
dg.exeChoose one:
msiexec /i dg.msi /qn ENROLLMENT_URL=<url> ENROLLMENT_TOKEN=<token>; the MSI writesdg.json, creates and starts the service, and enrollment completes on the bench (needs Edge reachability and NTP). Power off and ship. The machine connects at first boot at the user's site.dg.jsonper machine first and pushmsiexec /i dg.msi /qnwithout properties.Verify: at the logon screen the machine's fixed IP answers from the corporate side; no UI is visible.
6. Keep the
USERSlocation for interactive sessionsThe existing user-identity location remains (Desktop Client, separate MSI and service), with Allowed IPs limited to internal subnets (split tunnel) so the device tunnel keeps the default route. User/group ACL rules live only on
USERS.7. Verify
ping/RDP to the fixed IP from a Support host succeeds; no client UI; log off and re-check.\\fileserver\sharereachable only when a rule allows it; blocked otherwise.nftcounters).dg.exe, stored on disk; Core never holds the private key.8. Operate and intervene
dg status; Bulk re-enrol the affected devices → Download tokens → replacedg.json(locally or via SYSTEM script) →dg startorsc start DefguardNetworkDevice. No reinstall needed.