feat: use openssl for tls connections, add CA_ROOT_FILE support (#268) (h/t @kapcsandi)

This commit is contained in:
Stepan Kuzmin 2021-10-18 14:35:08 +03:00 committed by GitHub
parent d4d101c7f9
commit 7ad7f1ab8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 127 deletions

118
Cargo.lock generated
View File

@ -545,22 +545,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
[[package]]
name = "core-foundation"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
version = "0.2.1"
@ -1244,11 +1228,11 @@ dependencies = [
"env_logger",
"itertools",
"log",
"native-tls",
"num_cpus",
"openssl",
"postgis",
"postgres",
"postgres-native-tls",
"postgres-openssl",
"postgres-protocol",
"r2d2",
"r2d2_postgres",
@ -1384,24 +1368,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "native-tls"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "net2"
version = "0.2.37"
@ -1473,12 +1439,6 @@ dependencies = [
"openssl-sys",
]
[[package]]
name = "openssl-probe"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.67"
@ -1668,15 +1628,15 @@ dependencies = [
]
[[package]]
name = "postgres-native-tls"
name = "postgres-openssl"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d442770e2b1e244bb5eb03b31c79b65bb2568f413b899eaba850fa945a65954"
checksum = "1de0ea6504e07ca78355a6fb88ad0f36cafe9e696cbc6717f16a207f3a60be72"
dependencies = [
"futures",
"native-tls",
"openssl",
"tokio 1.12.0",
"tokio-native-tls",
"tokio-openssl",
"tokio-postgres",
]
@ -1914,15 +1874,6 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "resolv-conf"
version = "0.7.0"
@ -1975,16 +1926,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
"winapi 0.3.9",
]
[[package]]
name = "scheduled-thread-pool"
version = "0.2.5"
@ -2000,29 +1941,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -2298,20 +2216,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if 1.0.0",
"libc",
"rand 0.8.4",
"redox_syscall",
"remove_dir_all",
"winapi 0.3.9",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@ -2469,12 +2373,14 @@ dependencies = [
]
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
name = "tokio-openssl"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
checksum = "f24cddc8445a4dc8359cdd9e91c19d544fc95f672e32afe8945852b9381a09fe"
dependencies = [
"native-tls",
"futures",
"openssl",
"openssl-sys",
"tokio 1.12.0",
]

View File

@ -24,12 +24,12 @@ docopt = "1"
env_logger = "0.9"
itertools = "0.10"
log = "0.4"
native-tls = "0.2"
num_cpus = "1.13"
postgres = { version = "0.19.1", features = ["with-time-0_2", "with-uuid-0_8", "with-serde_json-1"] }
postgres-native-tls = "0.5.0"
postgres-protocol = "0.6.2"
openssl = "0.10.36"
postgis = "0.9.0"
postgres = { version = "0.19.1", features = ["with-time-0_2", "with-uuid-0_8", "with-serde_json-1"] }
postgres-openssl = "0.5.0"
postgres-protocol = "0.6.2"
r2d2 = "0.8"
r2d2_postgres = "0.18"
semver = "1.0"

View File

@ -366,6 +366,7 @@ Options:
--pool-size=<n> Maximum connections pool size [default: 20].
--watch Scan for new sources on sources list requests.
--workers=<n> Number of web server workers.
--ca-root-file=<path> Loads trusted root certificates from a file. The file should contain a sequence of PEM-formatted CA certificates.
--danger-accept-invalid-certs Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
```
@ -374,10 +375,11 @@ Options:
You can also configure martin using environment variables
| Environment variable | Example | Description |
| --------------------------- | -------------------------------- | ---------------------------- |
| DATABASE_URL | postgres://postgres@localhost/db | postgres database connection |
| WATCH_MODE | true | scan for new sources |
| DANGER_ACCEPT_INVALID_CERTS | false | Trust invalid certificates |
| ----------------------------- | ---------------------------------- | --------------------------------------------- |
| `DATABASE_URL` | `postgres://postgres@localhost/db` | Postgres database connection |
| `WATCH_MODE` | `true` | Scan for new sources on sources list requests |
| `CA_ROOT_FILE` | `./ca-certificate.crt` | Loads trusted root certificates from a file |
| `DANGER_ACCEPT_INVALID_CERTS` | `false` | Trust invalid certificates |
## Configuration File

View File

@ -32,6 +32,7 @@ Options:
--pool-size=<n> Maximum connections pool size [default: 20].
--watch Scan for new sources on sources list requests.
--workers=<n> Number of web server workers.
--ca-root-file=<path> Loads trusted root certificates from a file. The file should contain a sequence of PEM-formatted CA certificates.
--danger-accept-invalid-certs Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
";
@ -46,6 +47,7 @@ pub struct Args {
pub flag_watch: bool,
pub flag_version: bool,
pub flag_workers: Option<usize>,
pub flag_ca_root_file: Option<String>,
pub flag_danger_accept_invalid_certs: bool,
}
@ -70,6 +72,7 @@ pub fn generate_config(args: Args, pool: &Pool) -> io::Result<Config> {
worker_processes: args.flag_workers,
table_sources: Some(table_sources),
function_sources: Some(function_sources),
ca_root_file: None,
danger_accept_invalid_certs: Some(args.flag_danger_accept_invalid_certs),
};
@ -82,6 +85,7 @@ fn setup_from_config(file_name: String) -> io::Result<(Config, Pool)> {
let pool = setup_connection_pool(
&config.connection_string,
&config.ca_root_file,
Some(config.pool_size),
config.danger_accept_invalid_certs,
)
@ -124,6 +128,7 @@ fn setup_from_args(args: Args) -> io::Result<(Config, Pool)> {
info!("Connecting to database");
let pool = setup_connection_pool(
&connection_string,
&args.flag_ca_root_file,
args.flag_pool_size,
args.flag_danger_accept_invalid_certs,
)
@ -141,6 +146,10 @@ fn parse_env(args: Args) -> Args {
env::var_os("DATABASE_URL").and_then(|connection| connection.into_string().ok())
});
let flag_ca_root_file = args.flag_ca_root_file.or_else(|| {
env::var_os("CA_ROOT_FILE").and_then(|connection| connection.into_string().ok())
});
let flag_danger_accept_invalid_certs = args.flag_danger_accept_invalid_certs
|| env::var_os("DANGER_ACCEPT_INVALID_CERTS").is_some();
@ -149,6 +158,7 @@ fn parse_env(args: Args) -> Args {
Args {
arg_connection,
flag_watch,
flag_ca_root_file,
flag_danger_accept_invalid_certs,
..args
}

View File

@ -17,6 +17,7 @@ pub struct Config {
pub connection_string: String,
pub table_sources: Option<TableSources>,
pub function_sources: Option<FunctionSources>,
pub ca_root_file: Option<String>,
pub danger_accept_invalid_certs: bool,
}
@ -30,6 +31,7 @@ pub struct ConfigBuilder {
pub connection_string: String,
pub table_sources: Option<TableSources>,
pub function_sources: Option<FunctionSources>,
pub ca_root_file: Option<String>,
pub danger_accept_invalid_certs: Option<bool>,
}
@ -46,6 +48,7 @@ impl ConfigBuilder {
connection_string: self.connection_string,
table_sources: self.table_sources,
function_sources: self.function_sources,
ca_root_file: self.ca_root_file,
danger_accept_invalid_certs: self.danger_accept_invalid_certs.unwrap_or(false),
}
}

View File

@ -1,8 +1,8 @@
use std::io;
use std::str::FromStr;
use native_tls::TlsConnector;
use postgres_native_tls::MakeTlsConnector;
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
use postgres_openssl::MakeTlsConnector;
use r2d2::PooledConnection;
use r2d2_postgres::PostgresConnectionManager;
use semver::Version;
@ -14,25 +14,37 @@ pub type ConnectionManager = PostgresConnectionManager<MakeTlsConnector>;
pub type Pool = r2d2::Pool<ConnectionManager>;
pub type Connection = PooledConnection<ConnectionManager>;
fn make_tls_connector(danger_accept_invalid_certs: bool) -> io::Result<MakeTlsConnector> {
let connector = TlsConnector::builder()
.danger_accept_invalid_certs(danger_accept_invalid_certs)
.build()
.map_err(prettify_error("Can't build TLS connection".to_owned()))?;
fn make_tls_connector(
ca_root_file: &Option<String>,
danger_accept_invalid_certs: bool,
) -> io::Result<MakeTlsConnector> {
let mut builder = SslConnector::builder(SslMethod::tls())?;
let tls_connector = MakeTlsConnector::new(connector);
if danger_accept_invalid_certs {
builder.set_verify(SslVerifyMode::NONE);
}
if let Some(ca_root_file) = ca_root_file {
info!("Using {} as trusted root certificate", ca_root_file);
builder.set_ca_file(ca_root_file)?;
}
let tls_connector = MakeTlsConnector::new(builder.build());
Ok(tls_connector)
}
pub fn setup_connection_pool(
cn_str: &str,
connection_string: &str,
ca_root_file: &Option<String>,
pool_size: Option<u32>,
danger_accept_invalid_certs: bool,
) -> io::Result<Pool> {
let config = postgres::config::Config::from_str(cn_str)
let config = postgres::config::Config::from_str(connection_string)
.map_err(prettify_error("Can't parse connection string".to_owned()))?;
let tls_connector = make_tls_connector(danger_accept_invalid_certs)?;
let tls_connector = make_tls_connector(ca_root_file, danger_accept_invalid_certs)
.map_err(prettify_error("Can't build TLS connection".to_owned()))?;
let manager = PostgresConnectionManager::new(config, tls_connector);
let pool = r2d2::Pool::builder()

View File

@ -128,7 +128,7 @@ pub fn make_pool() -> Pool {
let connection_string: String = env::var("DATABASE_URL").unwrap();
info!("Connecting to {}", connection_string);
let pool = setup_connection_pool(&connection_string, Some(1), false).unwrap();
let pool = setup_connection_pool(&connection_string, &None, Some(1), false).unwrap();
info!("Connected to {}", connection_string);
pool