feat: QUIC agent tunnel — protocol, listener, agent client#1738
feat: QUIC agent tunnel — protocol, listener, agent client#1738irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 1 commit intomasterfrom
Conversation
1ab42a3 to
38e79d3
Compare
QUIC Agent Tunnel — Technical Specification1. EnrollmentHow an agent gets its certificateKey property: the private key never leaves the agent machine. Enrollment tokenThe enrollment token is either:
2. Stream MultiplexingOne QUIC connection, many independent streamsEach stream is independently ordered. How a new session is established
No new QUIC handshake is needed — streams are opened instantly on the existing connection. Message encodingAll control and session setup messages use length-prefixed bincode: After Size limits
Limits are enforced on the length prefix (before reading the payload) and on the bincode deserializer (prevents crafted payloads with huge internal Vec lengths). 3. User ExperienceNetwork topologyAdmin setup (one-time)
End-user workflow (daily use)The user has no awareness of the agent. From their perspective:
What happens behind the scenes: No VPN. No inbound firewall rules on the office network. No routing configuration. Transparent routing rulesWhen a connection request arrives, the gateway evaluates routing in priority order:
When multiple agents match the same target, the most recently seen agent is tried first. Resilience
|
1 similar comment
QUIC Agent Tunnel — Technical Specification1. EnrollmentHow an agent gets its certificateKey property: the private key never leaves the agent machine. Enrollment tokenThe enrollment token is either:
2. Stream MultiplexingOne QUIC connection, many independent streamsEach stream is independently ordered. How a new session is established
No new QUIC handshake is needed — streams are opened instantly on the existing connection. Message encodingAll control and session setup messages use length-prefixed bincode: After Size limits
Limits are enforced on the length prefix (before reading the payload) and on the bincode deserializer (prevents crafted payloads with huge internal Vec lengths). 3. User ExperienceNetwork topologyAdmin setup (one-time)
End-user workflow (daily use)The user has no awareness of the agent. From their perspective:
What happens behind the scenes: No VPN. No inbound firewall rules on the office network. No routing configuration. Transparent routing rulesWhen a connection request arrives, the gateway evaluates routing in priority order:
When multiple agents match the same target, the most recently seen agent is tried first. Resilience
|
There was a problem hiding this comment.
Pull request overview
Adds the first slice of a QUIC/mTLS “agent tunnel” system: a shared binary protocol crate, a Gateway-side QUIC listener/registry/enrollment API, and an Agent-side enrollment + reconnecting tunnel client. This enables routing Gateway-initiated TCP proxy sessions through outbound-connected agents (for private-network reachability).
Changes:
- Introduces
agent-tunnel-protocrate (control/session messages, framing, protocol versioning). - Adds Gateway agent-tunnel core (
agent_tunnelmodule), config wiring, REST endpoints, and token claim support (jet_agent_id) used in the forwarding path. - Adds Agent enrollment/bootstrap + QUIC tunnel client with auto-reconnect and domain auto-detection.
Reviewed changes
Copilot reviewed 35 out of 36 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| devolutions-gateway/tests/config.rs | Updates config samples to include agent_tunnel field. |
| devolutions-gateway/src/token.rs | Adds jet_agent_id to association claims; adjusts scope token claims serialization/visibility. |
| devolutions-gateway/src/service.rs | Initializes and registers the agent-tunnel listener task when enabled. |
| devolutions-gateway/src/ngrok.rs | Threads agent_tunnel_handle into the TCP tunnel client path. |
| devolutions-gateway/src/middleware/auth.rs | Adds auth exception for /jet/agent-tunnel/enroll (self-auth via bearer token). |
| devolutions-gateway/src/listener.rs | Threads agent_tunnel_handle into the generic client path. |
| devolutions-gateway/src/lib.rs | Exposes agent_tunnel module and adds agent_tunnel_handle to DgwState. |
| devolutions-gateway/src/generic_client.rs | Uses jet_agent_id to route Fwd connections through the agent tunnel. |
| devolutions-gateway/src/extract.rs | Adds request extractors for agent-management read/write access control. |
| devolutions-gateway/src/config.rs | Adds AgentTunnelConf to Gateway config DTO and runtime config. |
| devolutions-gateway/src/api/webapp.rs | Ensures new jet_agent_id claim is present (set to None) when minting tokens. |
| devolutions-gateway/src/api/mod.rs | Nests the new /jet/agent-tunnel/* router. |
| devolutions-gateway/src/api/agent_enrollment.rs | Implements enrollment + agent management endpoints (list/get/delete/resolve-target). |
| devolutions-gateway/src/agent_tunnel/mod.rs | Declares agent-tunnel submodules and re-exports core types. |
| devolutions-gateway/src/agent_tunnel/listener.rs | QUIC UDP listener event loop + proxy-stream request dispatching. |
| devolutions-gateway/src/agent_tunnel/enrollment_store.rs | In-memory single-use enrollment token store with expiry. |
| devolutions-gateway/src/agent_tunnel/stream.rs | Tokio AsyncRead/AsyncWrite wrapper over QUIC streams via channels. |
| devolutions-gateway/src/agent_tunnel/registry.rs | Agent registry with heartbeat liveness + subnet/domain routing selection. |
| devolutions-gateway/src/agent_tunnel/connection.rs | Managed quiche connection: handshake identity, control parsing, proxy stream setup. |
| devolutions-gateway/src/agent_tunnel/cert.rs | CA manager for enrollment signing + server cert issuance and cert parsing helpers. |
| devolutions-gateway/Cargo.toml | Adds QUIC/proto/cert/routing dependencies for the tunnel feature. |
| devolutions-agent/src/service.rs | Registers TunnelTask when tunnel is enabled; fixes conf_handle cloning for RDP task. |
| devolutions-agent/src/main.rs | Adds CLI support for enroll/up bootstrap flows and parsing helpers + tests. |
| devolutions-agent/src/lib.rs | Exposes new modules: tunnel, enrollment, domain_detect. |
| devolutions-agent/src/enrollment.rs | Implements enrollment request + persistence of certs/config merge. |
| devolutions-agent/src/domain_detect.rs | Adds Windows/Linux DNS domain auto-detection helper. |
| devolutions-agent/src/tunnel.rs | Implements reconnecting QUIC client + control/session stream handling and TCP proxying. |
| devolutions-agent/src/config.rs | Adds tunnel config section; makes save_config/get_conf_file_path public. |
| devolutions-agent/Cargo.toml | Adds proto/quiche/reqwest/rcgen dependencies and Windows feature for domain detection. |
| crates/agent-tunnel-proto/src/lib.rs | Defines the protocol crate API surface and exports. |
| crates/agent-tunnel-proto/src/version.rs | Adds protocol version constants + validation helper. |
| crates/agent-tunnel-proto/src/error.rs | Defines protocol-level error types. |
| crates/agent-tunnel-proto/src/control.rs | Adds control-plane message definitions + framed encode/decode. |
| crates/agent-tunnel-proto/src/session.rs | Adds session-plane message definitions + framed encode/decode. |
| crates/agent-tunnel-proto/Cargo.toml | New crate manifest and dependencies. |
| Cargo.lock | Locks new dependencies introduced for QUIC, cert handling, registry, and protocol crate. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ec35e22 to
9e345b7
Compare
Add QUIC-based agent tunnel core infrastructure. Agents in private
networks connect outbound to Gateway via QUIC/mTLS, advertise reachable
subnets and domains, and proxy TCP connections on behalf of Gateway.
Protocol (agent-tunnel-proto crate):
- RouteAdvertise with subnets + domain advertisements
- ConnectMessage/ConnectResponse for session stream setup
- Heartbeat/HeartbeatAck for liveness detection
- Protocol version negotiation (v2)
Gateway (agent_tunnel module):
- QUIC listener with mTLS authentication
- Agent registry with subnet/domain tracking
- Certificate authority for agent enrollment
- Enrollment token store (one-time tokens)
- Bidirectional proxy stream multiplexing
Agent (devolutions-agent):
- QUIC client with auto-reconnect and exponential backoff
- Agent enrollment with config merge (preserves existing settings)
- Domain auto-detection (Windows: USERDNSDOMAIN, Linux: resolv.conf)
- Subnet validation on incoming connections
- Certificate file permissions (0o600 on Unix)
API endpoints:
- POST /jet/agent-tunnel/enroll — agent enrollment
- GET /jet/agent-tunnel/agents — list agents
- GET /jet/agent-tunnel/agents/{id} — get agent
- DELETE /jet/agent-tunnel/agents/{id} — delete agent
- POST /jet/agent-tunnel/agents/resolve-target — routing diagnostics
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9e345b7 to
591adc0
Compare
Summary
Add QUIC-based agent tunnel core infrastructure (PR 1 of 4).
Agents in private networks connect outbound to Gateway via QUIC/mTLS, advertise reachable subnets and domains, and proxy TCP connections on behalf of Gateway. No inbound firewall rules needed.
See the Technical Specification comment for detailed protocol design (enrollment, multiplexing, user flow).
PR stack
What's in this PR
crates/agent-tunnel-proto/— protocol types (RouteAdvertise, ConnectMessage, Heartbeat)devolutions-gateway/src/agent_tunnel/— QUIC listener, agent registry, CA/cert management, stream abstractiondevolutions-agent/src/tunnel.rs— QUIC client with auto-reconnect (exponential backoff)devolutions-agent/src/enrollment.rs— CSR-based enrollment (private key never leaves agent)devolutions-agent/src/domain_detect.rs— AD domain auto-detection (Windows/Linux)devolutions-gateway/src/api/agent_enrollment.rs— enrollment + management API endpointsSecurity highlights
Test plan
cargo clippy --workspace --tests -- -D warningscleancargo +nightly fmt --all -- --checkclean