Support TLS upstream & downstream
This commit is contained in:
parent
976b9851d3
commit
122c17424c
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1812,6 +1812,7 @@ dependencies = [
|
||||||
"rustls-channel-resolver",
|
"rustls-channel-resolver",
|
||||||
"rustls-pemfile 2.0.0",
|
"rustls-pemfile 2.0.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-actix-web",
|
"tracing-actix-web",
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
|
|
|
@ -32,6 +32,7 @@ rustls = "0.22"
|
||||||
rustls-channel-resolver = "0.1.0"
|
rustls-channel-resolver = "0.1.0"
|
||||||
rustls-pemfile = "2.0.0"
|
rustls-pemfile = "2.0.0"
|
||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
|
tokio = { version = "1", features = ["fs"] }
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-actix-web = { version = "0.7.6", features = ["opentelemetry_0_21", "emit_event_on_error"] }
|
tracing-actix-web = { version = "0.7.6", features = ["opentelemetry_0_21", "emit_event_on_error"] }
|
||||||
tracing-error = "0.2.0"
|
tracing-error = "0.2.0"
|
||||||
|
|
117
src/main.rs
117
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::net::SocketAddr;
|
use std::{net::SocketAddr, path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
body::BodyStream, error::ErrorInternalServerError, web, App, HttpResponse, HttpServer,
|
body::BodyStream, error::ErrorInternalServerError, web, App, HttpResponse, HttpServer,
|
||||||
|
@ -11,6 +11,7 @@ use opentelemetry_sdk::{propagation::TraceContextPropagator, Resource};
|
||||||
use reqwest::{redirect::Policy, Client};
|
use reqwest::{redirect::Policy, Client};
|
||||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||||
use reqwest_tracing::TracingMiddleware;
|
use reqwest_tracing::TracingMiddleware;
|
||||||
|
use rustls_021::ServerConfig;
|
||||||
use tracing_actix_web::TracingLogger;
|
use tracing_actix_web::TracingLogger;
|
||||||
use tracing_error::ErrorLayer;
|
use tracing_error::ErrorLayer;
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
|
@ -24,7 +25,7 @@ struct Args {
|
||||||
short,
|
short,
|
||||||
long,
|
long,
|
||||||
env = "PICTRS_ADMIN__BIND_ADDRESS",
|
env = "PICTRS_ADMIN__BIND_ADDRESS",
|
||||||
default_value = "127.0.0.1:8084"
|
default_value = "[::]:8084"
|
||||||
)]
|
)]
|
||||||
bind_address: SocketAddr,
|
bind_address: SocketAddr,
|
||||||
#[clap(
|
#[clap(
|
||||||
|
@ -41,6 +42,12 @@ struct Args {
|
||||||
console_address: Option<SocketAddr>,
|
console_address: Option<SocketAddr>,
|
||||||
#[clap(long, env = "PICTRS_ADMIN__CONSOLE_EVENT_BUFFER_SIZE")]
|
#[clap(long, env = "PICTRS_ADMIN__CONSOLE_EVENT_BUFFER_SIZE")]
|
||||||
console_event_buffer_size: Option<usize>,
|
console_event_buffer_size: Option<usize>,
|
||||||
|
#[clap(long, env = "PICTRS_ADMIN__CERTIFICATE")]
|
||||||
|
pict_rs_certificate: Option<PathBuf>,
|
||||||
|
#[clap(long, env = "PICTRS_ADMIN__SERVER_CERTIFICATE")]
|
||||||
|
server_certificate: Option<PathBuf>,
|
||||||
|
#[clap(long, env = "PICTRS_ADMIN__SERVER_PRIVATE_KEY")]
|
||||||
|
server_private_key: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -276,7 +283,7 @@ async fn serve_static(name: web::Path<String>) -> HttpResponse {
|
||||||
fn init_tracing(
|
fn init_tracing(
|
||||||
service_name: &'static str,
|
service_name: &'static str,
|
||||||
opentelemetry_url: Option<&Url>,
|
opentelemetry_url: Option<&Url>,
|
||||||
console_addr: Option<SocketAddr>,
|
console_address: Option<SocketAddr>,
|
||||||
console_event_buffer_size: Option<usize>,
|
console_event_buffer_size: Option<usize>,
|
||||||
) -> color_eyre::Result<()> {
|
) -> color_eyre::Result<()> {
|
||||||
opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new());
|
opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new());
|
||||||
|
@ -293,7 +300,7 @@ fn init_tracing(
|
||||||
.with(format_layer)
|
.with(format_layer)
|
||||||
.with(ErrorLayer::default());
|
.with(ErrorLayer::default());
|
||||||
|
|
||||||
if let Some(addr) = console_addr {
|
if let Some(addr) = console_address {
|
||||||
let builder = ConsoleLayer::builder().with_default_env().server_addr(addr);
|
let builder = ConsoleLayer::builder().with_default_env().server_addr(addr);
|
||||||
|
|
||||||
let console_layer = if let Some(buffer_size) = console_event_buffer_size {
|
let console_layer = if let Some(buffer_size) = console_event_buffer_size {
|
||||||
|
@ -304,10 +311,12 @@ fn init_tracing(
|
||||||
|
|
||||||
let subscriber = subscriber.with(console_layer);
|
let subscriber = subscriber.with(console_layer);
|
||||||
|
|
||||||
init_subscriber(subscriber, targets, opentelemetry_url, service_name)
|
init_subscriber(subscriber, targets, opentelemetry_url, service_name)?;
|
||||||
|
tracing::info!("Starting console on {addr}");
|
||||||
} else {
|
} else {
|
||||||
init_subscriber(subscriber, targets, opentelemetry_url, service_name)
|
init_subscriber(subscriber, targets, opentelemetry_url, service_name)?;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_subscriber<S>(
|
fn init_subscriber<S>(
|
||||||
|
@ -349,6 +358,42 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn add_root_certificates(
|
||||||
|
builder: reqwest::ClientBuilder,
|
||||||
|
path: &PathBuf,
|
||||||
|
) -> color_eyre::Result<reqwest::ClientBuilder> {
|
||||||
|
let bytes = tokio::fs::read(path).await?;
|
||||||
|
|
||||||
|
let res = rustls_pemfile::certs(&mut bytes.as_slice()).try_fold(builder, |builder, res| {
|
||||||
|
let cert = res?;
|
||||||
|
let cert = reqwest::Certificate::from_der(&cert)?;
|
||||||
|
|
||||||
|
Ok(builder.add_root_certificate(cert))
|
||||||
|
});
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn open_keys(
|
||||||
|
certificate: &PathBuf,
|
||||||
|
private_key: &PathBuf,
|
||||||
|
) -> color_eyre::Result<rustls_021::sign::CertifiedKey> {
|
||||||
|
let cert_bytes = tokio::fs::read(certificate).await?;
|
||||||
|
let key_bytes = tokio::fs::read(private_key).await?;
|
||||||
|
|
||||||
|
let certs = rustls_pemfile::certs(&mut cert_bytes.as_slice())
|
||||||
|
.map(|res| res.map(|c| rustls_021::Certificate(c.to_vec())))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let key = rustls_pemfile::private_key(&mut key_bytes.as_slice())?
|
||||||
|
.ok_or_else(|| color_eyre::eyre::eyre!("No key in keyfile"))?;
|
||||||
|
|
||||||
|
let signing_key =
|
||||||
|
rustls_021::sign::any_supported_type(&rustls_021::PrivateKey(key.secret_der().to_vec()))?;
|
||||||
|
|
||||||
|
Ok(rustls_021::sign::CertifiedKey::new(certs, signing_key))
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> color_eyre::Result<()> {
|
async fn main() -> color_eyre::Result<()> {
|
||||||
let Args {
|
let Args {
|
||||||
|
@ -358,6 +403,9 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
opentelemetry_url,
|
opentelemetry_url,
|
||||||
console_address,
|
console_address,
|
||||||
console_event_buffer_size,
|
console_event_buffer_size,
|
||||||
|
pict_rs_certificate,
|
||||||
|
server_certificate,
|
||||||
|
server_private_key,
|
||||||
} = Args::parse();
|
} = Args::parse();
|
||||||
|
|
||||||
init_tracing(
|
init_tracing(
|
||||||
|
@ -367,10 +415,15 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
console_event_buffer_size,
|
console_event_buffer_size,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let client = Client::builder()
|
let builder = Client::builder()
|
||||||
.user_agent("pict-rs-admin v0.1.0")
|
.user_agent("pict-rs-admin v0.2.0")
|
||||||
.redirect(Policy::none())
|
.redirect(Policy::none());
|
||||||
.build()?;
|
|
||||||
|
let client = if let Some(path) = pict_rs_certificate {
|
||||||
|
add_root_certificates(builder, &path).await?.build()?
|
||||||
|
} else {
|
||||||
|
builder.build()?
|
||||||
|
};
|
||||||
|
|
||||||
let client = ClientBuilder::new(client)
|
let client = ClientBuilder::new(client)
|
||||||
.with(TracingMiddleware::default())
|
.with(TracingMiddleware::default())
|
||||||
|
@ -382,7 +435,7 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
pict_rs_api_key,
|
pict_rs_api_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpServer::new(move || {
|
let server = HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(TracingLogger::default())
|
.wrap(TracingLogger::default())
|
||||||
.app_data(web::Data::new(client.clone()))
|
.app_data(web::Data::new(client.clone()))
|
||||||
|
@ -390,10 +443,44 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
.route("/image/{path}", web::get().to(image))
|
.route("/image/{path}", web::get().to(image))
|
||||||
.route("/purge/{path}", web::get().to(purge))
|
.route("/purge/{path}", web::get().to(purge))
|
||||||
.route("/static/{path}", web::get().to(serve_static))
|
.route("/static/{path}", web::get().to(serve_static))
|
||||||
})
|
});
|
||||||
.bind(bind_address)?
|
|
||||||
.run()
|
if let Some((cert, key)) = server_certificate.zip(server_private_key) {
|
||||||
.await?;
|
let certified_key = open_keys(&cert, &key).await?;
|
||||||
|
|
||||||
|
let (tx, rx) = rustls_channel_resolver::channel::<32>(certified_key);
|
||||||
|
|
||||||
|
let handle = actix_web::rt::spawn(async move {
|
||||||
|
let mut interval = actix_web::rt::time::interval(Duration::from_secs(30));
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
match open_keys(&cert, &key).await {
|
||||||
|
Ok(certified_key) => tx.update(certified_key),
|
||||||
|
Err(e) => tracing::error!("Failed to read TLS keys {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let server_config = ServerConfig::builder()
|
||||||
|
.with_safe_defaults()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_cert_resolver(rx);
|
||||||
|
|
||||||
|
tracing::info!("Starting pict-rs-admin with TLS on {bind_address}");
|
||||||
|
server
|
||||||
|
.bind_rustls_021(bind_address, server_config)?
|
||||||
|
.run()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
handle.abort();
|
||||||
|
let _ = handle.await;
|
||||||
|
} else {
|
||||||
|
tracing::info!("Starting pict-rs-admin on {bind_address}");
|
||||||
|
server.bind(bind_address)?.run().await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue