[PM-40801] Add option for alternative DataProtection settings on FIPS nodes - #8092
[PM-40801] Add option for alternative DataProtection settings on FIPS nodes#8092eligrubb wants to merge 2 commits into
Conversation
🤖 Bitwarden Claude Code ReviewOverall Assessment: REQUEST CHANGES Re-reviewed at Code Review Details
Resolved in earlier passes:
|
|
|
||
| /// <summary> | ||
| /// Defines how ASP.NET Core data-protection keys are protected at rest. | ||
| /// Migration between types is not supported. |
There was a problem hiding this comment.
StorageManaged silently regenerates the key ring instead of failing fast.
Details and fix
"Migration between types is not supported" is documented here, but nothing enforces it. If StorageManaged is set on a region whose aspnet-dataprotection/keys.xml already holds certificate-wrapped keys, no protect/unprotect certificate is registered, so keys wrapped with the blob-stored certificate can no longer be decrypted. ASP.NET then marks those keys ineligible, generates a fresh key, and the app starts successfully — every value protected with the old keys stops round-tripping, including User.MasterPassword and User.Key (DatabaseFieldProtection, see src/Infrastructure.Dapper/Repositories/UserRepository.cs), so logins break until the config is reverted.
This is the same silent-divergence failure mode that UnprotectCertificateMissingFromBlobStorage_Throws was written to prevent ("pods came up... and auto-generated their own keys — producing a divergent key ring across a rolling deploy").
Suggested guard: when KeyProtectionPolicy == StorageManaged, read keys.xml at startup and throw InvalidOperationException if it exists and contains encryptedSecret — the same signal the new StorageManaged_PersistsUnwrappedKeysWithoutAcquiringCertificates test asserts on.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8092 +/- ##
==========================================
- Coverage 68.56% 63.27% -5.30%
==========================================
Files 2381 2381
Lines 103902 103910 +8
Branches 9405 9406 +1
==========================================
- Hits 71245 65744 -5501
- Misses 30310 35916 +5606
+ Partials 2347 2250 -97 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| return; | ||
| } | ||
|
|
||
| builder.PersistKeysToAzureBlobStorage( |
There was a problem hiding this comment.
A question, this lives in the !globalSettings.selfhosted branch, so does that mean this setting is not available in self hosted environments? I understood the purpose here to be supporting self hosted fips installations, but maybe I'm missing something?
There was a problem hiding this comment.
My understanding is that the failure affects the new GovMode cluster, not self hosted environments. I believe self-hosted currently skips persisting the keys and the failing dataprotection settings, this change should only affect BW-deployed FedRamp regions.
quexten
left a comment
There was a problem hiding this comment.
A question, other than that looks reasonable.
e2c781b to
3c81610
Compare
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-40801
📔 Objective
PKCS#1 v1.5 certificate encryption silently fails when running in a FIPS environment. To support running services in FIPS environments we want the option to adjust DataProtection encryption settings. This PR introduces a new
GlobalSettings:DataProtection:KeyProtectionPolicyenum. If the enum is unset or set toCertificate, the server will continue to use DataProtection via PKCS#1 v1.5 certificate encryption when storing the key ring. If theKeyProtectionPolicyis set toStorageManaged, then certificate-based DataProtection is skipped, in favor of storage-level protection at rest.💭 Implementation decisions
KeyProtectionPolicyshould only be set toStorageManagedfor new or self-hosted regions. So, this PR does not handle migrating key protection fromCertificatetoStorageManaged. WhenKeyProtectionPolicy=StorageManaged, adding certificate handling to the builder is skipped completely, for both Protecting and Unprotecting the key ring.This setting does not decrease user security. Currently, both the key ring and encrypting certificate are stored using the same connection string. With the
StorageManagedsetting on, the key ring is still stored using the connection string. No matter the setting, the key ring data is singularly protected by the connection string secret. Using theCertificatepolicy adds an additional non-FIPS compliant layer. See the related slack discussion for more.Examples of setting new env var
Using a certificate thumbprint:
{ "GlobalSettings": { "Storage": { "ConnectionString": "<azure-storage-connection-string>" }, "DataProtection": { "KeyProtectionPolicy": "Certificate", "CertificateThumbprint": "<certificate-thumbprint>" } } }Or using a certificate stored in Azure Blob Storage:
{ "GlobalSettings": { "Storage": { "ConnectionString": "<azure-storage-connection-string>" }, "DataProtection": { "KeyProtectionPolicy": "Certificate", "BlobName": "dataprotection.pfx", "CertificatePassword": "<certificate-password>" } } }Certificate is the default, so KeyProtectionPolicy may be omitted.
No application-level certificate wrapping:
{ "GlobalSettings": { "Storage": { "ConnectionString": "<azure-storage-connection-string>" }, "DataProtection": { "KeyProtectionPolicy": "StorageManaged" } } }