-
Notifications
You must be signed in to change notification settings - Fork 133
feat: add input encryption for validators #2342
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
Changes from 6 commits
781d918
68c0c3c
cfe6987
fcb3e8b
a861396
db96583
24aa5f9
c6fd347
5bed689
437d0ea
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 |
|---|---|---|
|
|
@@ -3,27 +3,40 @@ mod start; | |
|
|
||
| use std::num::NonZeroUsize; | ||
| use std::path::PathBuf; | ||
| use std::sync::Arc; | ||
|
|
||
| use anyhow::Context; | ||
| use clap::Parser; | ||
| use miden_node_utils::clap::GrpcOptionsInternal; | ||
| use miden_node_utils::logging::OpenTelemetry; | ||
| use miden_node_utils::shutdown::CancellationToken; | ||
| use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SigningKey; | ||
| use miden_protocol::crypto::dsa::eddsa_25519_sha512::KeyExchangeKey; | ||
| use miden_protocol::utils::serde::Deserializable; | ||
| use miden_validator::{DataDirectory, ValidatorSigner}; | ||
| use miden_validator::{ | ||
| DataDirectory, | ||
| LOG_TARGET, | ||
| LocalX25519TransactionInputDecrypter, | ||
| TransactionInputDecrypter, | ||
| ValidatorSigner, | ||
| }; | ||
|
|
||
| const ENV_DATA_DIRECTORY: &str = "MIDEN_VALIDATOR_DATA_DIRECTORY"; | ||
| const ENV_LISTEN: &str = "MIDEN_VALIDATOR_LISTEN"; | ||
| const ENV_KEY: &str = "MIDEN_VALIDATOR_KEY"; | ||
| const ENV_KMS_KEY_ID: &str = "MIDEN_VALIDATOR_KMS_KEY_ID"; | ||
| const ENV_SIGNING_KEY: &str = "MIDEN_VALIDATOR_SIGNING_KEY"; | ||
| const ENV_SIGNING_KEY_KMS_ID: &str = "MIDEN_VALIDATOR_SIGNING_KEY_KMS_ID"; | ||
| const ENV_ENCRYPTION_KEY: &str = "MIDEN_VALIDATOR_ENCRYPTION_KEY"; | ||
| const ENV_GENESIS_CONFIG_FILE: &str = "MIDEN_VALIDATOR_GENESIS_CONFIG_FILE"; | ||
| const ENV_SQLITE_CONNECTION_POOL_SIZE: &str = "MIDEN_VALIDATOR_SQLITE_CONNECTION_POOL_SIZE"; | ||
|
|
||
| /// A predefined, insecure validator key for development purposes. | ||
| pub(crate) const INSECURE_KEY_HEX: &str = | ||
| /// A predefined, insecure validator signing key for development purposes. | ||
| pub(crate) const INSECURE_SIGNING_KEY_HEX: &str = | ||
| "0101010101010101010101010101010101010101010101010101010101010101"; | ||
|
|
||
| /// A predefined, insecure shared transaction encryption key for development purposes. | ||
| pub(crate) const INSECURE_ENCRYPTION_KEY_HEX: &str = | ||
| "0202020202020202020202020202020202020202020202020202020202020202"; | ||
|
|
||
| // VALIDATOR COMMAND | ||
| // ================================================================================================ | ||
|
|
||
|
|
@@ -56,9 +69,9 @@ pub enum ValidatorCommand { | |
| /// Use the given configuration file to construct the genesis state from. | ||
| #[arg(long, env = ENV_GENESIS_CONFIG_FILE, value_name = "GENESIS_CONFIG")] | ||
| genesis_config_file: Option<PathBuf>, | ||
| /// Configuration for the Validator key used to sign the genesis block. | ||
| /// Configuration for the validator signing key used to sign the genesis block. | ||
| #[command(flatten)] | ||
| validator_key: ValidatorKey, | ||
| signing_key: ValidatorSigningKey, | ||
| }, | ||
|
|
||
| /// Applies pending validator database migrations. | ||
|
|
@@ -96,26 +109,40 @@ pub enum ValidatorCommand { | |
| /// | ||
| /// If not provided, a predefined key is used. | ||
| /// | ||
| /// Cannot be used with `key.kms-id`. | ||
| /// Cannot be used with `signing-key.kms-id`. | ||
| #[arg( | ||
| long = "key.hex", | ||
| env = ENV_KEY, | ||
| value_name = "VALIDATOR_KEY", | ||
| default_value = INSECURE_KEY_HEX, | ||
| group = "key" | ||
| long = "signing-key.hex", | ||
|
Mirko-von-Leipzig marked this conversation as resolved.
|
||
| env = ENV_SIGNING_KEY, | ||
| value_name = "VALIDATOR_SIGNING_KEY", | ||
| default_value = INSECURE_SIGNING_KEY_HEX, | ||
| group = "signing_key" | ||
| )] | ||
| validator_key: String, | ||
| signing_key: String, | ||
|
|
||
| /// Key ID for the KMS key used by validator to sign blocks. | ||
| /// | ||
| /// Cannot be used with `key.hex`. | ||
| /// Cannot be used with `signing-key.hex`. | ||
| #[arg( | ||
| long = "key.kms-id", | ||
| env = ENV_KMS_KEY_ID, | ||
| value_name = "VALIDATOR_KMS_KEY_ID", | ||
| group = "key" | ||
| long = "signing-key.kms-id", | ||
| env = ENV_SIGNING_KEY_KMS_ID, | ||
| value_name = "VALIDATOR_SIGNING_KEY_KMS_ID", | ||
| group = "signing_key" | ||
| )] | ||
| kms_key_id: Option<String>, | ||
| signing_key_kms_id: Option<String>, | ||
|
|
||
| /// Hex-encoded shared secret of the transaction encryption key. | ||
| /// | ||
| /// Unlike the per-validator signing key, this value must be identical across every | ||
| /// validator in the set. | ||
| /// | ||
| /// If not provided, a predefined insecure key is used. | ||
|
SantiagoPittella marked this conversation as resolved.
|
||
| #[arg( | ||
| long = "encryption-key.hex", | ||
| env = ENV_ENCRYPTION_KEY, | ||
| value_name = "VALIDATOR_ENCRYPTION_KEY", | ||
| default_value = INSECURE_ENCRYPTION_KEY_HEX | ||
| )] | ||
| encryption_key: String, | ||
|
Comment on lines
+143
to
+150
Contributor
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. Not for this PR, but should we also provide an option to get the key from KMS?
Collaborator
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. We just need to ensure KMS supports this key type, otherwise we cannot decrypt. |
||
| }, | ||
| } | ||
|
|
||
|
|
@@ -128,15 +155,15 @@ impl ValidatorCommand { | |
| data_directory, | ||
| sqlite_connection_pool_size, | ||
| genesis_config_file, | ||
| validator_key, | ||
| signing_key, | ||
| } => { | ||
| bootstrap::bootstrap( | ||
| &genesis_block_directory, | ||
| &accounts_directory, | ||
| &data_directory, | ||
| sqlite_connection_pool_size, | ||
| genesis_config_file.as_ref(), | ||
| validator_key, | ||
| signing_key, | ||
| ) | ||
| .await | ||
| }, | ||
|
|
@@ -150,38 +177,50 @@ impl ValidatorCommand { | |
| Self::Start { | ||
| listen, | ||
| grpc_options, | ||
| validator_key, | ||
| signing_key, | ||
| data_directory, | ||
| kms_key_id, | ||
| signing_key_kms_id, | ||
| sqlite_connection_pool_size, | ||
| encryption_key, | ||
| .. | ||
| } => { | ||
| let address = listen; | ||
|
|
||
| if let Some(kms_key_id) = kms_key_id { | ||
| let signer = ValidatorSigner::new_kms(kms_key_id).await?; | ||
| start::start( | ||
| address, | ||
| grpc_options, | ||
| signer, | ||
| data_directory, | ||
| sqlite_connection_pool_size, | ||
| shutdown, | ||
| ) | ||
| .await | ||
| } else { | ||
| let signer = SigningKey::read_from_bytes(hex::decode(validator_key)?.as_ref())?; | ||
| let signer = ValidatorSigner::new_local(signer); | ||
| start::start( | ||
| address, | ||
| grpc_options, | ||
| signer, | ||
| data_directory, | ||
| sqlite_connection_pool_size, | ||
| shutdown, | ||
| ) | ||
| .await | ||
| // Unlike the signing key, whose insecure default is caught at startup against the | ||
| // chain's committed validator key, nothing cross-checks the encryption key. Warn | ||
| // loudly so the default never runs in production unnoticed. | ||
| if encryption_key == INSECURE_ENCRYPTION_KEY_HEX { | ||
| tracing::warn!( | ||
| target: LOG_TARGET, | ||
| "Using the predefined, insecure transaction encryption key, configure \ | ||
| --encryption-key.hex for production deployments" | ||
| ); | ||
| } | ||
|
|
||
| let encryption_key_bytes = hex::decode(encryption_key) | ||
| .context("failed to decode the encryption key hex")?; | ||
| let encryption_key = KeyExchangeKey::read_from_bytes(&encryption_key_bytes) | ||
| .context("failed to construct the encryption key")?; | ||
| let decrypter: Arc<dyn TransactionInputDecrypter> = | ||
| Arc::new(LocalX25519TransactionInputDecrypter::new(encryption_key)); | ||
|
|
||
| let signer = if let Some(kms_key_id) = signing_key_kms_id { | ||
| ValidatorSigner::new_kms(kms_key_id).await? | ||
| } else { | ||
| let signer = SigningKey::read_from_bytes(hex::decode(signing_key)?.as_ref())?; | ||
| ValidatorSigner::new_local(signer) | ||
| }; | ||
|
|
||
| start::start( | ||
| address, | ||
| grpc_options, | ||
| signer, | ||
| decrypter, | ||
| data_directory, | ||
| sqlite_connection_pool_size, | ||
| shutdown, | ||
| ) | ||
| .await | ||
| }, | ||
| } | ||
| } | ||
|
|
@@ -194,42 +233,42 @@ impl ValidatorCommand { | |
| } | ||
| } | ||
|
|
||
| // VALIDATOR KEY | ||
| // VALIDATOR SIGNING KEY | ||
| // ================================================================================================ | ||
|
|
||
| /// Configuration for the Validator key used to sign blocks. | ||
| /// Configuration for the validator signing key used to sign blocks. | ||
| #[derive(clap::Args)] | ||
| #[group(required = false, multiple = false)] | ||
| pub struct ValidatorKey { | ||
| pub struct ValidatorSigningKey { | ||
| /// Insecure, hex-encoded validator secret key for development and testing purposes. | ||
| /// | ||
| /// If not provided, a predefined key is used. | ||
| /// | ||
| /// Cannot be used with `key.kms-id`. | ||
| /// Cannot be used with `signing-key.kms-id`. | ||
| #[arg( | ||
| long = "key.hex", | ||
| env = ENV_KEY, | ||
| value_name = "VALIDATOR_KEY", | ||
| default_value = INSECURE_KEY_HEX, | ||
| long = "signing-key.hex", | ||
| env = ENV_SIGNING_KEY, | ||
| value_name = "VALIDATOR_SIGNING_KEY", | ||
| default_value = INSECURE_SIGNING_KEY_HEX, | ||
| )] | ||
| pub validator_key: String, | ||
| pub signing_key: String, | ||
| /// Key ID for the KMS key used by validator to sign blocks. | ||
| /// | ||
| /// Cannot be used with `key.hex`. | ||
| /// Cannot be used with `signing-key.hex`. | ||
| #[arg( | ||
| long = "key.kms-id", | ||
| env = ENV_KMS_KEY_ID, | ||
| value_name = "VALIDATOR_KMS_KEY_ID", | ||
| long = "signing-key.kms-id", | ||
| env = ENV_SIGNING_KEY_KMS_ID, | ||
| value_name = "VALIDATOR_SIGNING_KEY_KMS_ID", | ||
| )] | ||
| pub validator_kms_key_id: Option<String>, | ||
| pub signing_key_kms_id: Option<String>, | ||
| } | ||
|
|
||
| impl ValidatorKey { | ||
| impl ValidatorSigningKey { | ||
| pub async fn into_signer(self) -> anyhow::Result<ValidatorSigner> { | ||
| if let Some(kms_key_id) = self.validator_kms_key_id { | ||
| if let Some(kms_key_id) = self.signing_key_kms_id { | ||
| Ok(ValidatorSigner::new_kms(kms_key_id).await?) | ||
| } else { | ||
| let signer = SigningKey::read_from_bytes(hex::decode(self.validator_key)?.as_ref())?; | ||
| let signer = SigningKey::read_from_bytes(hex::decode(self.signing_key)?.as_ref())?; | ||
| Ok(ValidatorSigner::new_local(signer)) | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.