Skip to content

feat(dgw): route KDC traffic through agent tunnel#1781

Open
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 1 commit into
masterfrom
feat/DGW-384-kdc-agent-tunnel
Open

feat(dgw): route KDC traffic through agent tunnel#1781
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 1 commit into
masterfrom
feat/DGW-384-kdc-agent-tunnel

Conversation

@irvingoujAtDevolution
Copy link
Copy Markdown
Contributor

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented May 12, 2026

Closes DGW-384.

Routes KDC traffic through the agent tunnel for the two remaining paths after #1741:

  • HTTP /jet/KdcProxy endpoint
  • RDP CredSSP/NLA (rdp_proxy.rs::send_network_request)

send_krb_message gains (agent_tunnel_handle, session_id: Uuid). RDP callers pass claims.jet_aid so 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).

@github-actions
Copy link
Copy Markdown

Let maintainers know that an action is required on their side

  • Add the label release-required Please cut a new release (Devolutions Gateway, Devolutions Agent, Jetsocat, PowerShell module) when you request a maintainer to cut a new release (Devolutions Gateway, Devolutions Agent, Jetsocat, PowerShell module)

  • Add the label release-blocker Follow-up is required before cutting a new release if a follow-up is required before cutting a new release

  • Add the label publish-required Please publish libraries (`Devolutions.Gateway.Utils`, OpenAPI clients, etc) when you request a maintainer to publish libraries (Devolutions.Gateway.Utils, OpenAPI clients, etc.)

  • Add the label publish-blocker Follow-up is required before publishing libraries if a follow-up is required before publishing libraries

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):

- `/jet/KdcProxy` HTTP endpoint — `send_krb_message` now consults the
  routing pipeline before falling back to direct TCP. The HTTP handler
  has no parent association, so it mints a fresh session_id purely for
  agent-side log correlation.

- RDP CredSSP/NLA — `rdp_proxy.rs::send_network_request` previously
  hard-coded `None` for the agent handle. Plumb `agent_tunnel_handle`
  and `session_id` from `RdpProxy` down through `perform_credssp_with_*`
  → `resolve_*_generator` → `send_network_request`. The same change
  reaches the credential-injection clean path (`rd_clean_path.rs`).
  `session_id` here is `session_info.id` / `claims.jet_aid` so the
  agent log ties KDC sub-traffic to its parent RDP session.

Stack: based on #1741. Picks up `agent_tunnel::routing::try_route`.

`send_krb_message` signature gains `(agent_tunnel_handle, session_id)`
in that order — required `Uuid`, no `Option<>` — so the call site is
honest about which UUID it's logging. The UDP scheme guard (KDC over
UDP keeps going direct because the agent protocol only carries TCP)
and the 64 KiB `MAX_KDC_REPLY_MESSAGE_LEN` DoS cap (and the matching
generic `read_kdc_reply_message`) come along since they live in the
same file and serve the same end.
// 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();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

@CBenoit Benoît Cortier (CBenoit) left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: Uuid through the CredSSP/NLA flow in rdp_proxy.rs (and callers) so CredSSP Kerberos network requests can use send_krb_message with tunnel routing.
  • Updates the HTTP KDC proxy handler to pass the tunnel handle and mint a session_id for 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.

Comment on lines +232 to +235
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:#}")))?
send_krb_message(&target_addr, &request.data)
send_krb_message(&target_addr, &request.data, agent_tunnel_handle, session_id)
.await
.map_err(|err| anyhow::Error::msg("failed to send KDC message").context(err))
reader.read_exact(&mut buf[4..]).await?;
Ok(buf)
}

@CBenoit Benoît Cortier (CBenoit) changed the title feat(dgw): route KDC traffic through agent tunnel (DGW-384) feat(dgw): route KDC traffic through agent tunnel May 20, 2026
@CBenoit
Copy link
Copy Markdown
Member

Make sure to rework the squash commit body, and add the ticket in a footer Issue: DGW-384 when you merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants