feat(dgw): encrypt in-memory credentials at rest with ChaCha20-Poly1305#1689
feat(dgw): encrypt in-memory credentials at rest with ChaCha20-Poly1305#1689Benoît Cortier (CBenoit) merged 17 commits intomasterfrom
Conversation
There was a problem hiding this comment.
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::SecretStringand 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.
|
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. |
|
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. |
|
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. |
|
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. |
|
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. |
|
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. |
Vladyslav Nikonov (vnikonov-devolutions)
left a comment
There was a problem hiding this comment.
Looks good to me 👍
bada7f5 to
d8fc305
Compare
02397c2 to
4b13f8a
Compare
|
I updated the CI so we get libsodium support for the ARM64 builds |
|
We're going to use libsodium now, a C dependency? I see this pull request is already weeks in the making, so I trust you've already handled the additional complexity that comes with it for cross-compilation. There was really no other way? |
9001e90 to
ebc432a
Compare
Add ChaCha20-Poly1305 encryption for credentials stored in the credential store. Passwords are encrypted at rest with a randomly generated 256-bit master key that is zeroized on drop. When built with the `mlock` cargo feature, the master key is additionally protected via libsodium's mlock/mprotect facilities, preventing exposure in memory dumps or swap. A startup warning is emitted in release builds when mlock is not enabled. Issue: DGW-326
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 18 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
devolutions-gateway/src/credential/mod.rs:76
#[derive(Deserialize)]is used in this module butserde::Deserializeis no longer imported (the previousserde::{de, ser}import was removed). This will fail to compile unless you either importserde::Deserializeor qualify the derive asserde::Deserialize.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
devolutions-gateway/src/credential/mod.rs:77
#[derive(Deserialize)]is used here, but this module has nouse serde::Deserialize;(noruse serde::{Deserialize, Serialize};). UnlessDeserializeis being referenced with a full path, this will fail to compile with “cannot find derive macroDeserializein this scope”. Import the derive macros (e.g.,use serde::Deserialize;) or switch the derives to fully-qualifiedserde::Deserialize/serde::Serialize.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
devolutions-gateway/src/credential/mod.rs:39
InsertErrorimplementsstd::error::Errorbut doesn’t expose the wrappedanyhow::Erroras a source, which can drop error-chain information for callers usingsource()/Error::cause-style introspection. Consider implementingsource()(or usingthiserror) so the underlying error is preserved.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
devolutions-gateway/src/credential/mod.rs:77
#[derive(Deserialize)]is used in this module, butserde::Deserializeis not imported into scope. This will not compile because derive macros require the trait name to resolve (e.g.,use serde::Deserialize;oruse serde::{Deserialize, Serialize};).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add ChaCha20-Poly1305 encryption for credentials stored in the credential
store. Passwords are encrypted at rest with a randomly generated 256-bit
master key held in a protected page.
The page protection hardening is performed using the best available OS
hardening in a best-effort basis:
write, WerRegisterExcludedMemoryBlock for WER crash report exclusion.
madvise(MADV_DONTDUMP) for core dump exclusion.
zeroize-on-drop on unsupported platforms.
In concrete terms: this protects users from leaking important secrets in
the event of a memory dump captured for debugging purposes.
Issue: DGW-326