Skip to content

feat(dgw): encrypt in-memory credentials#1689

Open
Benoît Cortier (CBenoit) wants to merge 6 commits intomasterfrom
DGW-326
Open

feat(dgw): encrypt in-memory credentials#1689
Benoît Cortier (CBenoit) wants to merge 6 commits intomasterfrom
DGW-326

Conversation

@CBenoit
Copy link
Member

Add ChaCha20-Poly1305 encryption for credentials stored in the
credential store. Passwords are encrypted at rest with a master key
protected via libsodium's mlock/mprotect facilities, preventing exposure
in memory dumps or swap.

Issue: DGW-326

Add ChaCha20-Poly1305 encryption for credentials stored in the
credential store. Passwords are encrypted at rest with a master key
protected via libsodium's mlock/mprotect facilities, preventing exposure
in memory dumps or swap.

Issue: DGW-326
Copy link
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

Adds in-memory encryption for credentials stored by Devolutions Gateway to reduce plaintext exposure in dumps/swap, aligning with DGW-326.

Changes:

  • Introduces ChaCha20-Poly1305 encryption for stored passwords with a lazily initialized process-wide master key.
  • Updates credential ingestion to accept cleartext (API-only) types and encrypt on insert; decrypts on-demand for CredSSP flows.
  • Switches various password-like fields to secrecy::SecretString and updates serialization/usage accordingly.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
devolutions-gateway/src/rdp_proxy.rs Decrypts stored credentials on-demand before CredSSP; updates Kerberos injection to use ExposeSecret.
devolutions-gateway/src/rd_clean_path.rs Updates Kerberos credential injection to pass password via ExposeSecret.
devolutions-gateway/src/credential/mod.rs Adds encrypted vs cleartext credential types; encrypts on insert and provides decrypt_password().
devolutions-gateway/src/credential/crypto.rs New module implementing ChaCha20-Poly1305 encryption and master-key handling (mlock/mprotect via secrets).
devolutions-gateway/src/config.rs Replaces several password fields with SecretString and adjusts (de)serialization and default checks.
devolutions-gateway/src/api/webapp.rs Uses ExposeSecret when verifying stored password hashes.
devolutions-gateway/src/api/preflight.rs Updates provisioning DTO to cleartext mapping type; changes error mapping for insert failures.
devolutions-gateway/Cargo.toml Adds crypto/secret-handling dependencies (chacha20poly1305, secrets, secrecy, rand).
Cargo.lock Locks new transitive dependencies for added crypto/secret crates.

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

@CBenoit
Copy link
Member Author

Copilot open a new pull request to apply changes based on the comments in this thread

We accept the panic in the LazyLock though. It’s not really expected to fail under normal conditions. Put the comment about libsodium in the README.md instead.

Copy link
Contributor

Copilot AI commented Feb 26, 2026

Benoît Cortier (@CBenoit) I've opened a new pull request, #1690, to work on those changes. Once the pull request is ready, I'll request review from you.

@CBenoit
Copy link
Member Author

Copilot Please make secrets (libsodium) an optional dependency with a feature flag. When secrets is not available, use secrecy for similar features (minus mlock). Ensure secrets is enabled for production builds. Log a warning on startup when a release build does not include the mlock security with libsodium. Ensure we build with secrets in the CI production builds.

Copy link
Contributor

Copilot AI commented Feb 26, 2026

Benoît Cortier (@CBenoit) I've opened a new pull request, #1691, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 26, 2026

Benoît Cortier (@CBenoit) I've opened a new pull request, #1692, to work on those changes. Once the pull request is ready, I'll request review from you.

// Encrypt (ciphertext includes 16-byte Poly1305 tag).
let ciphertext = cipher
.encrypt(&nonce, plaintext.as_bytes())
.map_err(|e| anyhow::anyhow!("encryption failed: {e}"))?;
Copy link
Member Author

Choose a reason for hiding this comment

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

Copilot Use anyhow::Context whenever possible

Copy link
Contributor

Copilot AI commented Feb 26, 2026

Benoît Cortier (@CBenoit) I've opened a new pull request, #1693, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good to me 👍

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.

4 participants