Skip to content

Commit 9f048ca

Browse files
authored
TQ: Add RackSecretLoader (#8943)
Add the mechanism for loading rack secrets on demand. This is the primary mechanism to be used by the key manager when deriving storage encryption keys. A follow up PR will integrate the `RackSecretLoader` into `Node` and add support for it to our cluster proptest. The `RackSecretLoader` follows a polling model and is sans-io like the rest of the protocol code. When to load and clear secrets will be controlled by an async wrapper on top of the `Node` api.
1 parent b112669 commit 9f048ca

File tree

4 files changed

+658
-6
lines changed

4 files changed

+658
-6
lines changed

trust-quorum/src/alarm.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
77
use serde::{Deserialize, Serialize};
88

9-
use crate::{Configuration, Epoch, PlatformId};
9+
use crate::{
10+
Configuration, Epoch, PlatformId,
11+
crypto::{DecryptionError, RackSecretReconstructError},
12+
};
1013

1114
#[allow(clippy::large_enum_variant)]
1215
#[derive(
@@ -33,4 +36,34 @@ pub enum Alarm {
3336
/// share digests in the Configuration. However, computation of the share
3437
/// still failed. This should be impossible.
3538
ShareComputationFailed { epoch: Epoch, err: gfss::shamir::CombineError },
39+
40+
/// We started collecting shares for a committed configuration,
41+
/// but we no longer have that configuration in our persistent state.
42+
CommittedConfigurationLost {
43+
latest_committed_epoch: Epoch,
44+
collecting_epoch: Epoch,
45+
},
46+
47+
/// Decrypting the encrypted rack secrets failed when presented with a
48+
/// `valid` RackSecret.
49+
///
50+
/// `Configuration` membership contains the hashes of each valid share. All
51+
/// shares utilized to reconstruct the rack secret were validated against
52+
/// these hashes, and the rack seceret was reconstructed. However, using
53+
/// the rack secret to derive encryption keys and decrypt the secrets from
54+
/// old configurations still failed. This should never be possible, and
55+
/// therefore we raise an alarm.
56+
RackSecretDecryptionFailed { epoch: Epoch, err: DecryptionError },
57+
58+
/// Reconstructing the rack secret failed when presented with `valid` shares.
59+
///
60+
/// `Configuration` membership contains the hashes of each valid share. All
61+
/// shares utilized to reconstruct the rack secret were validated against
62+
/// these hashes, and yet, the reconstruction still failed. This indicates
63+
/// either a bit flip in a share after validation, or, more likely, an
64+
/// invalid hash.
65+
RackSecretReconstructionFailed {
66+
epoch: Epoch,
67+
err: RackSecretReconstructError,
68+
},
3669
}

trust-quorum/src/crypto.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,30 @@ impl ExposeSecret<[u8; SECRET_LEN]> for ReconstructedRackSecret {
114114
}
115115
}
116116

117-
// Only use this in unit tests in this module
118-
#[cfg(test)]
119117
impl Clone for ReconstructedRackSecret {
120118
fn clone(&self) -> Self {
121119
self.expose_secret().as_slice().try_into().unwrap()
122120
}
123121
}
124122

125-
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
123+
#[cfg(test)]
124+
impl PartialEq for ReconstructedRackSecret {
125+
fn eq(&self, other: &Self) -> bool {
126+
self.expose_secret().ct_eq(other.expose_secret()).into()
127+
}
128+
}
129+
130+
#[derive(
131+
Debug,
132+
Clone,
133+
PartialEq,
134+
Eq,
135+
thiserror::Error,
136+
PartialOrd,
137+
Ord,
138+
Serialize,
139+
Deserialize,
140+
)]
126141
#[error("invalid rack secret size")]
127142
pub struct InvalidRackSecretSizeError;
128143

@@ -168,7 +183,18 @@ impl From<RackSecret> for ReconstructedRackSecret {
168183
}
169184
}
170185

171-
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, SlogInlineError)]
186+
#[derive(
187+
Debug,
188+
Clone,
189+
thiserror::Error,
190+
PartialEq,
191+
Eq,
192+
SlogInlineError,
193+
PartialOrd,
194+
Ord,
195+
Serialize,
196+
Deserialize,
197+
)]
172198
pub enum RackSecretReconstructError {
173199
#[error("share combine error")]
174200
Combine(
@@ -274,7 +300,18 @@ pub struct EncryptedRackSecrets {
274300
data: Box<[u8]>,
275301
}
276302

277-
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, SlogInlineError)]
303+
#[derive(
304+
Debug,
305+
Clone,
306+
PartialEq,
307+
Eq,
308+
PartialOrd,
309+
Ord,
310+
thiserror::Error,
311+
SlogInlineError,
312+
Serialize,
313+
Deserialize,
314+
)]
278315
pub enum DecryptionError {
279316
// An opaque error indicating decryption failed
280317
#[error("Failed to decrypt rack secrets")]
@@ -363,6 +400,10 @@ impl PlaintextRackSecrets {
363400
self.secrets.get(&epoch)
364401
}
365402

403+
pub fn into_inner(self) -> BTreeMap<Epoch, ReconstructedRackSecret> {
404+
self.secrets
405+
}
406+
366407
/// Consume the plaintext and return an `EncryptedRackSecrets`
367408
///
368409
/// We are encrypting rack secrets for prior epochs with the latest

trust-quorum/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ mod messages;
2424
mod node;
2525
mod node_ctx;
2626
mod persistent_state;
27+
#[allow(unused)]
28+
mod rack_secret_loader;
2729
mod validators;
2830
pub use configuration::Configuration;
2931
pub use coordinator_state::{

0 commit comments

Comments
 (0)