Skip to content

Commit

Permalink
feat: use openssl for tls connections, add CA_ROOT_FILE support (#268)…
Browse files Browse the repository at this point in the history
… (h/t @kapcsandi)
  • Loading branch information
stepankuzmin authored Oct 18, 2021
1 parent d4d101c commit 7ad7f1a
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 126 deletions.
118 changes: 12 additions & 106 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ docopt = "1"
env_logger = "0.9"
itertools = "0.10"
log = "0.4"
native-tls = "0.2"
num_cpus = "1.13"
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-native-tls = "0.5.0"
postgres-openssl = "0.5.0"
postgres-protocol = "0.6.2"
postgis = "0.9.0"
r2d2 = "0.8"
r2d2_postgres = "0.18"
semver = "1.0"
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,18 +366,20 @@ 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.
```

## Environment Variables

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 |
| Environment variable | Example | Description |
| ----------------------------- | ---------------------------------- | --------------------------------------------- |
| `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

Expand Down
10 changes: 10 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
";

Expand All @@ -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,
}

Expand All @@ -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),
};

Expand All @@ -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,
)
Expand Down Expand Up @@ -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,
)
Expand All @@ -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();

Expand All @@ -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
}
Expand Down
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -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>,
}

Expand All @@ -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),
}
}
Expand Down
34 changes: 23 additions & 11 deletions src/db.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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())?;

if danger_accept_invalid_certs {
builder.set_verify(SslVerifyMode::NONE);
}

let tls_connector = MakeTlsConnector::new(connector);
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()
Expand Down
2 changes: 1 addition & 1 deletion src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 7ad7f1a

Please sign in to comment.