diff --git a/Cargo.lock b/Cargo.lock index a8db2298d..0e64197ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1709,6 +1709,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "levenshtein" version = "1.0.5" @@ -2477,6 +2483,7 @@ dependencies = [ "harmonizer", "heck", "houston", + "lazycell", "opener", "os_info", "predicates", diff --git a/Cargo.toml b/Cargo.toml index d73544218..27f873c46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ git-url-parse = "0.3" git2 = { version = "0.13", default-features = false, features = ["vendored-openssl"] } harmonizer = { version = "0.27.0", optional = true } heck = "0.3" +lazycell = "1" opener = "0.5" os_info = "3.0" prettytable-rs = "0.8" diff --git a/docs/source/configuring.md b/docs/source/configuring.md index 7e72883b1..5e27c79b7 100644 --- a/docs/source/configuring.md +++ b/docs/source/configuring.md @@ -265,6 +265,13 @@ If you use a version control system besides Git, you can use the environment var Currently, only Git is fully supported by Apollo Studio. +## Bypass TLS/SSL Validation + +In some configurations (often on internal networks) users may need Rover to communicate over encrypted channels (e.g., HTTPS) but avoid the more stringent digital certificate verifications which validate hostnames or may even wish to bypass the digital certificate validation entirely. This is generally not recommended and considered to be much less secure but for cases where it's necessary, there are two flags you can use to configure how Rover validates HTTPS requests: + +- The `--insecure-accept-invalid-hostnames` flag will disable hostname validation. If hostname verification is not used, any valid certificate for any site will be trusted for use from any other. This introduces a significant vulnerability to man-in-the-middle attacks. + +- The `--insecure-accept-invalid-certs` flag will disable certificate validation. If invalid certificates are trusted, any certificate for any site will be trusted for use. This includes expired certificates. This introduces significant vulnerabilities, and should only be used as a last resort. ## Supported environment variables You can configure Rover's behavior by setting the environment variables listed below. diff --git a/src/cli.rs b/src/cli.rs index c10e3ca6c..130cd35b9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,5 @@ use camino::Utf8PathBuf; +use lazycell::AtomicLazyCell; use reqwest::blocking::Client; use serde::Serialize; use structopt::{clap::AppSettings, StructOpt}; @@ -6,7 +7,7 @@ use structopt::{clap::AppSettings, StructOpt}; use crate::command::output::JsonOutput; use crate::command::{self, RoverOutput}; use crate::utils::{ - client::StudioClientConfig, + client::{get_configured_client, StudioClientConfig}, env::{RoverEnv, RoverEnvKey}, stringify::option_from_display, version, @@ -66,13 +67,40 @@ pub struct Rover { #[structopt(long = "output", default_value = "plain", possible_values = &["json", "plain"], case_insensitive = true, global = true)] output_type: OutputType, + /// Accept invalid certificates when performing HTTPS requests. + /// + /// You should think very carefully before using this flag. + /// + /// If invalid certificates are trusted, any certificate for any site will be trusted for use. + /// This includes expired certificates. + /// This introduces significant vulnerabilities, and should only be used as a last resort. + #[structopt( + long = "insecure-accept-invalid-certs", + case_insensitive = true, + global = true + )] + accept_invalid_certs: bool, + + /// Accept invalid hostnames when performing HTTPS requests. + /// + /// You should think very carefully before using this flag. + /// + /// If hostname verification is not used, any valid certificate for any site will be trusted for use from any other. + /// This introduces a significant vulnerability to man-in-the-middle attacks. + #[structopt( + long = "insecure-accept-invalid-hostnames", + case_insensitive = true, + global = true + )] + accept_invalid_hostnames: bool, + #[structopt(skip)] #[serde(skip_serializing)] pub(crate) env_store: RoverEnv, #[structopt(skip)] #[serde(skip_serializing)] - client: Client, + client: AtomicLazyCell, } impl Rover { @@ -214,8 +242,20 @@ impl Rover { } pub(crate) fn get_reqwest_client(&self) -> Client { - // we can use clone here freely since `reqwest` uses an `Arc` under the hood - self.client.clone() + // return a clone of the underlying client if it's already been populated + if let Some(client) = self.client.borrow() { + // we can use clone here freely since `reqwest` uses an `Arc` under the hood + client.clone() + } else { + // if a request hasn't been made yet, this cell won't be populated yet + self.client + .fill( + get_configured_client(self.accept_invalid_certs, self.accept_invalid_hostnames) + .expect("Could not configure the request client"), + ) + .expect("Could not overwrite the existing request client"); + self.get_reqwest_client() + } } } diff --git a/src/utils/client.rs b/src/utils/client.rs index 574c9799b..94f24ac05 100644 --- a/src/utils/client.rs +++ b/src/utils/client.rs @@ -8,6 +8,19 @@ use rover_client::blocking::StudioClient; /// the Apollo graph registry's production API endpoint const STUDIO_PROD_API_ENDPOINT: &str = "https://graphql.api.apollographql.com/api/graphql"; +pub(crate) fn get_configured_client( + accept_invalid_certs: bool, + accept_invalid_hostnames: bool, +) -> Result { + let client = Client::builder() + .gzip(true) + .brotli(true) + .danger_accept_invalid_certs(accept_invalid_certs) + .danger_accept_invalid_hostnames(accept_invalid_hostnames) + .build()?; + Ok(client) +} + pub struct StudioClientConfig { pub(crate) config: config::Config, client: Client,