Pass EL JWT secret key via cli flag (#3568)
## Proposed Changes In this change I've added a new beacon_node cli flag `--execution-jwt-secret-key` for passing the JWT secret directly as string. Without this flag, it was non-trivial to pass a secrets file containing a JWT secret key without compromising its contents into some management repo or fiddling around with manual file mounts for cloud-based deployments. When used in combination with environment variables, the secret can be injected into container-based systems like docker & friends quite easily. It's both possible to either specify the file_path to the JWT secret or pass the JWT secret directly. I've modified the docs and attached a test as well. ## Additional Info The logic has been adapted a bit so that either one of `--execution-jwt` or `--execution-jwt-secret-key` must be set when specifying `--execution-endpoint` so that it's still compatible with the semantics before this change and there's at least one secret provided.
This commit is contained in:
parent
4926e3967f
commit
242ae21e5d
@ -440,7 +440,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
JSON-RPC connection. Uses the same endpoint to populate the \
|
JSON-RPC connection. Uses the same endpoint to populate the \
|
||||||
deposit cache.")
|
deposit cache.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.requires("execution-jwt")
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("execution-jwt")
|
Arg::with_name("execution-jwt")
|
||||||
@ -452,6 +451,17 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.requires("execution-endpoint")
|
.requires("execution-endpoint")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("execution-jwt-secret-key")
|
||||||
|
.long("execution-jwt-secret-key")
|
||||||
|
.value_name("EXECUTION-JWT-SECRET-KEY")
|
||||||
|
.alias("jwt-secret-key")
|
||||||
|
.help("Hex-encoded JWT secret for the \
|
||||||
|
execution endpoint provided in the --execution-endpoint flag.")
|
||||||
|
.requires("execution-endpoint")
|
||||||
|
.conflicts_with("execution-jwt")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("execution-jwt-id")
|
Arg::with_name("execution-jwt-id")
|
||||||
.long("execution-jwt-id")
|
.long("execution-jwt-id")
|
||||||
|
@ -3,6 +3,7 @@ use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG;
|
|||||||
use client::{ClientConfig, ClientGenesis};
|
use client::{ClientConfig, ClientGenesis};
|
||||||
use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR};
|
use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR};
|
||||||
use environment::RuntimeContext;
|
use environment::RuntimeContext;
|
||||||
|
use execution_layer::DEFAULT_JWT_FILE;
|
||||||
use genesis::Eth1Endpoint;
|
use genesis::Eth1Endpoint;
|
||||||
use http_api::TlsConfig;
|
use http_api::TlsConfig;
|
||||||
use lighthouse_network::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig, PeerIdSerialized};
|
use lighthouse_network::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig, PeerIdSerialized};
|
||||||
@ -288,12 +289,34 @@ pub fn get_config<E: EthSpec>(
|
|||||||
let execution_endpoint =
|
let execution_endpoint =
|
||||||
parse_only_one_value(endpoints, SensitiveUrl::parse, "--execution-endpoint", log)?;
|
parse_only_one_value(endpoints, SensitiveUrl::parse, "--execution-endpoint", log)?;
|
||||||
|
|
||||||
// Parse a single JWT secret, logging warnings if multiple are supplied.
|
// JWTs are required if `--execution-endpoint` is supplied. They can be either passed via
|
||||||
//
|
// file_path or directly as string.
|
||||||
// JWTs are required if `--execution-endpoint` is supplied.
|
|
||||||
let secret_files: String = clap_utils::parse_required(cli_args, "execution-jwt")?;
|
let secret_file: PathBuf;
|
||||||
let secret_file =
|
// Parse a single JWT secret from a given file_path, logging warnings if multiple are supplied.
|
||||||
parse_only_one_value(&secret_files, PathBuf::from_str, "--execution-jwt", log)?;
|
if let Some(secret_files) = cli_args.value_of("execution-jwt") {
|
||||||
|
secret_file =
|
||||||
|
parse_only_one_value(secret_files, PathBuf::from_str, "--execution-jwt", log)?;
|
||||||
|
|
||||||
|
// Check if the JWT secret key is passed directly via cli flag and persist it to the default
|
||||||
|
// file location.
|
||||||
|
} else if let Some(jwt_secret_key) = cli_args.value_of("execution-jwt-secret-key") {
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
secret_file = client_config.data_dir.join(DEFAULT_JWT_FILE);
|
||||||
|
let mut jwt_secret_key_file = File::create(secret_file.clone())
|
||||||
|
.map_err(|e| format!("Error while creating jwt_secret_key file: {:?}", e))?;
|
||||||
|
jwt_secret_key_file
|
||||||
|
.write_all(jwt_secret_key.as_bytes())
|
||||||
|
.map_err(|e| {
|
||||||
|
format!(
|
||||||
|
"Error occured while writing to jwt_secret_key file: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
} else {
|
||||||
|
return Err("Error! Please set either --execution-jwt file_path or --execution-jwt-secret-key directly via cli when using --execution-endpoint".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
// Parse and set the payload builder, if any.
|
// Parse and set the payload builder, if any.
|
||||||
if let Some(endpoint) = cli_args.value_of("builder") {
|
if let Some(endpoint) = cli_args.value_of("builder") {
|
||||||
|
@ -48,6 +48,10 @@ If you set up an execution engine with `--execution-endpoint` then you *must* pr
|
|||||||
using `--execution-jwt`. This is a mandatory form of authentication that ensures that Lighthouse
|
using `--execution-jwt`. This is a mandatory form of authentication that ensures that Lighthouse
|
||||||
has authority to control the execution engine.
|
has authority to control the execution engine.
|
||||||
|
|
||||||
|
> Tip: the --execution-jwt-secret-key <STRING> flag can be used instead of --execution-jwt <FILE>.
|
||||||
|
> This is useful, for example, for users who wish to inject the value into a Docker container without
|
||||||
|
> needing to pass a jwt secret file.
|
||||||
|
|
||||||
The execution engine connection must be **exclusive**, i.e. you must have one execution node
|
The execution engine connection must be **exclusive**, i.e. you must have one execution node
|
||||||
per beacon node. The reason for this is that the beacon node _controls_ the execution node. Please
|
per beacon node. The reason for this is that the beacon node _controls_ the execution node. Please
|
||||||
see the [FAQ](#faq) for further information about why many:1 and 1:many configurations are not
|
see the [FAQ](#faq) for further information about why many:1 and 1:many configurations are not
|
||||||
|
@ -4,7 +4,7 @@ use crate::exec::{CommandLineTestExec, CompletedTest};
|
|||||||
use eth1::Eth1Endpoint;
|
use eth1::Eth1Endpoint;
|
||||||
use lighthouse_network::PeerId;
|
use lighthouse_network::PeerId;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@ -386,6 +386,27 @@ fn run_merge_execution_endpoints_flag_test(flag: &str) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
fn run_execution_jwt_secret_key_is_persisted() {
|
||||||
|
let jwt_secret_key = "0x3cbc11b0d8fa16f3344eacfd6ff6430b9d30734450e8adcf5400f88d327dcb33";
|
||||||
|
CommandLineTest::new()
|
||||||
|
.flag("execution-endpoint", Some("http://localhost:8551/"))
|
||||||
|
.flag("execution-jwt-secret-key", Some(jwt_secret_key))
|
||||||
|
.run_with_zero_port()
|
||||||
|
.with_config(|config| {
|
||||||
|
let config = config.execution_layer.as_ref().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
config.execution_endpoints[0].full.to_string(),
|
||||||
|
"http://localhost:8551/"
|
||||||
|
);
|
||||||
|
let mut file_jwt_secret_key = String::new();
|
||||||
|
File::open(config.secret_files[0].clone())
|
||||||
|
.expect("could not open jwt_secret_key file")
|
||||||
|
.read_to_string(&mut file_jwt_secret_key)
|
||||||
|
.expect("could not read from file");
|
||||||
|
assert_eq!(file_jwt_secret_key, jwt_secret_key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
fn merge_execution_endpoints_flag() {
|
fn merge_execution_endpoints_flag() {
|
||||||
run_merge_execution_endpoints_flag_test("execution-endpoints")
|
run_merge_execution_endpoints_flag_test("execution-endpoints")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user