Skip to content

Instantly share code, notes, and snippets.

@phongphan
Last active April 9, 2023 14:47
Show Gist options
  • Save phongphan/ec2d4c3cb2e75cd01367e58633c77bb6 to your computer and use it in GitHub Desktop.
Save phongphan/ec2d4c3cb2e75cd01367e58633c77bb6 to your computer and use it in GitHub Desktop.
axum mTLS using openssl
use axum::{extract::ConnectInfo, response::Html, routing::get, Router};
use axum_server::tls_openssl::OpenSSLConfig;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslVerifyMode};
use openssl::x509::{
store::{X509Store, X509StoreBuilder},
X509,
};
use std::{net::SocketAddr, path::PathBuf};
#[tokio::main]
async fn main() {
// openssl
let mut tls_builder = SslAcceptor::mozilla_modern_v5(SslMethod::tls()).unwrap();
tls_builder
.set_certificate_file(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("certs")
.join("server_cert.crt"),
SslFiletype::PEM,
)
.unwrap();
tls_builder
.set_private_key_file(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("certs")
.join("server_pk.key"),
SslFiletype::PEM,
)
.unwrap();
tls_builder.check_private_key().unwrap();
// client verifier
// set options to make sure to validate the peer aka mtls
let trusted_client_cert_bytes = std::fs::read(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("certs")
.join("client_cert.crt"),
)
.unwrap();
let trusted_client_cert = X509::from_pem(&trusted_client_cert_bytes).unwrap();
let mut builder = X509StoreBuilder::new().unwrap();
let _ = builder.add_cert(trusted_client_cert);
let store: X509Store = builder.build();
let mut verify_mode = SslVerifyMode::empty();
verify_mode.set(SslVerifyMode::PEER, true);
verify_mode.set(SslVerifyMode::FAIL_IF_NO_PEER_CERT, true);
tls_builder.set_verify_cert_store(store).unwrap();
tls_builder.set_verify(verify_mode);
// openssl
let app = Router::new().route("/", get(handler));
let cfg = OpenSSLConfig::try_from(tls_builder).unwrap();
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("listening on {}", addr);
axum_server::bind_openssl(addr, cfg)
.serve(app.into_make_service_with_connect_info::<SocketAddr>())
.await
.unwrap();
}
async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> Html<String> {
Html(format!("<h1>Hello, world! {}", addr.to_string()))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment