temporarily implemented client authentication using client certificates (mTLS)
This commit is contained in:
parent
8f7f9d4257
commit
d7193af4e6
21 changed files with 326 additions and 40 deletions
|
|
@ -1,5 +1,14 @@
|
|||
use super::proxy_main::{LocalExecutor, Proxy};
|
||||
use crate::{constants::*, error::*, log::*, utils::BytesName};
|
||||
use super::{
|
||||
proxy_client_cert::check_client_authentication,
|
||||
proxy_main::{LocalExecutor, Proxy},
|
||||
};
|
||||
use crate::{
|
||||
backend::{ServerCrypto, SniKeyIdsMap},
|
||||
constants::*,
|
||||
error::*,
|
||||
log::*,
|
||||
utils::BytesName,
|
||||
};
|
||||
use hyper::{client::connect::Connect, server::conn::Http};
|
||||
use rustls::ServerConfig;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -19,7 +28,7 @@ impl<T> Proxy<T>
|
|||
where
|
||||
T: Connect + Clone + Sync + Send + 'static,
|
||||
{
|
||||
async fn cert_service(&self, server_crypto_tx: watch::Sender<Option<Arc<ServerConfig>>>) {
|
||||
async fn cert_service(&self, server_crypto_tx: watch::Sender<Option<Arc<ServerCrypto>>>) {
|
||||
info!("Start cert watch service");
|
||||
loop {
|
||||
if let Ok(server_crypto) = self.globals.backends.generate_server_crypto_with_cert_resolver().await {
|
||||
|
|
@ -38,21 +47,23 @@ where
|
|||
async fn listener_service(
|
||||
&self,
|
||||
server: Http<LocalExecutor>,
|
||||
mut server_crypto_rx: watch::Receiver<Option<Arc<ServerConfig>>>,
|
||||
mut server_crypto_rx: watch::Receiver<Option<Arc<ServerCrypto>>>,
|
||||
) -> Result<()> {
|
||||
let tcp_listener = TcpListener::bind(&self.listening_on).await?;
|
||||
info!("Start TCP proxy serving with HTTPS request for configured host names");
|
||||
|
||||
// let mut server_crypto: Option<Arc<ServerConfig>> = None;
|
||||
let mut tls_acceptor: Option<TlsAcceptor> = None;
|
||||
let mut sni_client_ca_keyid_map: Option<Arc<SniKeyIdsMap>> = None;
|
||||
loop {
|
||||
tokio::select! {
|
||||
tcp_cnx = tcp_listener.accept() => {
|
||||
if tls_acceptor.is_none() || tcp_cnx.is_err() {
|
||||
if tls_acceptor.is_none() || tcp_cnx.is_err() || sni_client_ca_keyid_map.is_none() {
|
||||
continue;
|
||||
}
|
||||
let (raw_stream, client_addr) = tcp_cnx.unwrap();
|
||||
let acceptor = tls_acceptor.clone().unwrap();
|
||||
let sni_cc_map = sni_client_ca_keyid_map.clone().unwrap();
|
||||
let server_clone = server.clone();
|
||||
let self_inner = self.clone();
|
||||
|
||||
|
|
@ -70,6 +81,13 @@ where
|
|||
if server_name.is_none(){
|
||||
Err(RpxyError::Proxy("No SNI is given".to_string()))
|
||||
} else {
|
||||
//////////////////////////////
|
||||
// Check client certificate
|
||||
// TODO: consider move this function to the layer of handle_request (L7) to return 403
|
||||
let client_certs = conn.peer_certificates();
|
||||
let client_certs_setting_for_sni = sni_cc_map.get(&server_name.clone().unwrap());
|
||||
check_client_authentication(client_certs, client_certs_setting_for_sni)?;
|
||||
//////////////////////////////
|
||||
// this immediately spawns another future to actually handle stream. so it is okay to introduce timeout for handshake.
|
||||
self_inner.client_serve(stream, server_clone, client_addr, server_name); // TODO: don't want to pass copied value...
|
||||
Ok(())
|
||||
|
|
@ -95,7 +113,8 @@ where
|
|||
break;
|
||||
}
|
||||
let server_crypto = server_crypto_rx.borrow().clone().unwrap();
|
||||
tls_acceptor = Some(TlsAcceptor::from(server_crypto));
|
||||
tls_acceptor = Some(TlsAcceptor::from(server_crypto.inner.clone()));
|
||||
sni_client_ca_keyid_map = Some(server_crypto.server_name_client_ca_keyids_map.clone());
|
||||
}
|
||||
else => break
|
||||
}
|
||||
|
|
@ -104,10 +123,10 @@ where
|
|||
}
|
||||
|
||||
#[cfg(feature = "http3")]
|
||||
async fn listener_service_h3(&self, mut server_crypto_rx: watch::Receiver<Option<Arc<ServerConfig>>>) -> Result<()> {
|
||||
async fn listener_service_h3(&self, mut server_crypto_rx: watch::Receiver<Option<Arc<ServerCrypto>>>) -> Result<()> {
|
||||
info!("Start UDP proxy serving with HTTP/3 request for configured host names");
|
||||
// first set as null config server
|
||||
let server_crypto = ServerConfig::builder()
|
||||
let rustls_server_config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_cert_resolver(Arc::new(tokio_rustls::rustls::server::ResolvesServerCertUsingSni::new()));
|
||||
|
|
@ -117,16 +136,17 @@ where
|
|||
.max_concurrent_bidi_streams(self.globals.h3_max_concurrent_bidistream)
|
||||
.max_concurrent_uni_streams(self.globals.h3_max_concurrent_unistream);
|
||||
|
||||
let mut server_config_h3 = QuicServerConfig::with_crypto(Arc::new(server_crypto));
|
||||
let mut server_config_h3 = QuicServerConfig::with_crypto(Arc::new(rustls_server_config));
|
||||
server_config_h3.transport = Arc::new(transport_config_quic);
|
||||
server_config_h3.concurrent_connections(self.globals.h3_max_concurrent_connections);
|
||||
let (endpoint, mut incoming) = Endpoint::server(server_config_h3, self.listening_on)?;
|
||||
|
||||
let mut server_crypto: Option<Arc<ServerConfig>> = None;
|
||||
let mut server_crypto: Option<Arc<ServerCrypto>> = None;
|
||||
let mut sni_client_ca_keyid_map: Option<Arc<SniKeyIdsMap>> = None;
|
||||
loop {
|
||||
tokio::select! {
|
||||
new_conn = incoming.next() => {
|
||||
if server_crypto.is_none() || new_conn.is_none() {
|
||||
if server_crypto.is_none() || new_conn.is_none() || sni_client_ca_keyid_map.is_none() {
|
||||
continue;
|
||||
}
|
||||
let mut conn = new_conn.unwrap();
|
||||
|
|
@ -152,7 +172,7 @@ where
|
|||
);
|
||||
// TODO: server_nameをここで出してどんどん深く投げていくのは効率が悪い。connecting -> connectionsの後でいいのでは?
|
||||
// TODO: 通常のTLSと同じenumか何かにまとめたい
|
||||
let fut = self.clone().connection_serve_h3(conn, new_server_name);
|
||||
let fut = self.clone().connection_serve_h3(conn, new_server_name, sni_client_ca_keyid_map.clone().unwrap());
|
||||
self.globals.runtime_handle.spawn(async move {
|
||||
// Timeout is based on underlying quic
|
||||
if let Err(e) = fut.await {
|
||||
|
|
@ -166,7 +186,8 @@ where
|
|||
}
|
||||
server_crypto = server_crypto_rx.borrow().clone();
|
||||
if server_crypto.is_some(){
|
||||
endpoint.set_server_config(Some(QuicServerConfig::with_crypto(server_crypto.clone().unwrap())));
|
||||
endpoint.set_server_config(Some(QuicServerConfig::with_crypto(server_crypto.clone().unwrap().inner.clone())));
|
||||
sni_client_ca_keyid_map = Some(server_crypto.clone().unwrap().server_name_client_ca_keyids_map.clone());
|
||||
}
|
||||
}
|
||||
else => break
|
||||
|
|
@ -177,7 +198,7 @@ where
|
|||
}
|
||||
|
||||
pub async fn start_with_tls(self, server: Http<LocalExecutor>) -> Result<()> {
|
||||
let (tx, rx) = watch::channel::<Option<Arc<ServerConfig>>>(None);
|
||||
let (tx, rx) = watch::channel::<Option<Arc<ServerCrypto>>>(None);
|
||||
#[cfg(not(feature = "http3"))]
|
||||
{
|
||||
select! {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue