diff --git a/book/src/api-vc.md b/book/src/api-vc.md index 0a8941edaf7..6ee79d4f720 100644 --- a/book/src/api-vc.md +++ b/book/src/api-vc.md @@ -17,18 +17,21 @@ The following CLI flags control the HTTP server: - `--http`: enable the HTTP server (required even if the following flags are provided). +- `--http-address`: specify the listen address of the server. It is almost always unsafe to use a non-default HTTP listen address. Use with caution. See the **Security** section below for more information. - `--http-port`: specify the listen port of the server. - `--http-allow-origin`: specify the value of the `Access-Control-Allow-Origin` header. The default is to not supply a header. ## Security -The validator client HTTP is **not encrypted** (i.e., it is **not HTTPS**). For -this reason, it will only listen on `127.0.0.1`. +The validator client HTTP server is **not encrypted** (i.e., it is **not HTTPS**). For +this reason, it will listen by default on `127.0.0.1`. It is unsafe to expose the validator client to the public Internet without additional transport layer security (e.g., HTTPS via nginx, SSH tunnels, etc.). +For custom setups, such as certain Docker configurations, a custom HTTP listen address can be used by passing the `--http-address` and `--unencrypted-http-transport` flags. The `--unencrypted-http-transport` flag is a safety flag which is required to ensure the user is aware of the potential risks when using a non-default listen address. + ### CLI Example Start the validator client with the HTTP server listening on [http://localhost:5062](http://localhost:5062): diff --git a/lighthouse/tests/validator_client.rs b/lighthouse/tests/validator_client.rs index a6a644fd4d6..ac255dffa02 100644 --- a/lighthouse/tests/validator_client.rs +++ b/lighthouse/tests/validator_client.rs @@ -284,6 +284,24 @@ fn http_flag() { .with_config(|config| assert!(config.http_api.enabled)); } #[test] +fn http_address_flag() { + let addr = "127.0.0.99".parse::().unwrap(); + CommandLineTest::new() + .flag("http-address", Some("127.0.0.99")) + .flag("unencrypted-http-transport", None) + .run() + .with_config(|config| assert_eq!(config.http_api.listen_addr, addr)); +} +#[test] +#[should_panic] +fn missing_unencrypted_http_transport_flag() { + let addr = "127.0.0.99".parse::().unwrap(); + CommandLineTest::new() + .flag("http-address", Some("127.0.0.99")) + .run() + .with_config(|config| assert_eq!(config.http_api.listen_addr, addr)); +} +#[test] fn http_port_flag() { CommandLineTest::new() .flag("http-port", Some("9090")) diff --git a/validator_client/src/cli.rs b/validator_client/src/cli.rs index 08d3d9ae56e..df346cfeb9c 100644 --- a/validator_client/src/cli.rs +++ b/validator_client/src/cli.rs @@ -125,23 +125,36 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .takes_value(false), ) /* - * Note: there is purposefully no `--http-address` flag provided. + * Note: The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is + * unsafe to publish on a public network. * - * The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is unsafe to - * publish on a public network. - * - * We restrict the user to `127.0.0.1` and they must provide some other transport-layer - * encryption (e.g., SSH tunnels). + * If the `--http-address` flag is used, the `--unencrypted-http-transport` flag + * must also be used in order to make it clear to the user that this is unsafe. */ + .arg( + Arg::with_name("http-address") + .long("http-address") + .value_name("ADDRESS") + .help("Set the address for the HTTP address. The HTTP server is not encrypted \ + and therefore it is unsafe to publish on a public network. When this \ + flag is used, it additionally requires the explicit use of the \ + `--unencrypted-http-transport` flag to ensure the user is aware of the \ + risks involved. For access via the Internet, users should apply \ + transport-layer security like a HTTPS reverse-proxy or SSH tunnelling.") + .requires("unencrypted-http-transport"), + ) + .arg( + Arg::with_name("unencrypted-http-transport") + .long("unencrypted-http-transport") + .help("This is a safety flag to ensure that the user is aware that the http \ + transport is unencrypted and using a custom HTTP address is unsafe.") + .requires("http-address"), + ) .arg( Arg::with_name("http-port") .long("http-port") .value_name("PORT") - .help("Set the listen TCP port for the RESTful HTTP API server. This server does **not** \ - provide encryption and is completely unsuitable to expose to a public network. \ - We do not provide a --http-address flag and restrict the user to listening on \ - 127.0.0.1. For access via the Internet, apply a transport-layer security like \ - a HTTPS reverse-proxy or SSH tunnelling.") + .help("Set the listen TCP port for the RESTful HTTP API server.") .default_value("5062") .takes_value(true), ) diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index b299247de20..ba1c2ce9e59 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -197,6 +197,19 @@ impl Config { config.http_api.enabled = true; } + if let Some(address) = cli_args.value_of("http-address") { + if cli_args.is_present("unencrypted-http-transport") { + config.http_api.listen_addr = address + .parse::() + .map_err(|_| "http-address is not a valid IPv4 address.")?; + } else { + return Err( + "While using `--http-address`, you must also use `--unencrypted-http-transport`." + .to_string(), + ); + } + } + if let Some(port) = cli_args.value_of("http-port") { config.http_api.listen_port = port .parse::()