-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enhance consensus key rotation support #13926
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,15 +123,22 @@ impl ConfigSanitizer for SafetyRulesConfig { | |
pub enum InitialSafetyRulesConfig { | ||
FromFile { | ||
identity_blob_path: PathBuf, | ||
#[serde(skip_serializing_if = "Vec::is_empty", default)] | ||
overriding_identity_paths: Vec<PathBuf>, | ||
waypoint: WaypointConfig, | ||
}, | ||
None, | ||
} | ||
|
||
impl InitialSafetyRulesConfig { | ||
pub fn from_file(identity_blob_path: PathBuf, waypoint: WaypointConfig) -> Self { | ||
pub fn from_file( | ||
identity_blob_path: PathBuf, | ||
overriding_identity_paths: Vec<PathBuf>, | ||
waypoint: WaypointConfig, | ||
) -> Self { | ||
Self::FromFile { | ||
identity_blob_path, | ||
overriding_identity_paths, | ||
waypoint, | ||
} | ||
} | ||
|
@@ -160,6 +167,38 @@ impl InitialSafetyRulesConfig { | |
}, | ||
} | ||
} | ||
|
||
pub fn overriding_identity_blobs(&self) -> anyhow::Result<Vec<IdentityBlob>> { | ||
match self { | ||
InitialSafetyRulesConfig::FromFile { | ||
overriding_identity_paths, | ||
.. | ||
} => { | ||
let mut blobs = vec![]; | ||
for path in overriding_identity_paths { | ||
let blob = IdentityBlob::from_file(path)?; | ||
blobs.push(blob); | ||
} | ||
Ok(blobs) | ||
}, | ||
InitialSafetyRulesConfig::None => { | ||
bail!("loading overriding identity blobs failed with missing initial safety rules config") | ||
}, | ||
} | ||
} | ||
|
||
#[cfg(feature = "smoke-test")] | ||
pub fn overriding_identity_blob_paths_mut(&mut self) -> &mut Vec<PathBuf> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Maybe make this test-only? It seems like it's only used in the smoke tests? Or better yet, don't expose this here if possible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed. NOTE that we can't reuse feature There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aah, in that case, don't worry about it -- you can remove the |
||
match self { | ||
InitialSafetyRulesConfig::FromFile { | ||
overriding_identity_paths, | ||
.. | ||
} => overriding_identity_paths, | ||
InitialSafetyRulesConfig::None => { | ||
unreachable!() | ||
}, | ||
} | ||
} | ||
} | ||
|
||
/// Defines how safety rules should be executed | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,13 +11,13 @@ use crate::{ | |
thread::ThreadService, | ||
SafetyRules, TSafetyRules, | ||
}; | ||
use anyhow::anyhow; | ||
use aptos_config::config::{InitialSafetyRulesConfig, SafetyRulesConfig, SafetyRulesService}; | ||
use aptos_crypto::bls12381::PrivateKey; | ||
use aptos_crypto::bls12381::PublicKey; | ||
use aptos_global_constants::CONSENSUS_KEY; | ||
use aptos_infallible::RwLock; | ||
use aptos_logger::{info, warn}; | ||
use aptos_secure_storage::{KVStorage, Storage}; | ||
use std::{net::SocketAddr, sync::Arc}; | ||
use std::{net::SocketAddr, sync::Arc, time::Instant}; | ||
|
||
pub fn storage(config: &SafetyRulesConfig) -> PersistentSafetyStorage { | ||
let backend = &config.backend; | ||
|
@@ -45,8 +45,8 @@ pub fn storage(config: &SafetyRulesConfig) -> PersistentSafetyStorage { | |
} else { | ||
let storage = | ||
PersistentSafetyStorage::new(internal_storage, config.enable_cached_safety_data); | ||
// If it's initialized, then we can continue | ||
if storage.author().is_ok() { | ||
|
||
let mut storage = if storage.author().is_ok() { | ||
storage | ||
} else if !matches!( | ||
config.initial_safety_rules_config, | ||
|
@@ -75,19 +75,32 @@ pub fn storage(config: &SafetyRulesConfig) -> PersistentSafetyStorage { | |
panic!( | ||
"Safety rules storage is not initialized, provide an initial safety rules config" | ||
) | ||
}; | ||
|
||
// Ensuring all the overriding consensus keys are in the storage. | ||
let timer = Instant::now(); | ||
for blob in config | ||
zjma marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.initial_safety_rules_config | ||
.overriding_identity_blobs() | ||
.unwrap_or_default() | ||
{ | ||
if let Some(sk) = blob.consensus_private_key { | ||
let pk_hex = hex::encode(PublicKey::from(&sk).to_bytes()); | ||
let storage_key = format!("{}_{}", CONSENSUS_KEY, pk_hex); | ||
match storage.internal_store().set(storage_key.as_str(), sk) { | ||
Ok(_) => { | ||
info!("Setting {storage_key} succeeded."); | ||
}, | ||
Err(e) => { | ||
warn!("Setting {storage_key} failed with internal store set error: {e}"); | ||
}, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
info!("Overriding key work time: {:?}", timer.elapsed()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: do we think this is necessary to track/log? |
||
|
||
pub fn load_consensus_key_from_secure_storage( | ||
config: &SafetyRulesConfig, | ||
) -> anyhow::Result<PrivateKey> { | ||
let storage: Storage = (&config.backend).into(); | ||
let storage = Box::new(storage); | ||
let response = storage.get::<PrivateKey>(CONSENSUS_KEY).map_err(|e| { | ||
anyhow!("load_consensus_key_from_secure_storage failed with storage read error: {e}") | ||
})?; | ||
Ok(response.value) | ||
storage | ||
} | ||
} | ||
|
||
enum SafetyRulesWrapper { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a vector? Will 1 path not suffice (if the operator wants to rotate again, they need to move the new key to the old key location, and then add a single override). Would that work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory 2 slots (1 existing, 1 new) is enough. It's just i found n slots can also be supported for free by just replacing
Option<PathBuf>
withVec<PathBuf>
...