Skip to content

Commit 51e31e7

Browse files
authored
Merge pull request #31 from stackhpc/feature/tls
Initial TLS support
2 parents 5b27c64 + d246eff commit 51e31e7

File tree

3 files changed

+84
-7
lines changed

3 files changed

+84
-7
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ Cargo.lock
1717
# Added by cargo
1818

1919
/target
20+
21+
# Dev TLS certs
22+
.certs/

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ aws-smithy-http = "0.54"
1515
aws-smithy-types = "0.54"
1616
aws-types = "0.54"
1717
axum = { version = "0.6", features = ["headers"] }
18+
axum-server = { version = "0.4.7", features = ["tls-rustls"] }
1819
clap = { version = "4.2.1", features = ["derive", "env"] }
20+
expanduser = "1.2.2"
1921
http = "*"
2022
hyper = { version = "0.14", features = ["full"] }
2123
maligned = "0.2.1"

src/main.rs

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
//! * [ndarray] provides [NumPy](https://numpy.orgq)-like n-dimensional arrays used in numerical
2323
//! computation.
2424
25+
use std::{net::SocketAddr, process::exit, str::FromStr, time::Duration};
26+
27+
use axum_server::{tls_rustls::RustlsConfig, Handle};
2528
use clap::Parser;
29+
use expanduser::expanduser;
2630
use tokio::signal;
2731
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
2832

@@ -44,6 +48,26 @@ struct CommandLineArgs {
4448
/// The port to which the proxy should bind
4549
#[arg(long, default_value_t = 8080, env = "S3_ACTIVE_STORAGE_PORT")]
4650
port: u16,
51+
/// Flag indicating whether HTTPS should be used
52+
#[arg(long, default_value_t = false, env = "S3_ACTIVE_STORAGE_HTTPS")]
53+
https: bool,
54+
/// Path to the certificate file to be used for HTTPS encryption
55+
#[arg(
56+
long,
57+
default_value = "~/.config/s3-active-storage/certs/cert.pem",
58+
env = "S3_ACTIVE_STORAGE_CERT_FILE"
59+
)]
60+
cert_file: String,
61+
/// Path to the key file to be used for HTTPS encryption
62+
#[arg(
63+
long,
64+
default_value = "~/.config/s3-active-storage/certs/key.pem",
65+
env = "S3_ACTIVE_STORAGE_KEY_FILE"
66+
)]
67+
key_file: String,
68+
/// Maximum time in seconds to wait for operations to complete upon receiving `ctrl+c` signal.
69+
#[arg(long, default_value_t = 60, env = "S3_ACTIVE_STORAGE_SHUTDOWN_TIMEOUT")]
70+
graceful_shutdown_timeout: u64,
4771
}
4872

4973
/// Application entry point
@@ -54,13 +78,59 @@ async fn main() {
5478
init_tracing();
5579

5680
let router = app::router();
81+
let addr = SocketAddr::from_str(&format!("{}:{}", args.host, args.port))
82+
.expect("invalid host name, IP address or port number");
83+
84+
// Catch ctrl+c and try to shutdown gracefully
85+
let handle = Handle::new();
86+
tokio::spawn(shutdown_signal(
87+
handle.clone(),
88+
args.graceful_shutdown_timeout,
89+
));
5790

58-
// run it with hyper
59-
axum::Server::bind(&format!("{}:{}", args.host, args.port).parse().unwrap())
60-
.serve(router.into_make_service())
61-
.with_graceful_shutdown(shutdown_signal())
62-
.await
63-
.unwrap();
91+
if args.https {
92+
// Expand files
93+
let abs_cert_file = expanduser(args.cert_file)
94+
.expect("Failed to expand ~ to user name. Please provide an absolute path instead.")
95+
.canonicalize()
96+
.expect("failed to determine absolute path to TLS cerficate file");
97+
let abs_key_file = expanduser(args.key_file)
98+
.expect("Failed to expand ~ to user name. Please provide an absolute path instead.")
99+
.canonicalize()
100+
.expect("failed to determine absolute path to TLS key file");
101+
// Check files exist
102+
if !abs_cert_file.exists() {
103+
println!(
104+
"TLS certificate file expected at '{}' but not found.",
105+
abs_cert_file.display()
106+
);
107+
exit(1)
108+
}
109+
if !abs_key_file.exists() {
110+
println!(
111+
"TLS key file expected at '{}' but not found.",
112+
abs_key_file.display()
113+
);
114+
exit(1)
115+
}
116+
// Set up TLS config
117+
let tls_config = RustlsConfig::from_pem_file(abs_cert_file, abs_key_file)
118+
.await
119+
.expect("Failed to load TLS certificate files");
120+
// run HTTPS server with hyper
121+
axum_server::bind_rustls(addr, tls_config)
122+
.handle(handle)
123+
.serve(router.into_make_service())
124+
.await
125+
.unwrap();
126+
} else {
127+
// run HTTP server with hyper
128+
axum_server::bind(addr)
129+
.handle(handle)
130+
.serve(router.into_make_service())
131+
.await
132+
.unwrap();
133+
}
64134
}
65135

66136
/// Initlialise tracing (logging)
@@ -80,7 +150,7 @@ fn init_tracing() {
80150
/// Graceful shutdown handler
81151
///
82152
/// Installs signal handlers to catch Ctrl-C or SIGTERM and trigger a graceful shutdown.
83-
async fn shutdown_signal() {
153+
async fn shutdown_signal(handle: Handle, timeout: u64) {
84154
let ctrl_c = async {
85155
signal::ctrl_c()
86156
.await
@@ -104,4 +174,6 @@ async fn shutdown_signal() {
104174
}
105175

106176
println!("signal received, starting graceful shutdown");
177+
// Force shutdown if graceful shutdown takes longer than 10s
178+
handle.graceful_shutdown(Some(Duration::from_secs(timeout)));
107179
}

0 commit comments

Comments
 (0)