feat(agent-installer): add Agent Tunnel configuration dialog#1789
feat(agent-installer): add Agent Tunnel configuration dialog#1789irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 6 commits into
Conversation
Let maintainers know that an action is required on their side
|
Adds an optional Agent Tunnel wizard step to the Devolutions Agent installer so admins can enroll the agent in a Gateway QUIC tunnel as part of MSI install (UI or unattended). Surfaces three MSI public properties for unattended installs: - AGENT_TUNNEL_ENROLLMENT_STRING (dgw-enroll:v1:<base64> from DVLS/Hub/Gateway) - AGENT_TUNNEL_ADVERTISE_SUBNETS (CSV CIDR; empty = none) - AGENT_TUNNEL_ADVERTISE_DOMAINS (CSV DNS suffixes; empty = auto-detect only) Wires a new deferred elevated custom action (EnrollAgentTunnel) that runs Before StartServices when AGENT_TUNNEL_FEATURE is being installed. It base64-decodes the enrollment payload, shells out to `devolutions-agent.exe enroll <url> <token> <name> [subnets]` with a 60s timeout, and redacts the token in the session log. Advertise domains are persisted by patching `Tunnel.AdvertiseDomains` in agent.json post-enrollment, matching the agreed direction that domain config lives in the file rather than as a CLI flag. The Tunnel feature itself is opt-in (isEnabled:false, allowChange:true); the dialog is skipped when the feature isn't selected. An empty enrollment string also skips tunnel setup, allowing the installer to be used without touching the tunnel.
a521b61 to
460aeab
Compare
WixSharp's runtime dialog loader threw at AgentTunnelDialog init (MSI 1603) because the tableLayoutPanel had RowCount=8 but the new gateway URL controls were placed at rows 8/9/10.
…add Agent name field - Propagate AGENT_TUNNEL_* properties to deferred CA via Secure MSI Property declarations + explicit UsesProperties string. The deferred CA was previously seeing empty values because the wizard-set properties never crossed the UAC boundary. - Treat empty enrollment string as install failure (was silent skip). EnrollAgentTunnel CA now returns ActionResult.Failure and surfaces session.Message(InstallMessage.Error, ...) on the empty case and on enrollment timeout, non-zero exit, and exception paths. - Add optional Agent name field to AgentTunnelDialog. Resolution order at install time: dialog value > JWT jet_agent_name claim > computer name. Avoids "missing required --name" failures when the JWT lacks the claim. - Update Wizard.ShouldSkip-gated dialog so blank enrollment is blocked at UI validation (previously the dialog let users click Next on empty).
Captures the root cause behind silent enrollment-success-but-no-tunnel failures we hit during integration testing, the constraints we've confirmed with the team, and the proposed redesign: - Decouple Gateway's cryptographic identity (server cert SAN) from its network reachability (the host agents dial). Replace single conf.hostname with AgentTunnel.AdvertisedNames (multi-SAN, label-able). - Agent derives its QUIC endpoint from the host it enrolled through (jet_gw_url) + a quic_port returned by the gateway, instead of accepting whatever hostname the gateway dictates. - Gateway validates enrollment URL host against AdvertisedNames upfront, with a structured 400 response carrying error/message/help. - New agent.exe verify-tunnel subcommand wired into the MSI CA so install success means the tunnel is actually up, not just that a cert was written. Errors expose a structured kind/detail/next_step triple. - DVLS enrollment-string UI becomes a dropdown over AdvertisedNames (refreshed from gateway diagnostics) instead of a free-text URL box. Includes a 9-entry error catalog with operator-facing next-step text, non-goals (single-use enforcement, gateway farms — deferred), migration path, and a 5-PR implementation plan. Includes Codex's review.
Summary
Adds an optional Agent Tunnel wizard step to the Devolutions Agent MSI installer so admins can enrol the agent in a Gateway QUIC tunnel during install — UI or unattended.
Three text fields in the dialog: enrolment string, advertise subnets, advertise domains. The feature is opt-in (
isEnabled: false, allowChange: true); the dialog is skipped when the feature isn't selected, and an empty enrolment string skips tunnel setup even if the feature is on, so the installer remains usable for non-tunnel deployments.Smoke-tested end-to-end against a local DVLS + Gateway + Agent stack: MSI built clean, agent enrolled successfully, RDP TCP traffic routed through the agent tunnel to
IT-HELP-DC:3389.MSI public properties (unattended install)
Custom action
EnrollAgentTunnelis deferred + elevated +Impersonate=false, runsBefore StartServices, gated byFeatures.AGENT_TUNNEL_FEATURE.BeingInstall(). It:dgw-enroll:v1:prefix, strips whitespace, pads base64url, decodes JSON payload (api_base_url,enrollment_token, optionalname).devolutions-agent.exe enroll <url> <token> <name> [subnets]with a 60s timeout; on timeout the child is killed.***) symmetrically across the command-line log and child stdout/stderr.Tunnel.AdvertiseDomainsof%ProgramData%\Devolutions\Agent\agent.json. This matches the design that advertise domains live in config, not on the CLI (replaces the closed feat(agent): --advertise-domains CLI flag #1774).Depends on
/jet/tunnel/enroll)Both merged to master 2026-05-20.
Test plan
CNDL1138/CNDL1006warnings from existing code, not introduced here)dgw-enroll:v1:prefix → validation error in dialogIT-HELP-DC:3389succeedsReview history
Pre-review and codex-review passes folded into the single commit. Notable points addressed:
JObject,Value<string>(),IsNullOrWhiteSpacevalidation)WaitForExit(60_000)return-value check with child kill on timeoutInstallDirDlg*strings leaked into en-us