feat(dgw): route KDC traffic through agent tunnel#1781
Conversation
Let maintainers know that an action is required on their side
|
839b656 to
f390d98
Compare
32eb2dc to
92c095c
Compare
| // a parent association — so we mint a fresh session_id purely for log/agent | ||
| // correlation. The RDP CredSSP/NLA caller (rdp_proxy.rs::send_network_request) | ||
| // passes `claims.jet_aid` instead so KDC sub-traffic correlates with its RDP session. | ||
| let session_id = Uuid::new_v4(); |
There was a problem hiding this comment.
We could consider using the jti of the KDC token, so there is a more persistent correlation, even though it’s not directly the associated session ID.
There was a problem hiding this comment.
Pull request overview
This PR extends Devolutions Gateway’s “transparent agent tunnel routing” to cover the remaining Kerberos/KDC traffic paths (HTTP /jet/KdcProxy and the CredSSP/NLA Kerberos sub-flow), so KDC requests can traverse the agent QUIC tunnel when appropriate and logs can correlate sub-traffic with a session ID.
Changes:
- Plumbs an optional
agent_tunnel_handle+session_id: Uuidthrough the CredSSP/NLA flow inrdp_proxy.rs(and callers) so CredSSP Kerberos network requests can usesend_krb_messagewith tunnel routing. - Updates the HTTP KDC proxy handler to pass the tunnel handle and mint a
session_idfor correlation. - Adds a bounded-length read for TCP-framed KDC replies and integrates the agent-tunnel routing pipeline into
send_krb_message.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
devolutions-gateway/src/rdp_proxy.rs |
Plumbs agent-tunnel handle + session correlation into CredSSP network requests. |
devolutions-gateway/src/rd_clean_path.rs |
Passes tunnel handle + session ID into CredSSP helpers during clean-path credential injection. |
devolutions-gateway/src/generic_client.rs |
Passes the agent-tunnel handle into RdpProxy so CredSSP can route KDC traffic. |
devolutions-gateway/src/api/kdc_proxy.rs |
Routes KDC traffic via agent tunnel (when possible), adds session correlation, and caps TCP reply allocation. |
crates/agent-tunnel/src/routing.rs |
Updates module docs to include KDC proxy/CredSSP usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if let Some((mut stream, _agent)) = | ||
| agent_tunnel::routing::try_route(tunnel_handle, None, &route_target, session_id, kdc_target) | ||
| .await | ||
| .map_err(|e| HttpError::bad_gateway().build(format!("KDC routing through agent tunnel failed: {e:#}")))? |
| reader.read_exact(&mut buf[4..]).await?; | ||
| Ok(buf) | ||
| } | ||
|
|
|
Make sure to rework the squash commit body, and add the ticket in a footer |
0139388 to
4e2e02f
Compare
When an agent advertises the KDC's subnet or DNS domain, route Kerberos traffic through the QUIC tunnel just like every other proxy path. This closes the last gap left after the transparent routing PR (#1741). Two paths now use the same routing pipeline as connection forwarding: - `/jet/KdcProxy` HTTP endpoint — `send_krb_message` consults the routing pipeline before falling back to direct TCP. - RDP CredSSP/NLA — `rdp_proxy.rs::send_network_request` previously hard-coded `None` for the agent handle. Plumb `agent_tunnel_handle`, `session_id`, and `explicit_agent_id` from `RdpProxy` down through `perform_credssp_as_*` -> `resolve_*_generator` -> `send_network_request`. The same change reaches the credential-injection clean path (`rd_clean_path.rs`). Session correlation: - RDP CredSSP callers pass the parent association's `jet_aid` so KDC sub-traffic ties back to its parent RDP session in agent-side logs. - The HTTP `/jet/KdcProxy` handler passes the KDC token's own `jti` (the most persistent identifier available without a parent association). `KdcToken` now carries `jti` alongside the claims for this purpose. Explicit-agent routing (matches every other proxy path): - `send_krb_message` takes `explicit_agent_id: Option<Uuid>` and forwards it to `agent_tunnel::routing::try_route`. When the parent association pins `jet_agent_id`, the KDC sub-traffic is routed via that agent or fails -- never silently falls back to a different agent or to direct connect. The HTTP handler passes `None`. Hardening (came along since they live in the same file): - 64 KiB `MAX_KDC_REPLY_MESSAGE_LEN` DoS cap on the announced TCP-framed KDC reply length, with overflow-safe length math. - UDP scheme guard: KDC over UDP keeps going direct because the agent tunnel only carries TCP today. Drive-by: `crates/agent-tunnel/src/listener.rs` move-after-move on `ca_manager` introduced by #1775 -- fixed with `Arc::clone` to keep master building on `--no-default-features` configurations. Stack: based on #1741. Picks up `agent_tunnel::routing::try_route`. Issue: DGW-384
4e2e02f to
b7f2473
Compare
6e80f71
into
master
Closes DGW-384.
Routes KDC traffic through the agent tunnel for the two remaining paths after #1741:
/jet/KdcProxyendpointrdp_proxy.rs::send_network_request)send_krb_messagegains(agent_tunnel_handle, session_id: Uuid). RDP callers passclaims.jet_aidso agent-side logs correlate KDC sub-traffic with the parent RDP session; the HTTP handler mints a fresh UUID since its token has no parent association.Depends on #1741 — must merge first (uses
agent_tunnel::routing::try_route).