Skip to content

feat(dgw): provision the target-side KDC for credential injection#1865

Open
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 5 commits into
DVLS-14697-kerberos-kdc-injectionfrom
DVLS-14697-kdc-provisioning-store
Open

feat(dgw): provision the target-side KDC for credential injection#1865
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 5 commits into
DVLS-14697-kerberos-kdc-injectionfrom
DVLS-14697-kdc-provisioning-store

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Follow-up to #1862. Lets the provisioner (DVLS) supply the real target-side KDC address for Kerberos credential injection, and puts it in the right home.

  • TokenKeyedStore<V> — a generic store keyed by association-token JTI, owning TTL and cleanup, knowing nothing about what it holds.
  • ProvisioningStore (built on it) owns the credential mapping and target options, and is the encryption boundary: cleartext is encrypted on the way in, so the master key never leaves the credential module.
  • The KDC address is provisioned over the authenticated preflight channel as a connection_options block, and stored as plaintext routing metadata (TargetConnectionOptions) — not as a secret, and not on the association token.
  • The credential-injection KDC service is a separate service keyed by the same JTI. It owns only the Kerberos session cache and reads the provisioning store at resolution time; it does not own or wrap it. Re-provisioning is detected by entry identity, so a stale Kerberos session is never reused.
  • The target-side CredSSP leg now uses the provisioned KDC (completing the TODO left in fix(dgw): decide credential-injection CredSSP protocol once for both legs #1862).

Behind enable_unstable + debug.kerberos_credential_injection; no stable consumer yet.

Tests

cargo +nightly fmt --all; cargo clippy -p devolutions-gateway --lib --tests -- -D warnings; cargo test -p devolutions-gateway --lib (123 passed).

Issue: DVLS-14697

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors credential provisioning into a generic token-keyed store and adds target KDC connection options.

Changes:

  • Introduces generic provisioning storage with TTL cleanup.
  • Separates credential storage from KDC session management.
  • Exposes and consumes krb_kdc through preflight APIs and generated clients.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
devolutions-gateway/src/token_keyed_store.rs Adds generic JTI-keyed storage.
devolutions-gateway/src/target_connection_options.rs Defines target KDC options.
devolutions-gateway/src/target_addr.rs Adds URL conversion.
devolutions-gateway/src/service.rs Registers provisioning services.
devolutions-gateway/src/rdp_proxy.rs Applies provisioned KDC configuration.
devolutions-gateway/src/rd_clean_path.rs Resolves provisioned credentials.
devolutions-gateway/src/provisioning.rs Adds encrypted provisioning storage.
devolutions-gateway/src/openapi.rs Adds connection-options schema.
devolutions-gateway/src/ngrok.rs Passes new service handles.
devolutions-gateway/src/listener.rs Passes new service handles.
devolutions-gateway/src/lib.rs Exposes modules and state fields.
devolutions-gateway/src/kdc_connector.rs Shares KDC scheme validation.
devolutions-gateway/src/generic_client.rs Resolves credential injection through provisioning.
devolutions-gateway/src/credential/mod.rs Removes credential-store responsibilities.
devolutions-gateway/src/credential/crypto.rs Updates encryption documentation.
devolutions-gateway/src/credential_injection_kdc.rs Separates KDC session caching from provisioning.
devolutions-gateway/src/api/rdp.rs Wires provisioning into RDP handling.
devolutions-gateway/src/api/preflight.rs Provisions connection options.
devolutions-gateway/src/api/kdc_proxy.rs Resolves KDC state from provisioning.
openapi/ts-angular-client/model/targetConnectionOptions.ts Adds generated TypeScript model.
openapi/ts-angular-client/model/preflightOperation.ts Exposes connection options.
openapi/ts-angular-client/model/models.ts Exports the new model.
openapi/ts-angular-client/.openapi-generator/FILES Tracks generated TypeScript output.
openapi/gateway-api.yaml Defines the public schema.
openapi/dotnet-client/src/Devolutions.Gateway.Client/Model/TargetConnectionOptions.cs Adds generated .NET model.
openapi/dotnet-client/src/Devolutions.Gateway.Client/Model/PreflightOperation.cs Adds connection options to preflight operations.
openapi/dotnet-client/README.md Lists the new model.
openapi/dotnet-client/docs/TargetConnectionOptions.md Documents the new model.
openapi/dotnet-client/docs/PreflightOperation.md Documents the new property.
openapi/dotnet-client/.openapi-generator/FILES Tracks generated .NET output.
openapi/doc/index.adoc Updates generated API documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread devolutions-gateway/src/rdp_proxy.rs
Comment thread devolutions-gateway/src/target_connection_options.rs Outdated
…ing store

Extract a protocol-neutral `TokenKeyedStore<V>` that owns JTI keying, TTL, and
cleanup and knows nothing about its value type. The target KDC address moves off
the credential type into a plaintext `TargetConnectionOptions`, provisioned via a
new `connection_options` block on `provision-credentials`. Encryption stays at
the credential boundary, so the store never touches the master key.
Narrow the new token-keyed store, target connection options, and the
service-level InsertError to `pub(crate)`. Only the binary-facing
CredentialService surface stays `pub`.
…ervices

Separate the provisioning store (credentials + target options, keyed by JTI) from
the credential-injection KDC service (Kerberos session cache). Neither owns the
other: the KDC service reads the store passed in at resolution time, and notices
re-provisioning through a weak reference to the entry rather than an insert-time
callback. Encryption stays in the provisioning store, at the credential boundary.
…truction

Rename `CredentialService` to `CredentialInjectionKdcService` (it now holds only
the Kerberos session cache, no credentials) and the `DgwState` field likewise.
Validate the KDC scheme when a `TargetConnectionOptions` is built, not only when
deserialized, so in-crate callers can't construct an unsupported address. Document
that `TokenKeyedStore::get` may return an expired-but-not-yet-swept entry.
Reject an unsupported scheme, a missing host (e.g. `tcp://:88`), or an unparseable
URL when a `TargetConnectionOptions` is built, so provisioning fails fast at
preflight instead of at RDP session start.
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.

2 participants