feat(dgw): encrypt in-memory credentials#1689
feat(dgw): encrypt in-memory credentials#1689Benoît Cortier (CBenoit) wants to merge 6 commits intomasterfrom
Conversation
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
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. |
| // Encrypt (ciphertext includes 16-byte Poly1305 tag). | ||
| let ciphertext = cipher | ||
| .encrypt(&nonce, plaintext.as_bytes()) | ||
| .map_err(|e| anyhow::anyhow!("encryption failed: {e}"))?; |
There was a problem hiding this comment.
Copilot Use anyhow::Context whenever possible
|
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 👍
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