11use std:: {
2- collections:: VecDeque ,
2+ collections:: { HashMap , VecDeque } ,
33 convert:: Infallible ,
44 sync:: { Arc , Mutex , PoisonError } ,
55 time:: Duration ,
@@ -29,6 +29,7 @@ use defguard_common::{
2929 types:: proxy:: ProxyControlMessage ,
3030 utils:: strip_scheme,
3131} ;
32+ use defguard_grpc_tls:: certs:: proxy_mtls_channel;
3233use defguard_proto:: {
3334 common:: { CertBundle , CertificateInfo } ,
3435 gateway:: gateway_setup_client:: GatewaySetupClient ,
@@ -43,7 +44,10 @@ use reqwest::Url;
4344use serde:: { Deserialize , Serialize } ;
4445use sqlx:: PgPool ;
4546use tokio:: {
46- sync:: mpsc:: { Sender , UnboundedReceiver , UnboundedSender , unbounded_channel} ,
47+ sync:: {
48+ mpsc:: { Sender , UnboundedReceiver , UnboundedSender , unbounded_channel} ,
49+ oneshot, watch,
50+ } ,
4751 time:: { Instant , sleep_until, timeout} ,
4852} ;
4953use tokio_stream:: StreamExt ;
@@ -1175,8 +1179,7 @@ fn public_proxy_hostname() -> Result<String, String> {
11751179/// collected during the ACME run (sent by the proxy via an [`AcmeLogs`] event).
11761180async fn call_proxy_trigger_acme (
11771181 pool : & PgPool ,
1178- proxy_host : & str ,
1179- proxy_port : u16 ,
1182+ proxy : & Proxy < Id > ,
11801183 domain : String ,
11811184 account_credentials_json : String ,
11821185 progress_tx : UnboundedSender < AcmeStep > ,
@@ -1191,32 +1194,29 @@ async fn call_proxy_trigger_acme(
11911194 )
11921195 } ) ?;
11931196
1194- let cert_pem = der_to_pem ( & ca_cert_der, defguard_certs:: PemLabel :: Certificate )
1195- . map_err ( |e| ( format ! ( "Failed to convert CA cert to PEM: {e}" ) , Vec :: new ( ) ) ) ?;
1196-
1197- let endpoint_str = format ! ( "https://{proxy_host}:{proxy_port}" ) ;
1198- let endpoint = Endpoint :: from_shared ( endpoint_str)
1199- . map_err ( |e| ( format ! ( "Failed to build Edge endpoint: {e}" ) , Vec :: new ( ) ) ) ?
1200- . http2_keep_alive_interval ( Duration :: from_secs ( 5 ) )
1201- . tcp_keepalive ( Some ( Duration :: from_secs ( 5 ) ) )
1202- . keep_alive_while_idle ( true ) ;
1203-
1204- let tls = ClientTlsConfig :: new ( ) . ca_certificate ( Certificate :: from_pem ( cert_pem) ) ;
1205- let endpoint = endpoint. tls_config ( tls) . map_err ( |e| {
1197+ let cert_serial = proxy. certificate_serial . as_deref ( ) . ok_or_else ( || {
12061198 (
1207- format ! ( "Failed to configure TLS for Edge endpoint: {e}" ) ,
1199+ "Edge certificate serial not provisioned" . to_string ( ) ,
12081200 Vec :: new ( ) ,
12091201 )
12101202 } ) ?;
12111203
1204+ // Seed a one-shot serial map so the rustls verifier validates the server cert serial.
1205+ let ( _, certs_rx) = watch:: channel ( Arc :: new ( HashMap :: from ( [ (
1206+ proxy. id ,
1207+ cert_serial. to_string ( ) ,
1208+ ) ] ) ) ) ;
1209+
1210+ let channel = proxy_mtls_channel ( proxy, & ca_cert_der, certs_rx)
1211+ . map_err ( |e| ( format ! ( "Failed to build mTLS channel: {e}" ) , Vec :: new ( ) ) ) ?;
1212+
12121213 let version = Version :: parse ( VERSION )
12131214 . map_err ( |e| ( format ! ( "Failed to parse core version: {e}" ) , Vec :: new ( ) ) ) ?;
12141215 let version_interceptor = ClientVersionInterceptor :: new ( version) ;
12151216
1216- let mut client =
1217- ProxyClient :: with_interceptor ( endpoint. connect_lazy ( ) , move |req : Request < ( ) > | {
1218- version_interceptor. clone ( ) . call ( req)
1219- } ) ;
1217+ let mut client = ProxyClient :: with_interceptor ( channel, move |req : Request < ( ) > | {
1218+ version_interceptor. clone ( ) . call ( req)
1219+ } ) ;
12201220
12211221 let mut stream = client
12221222 . trigger_acme ( AcmeChallenge {
@@ -1300,7 +1300,7 @@ pub async fn stream_proxy_acme(
13001300
13011301 let account_credentials_json = certs. acme_account_credentials. clone( ) . unwrap_or_default( ) ;
13021302
1303- let proxies = match Proxy :: list ( & pool) . await {
1303+ let proxies = match Proxy :: all_enabled ( & pool) . await {
13041304 Ok ( list) => list,
13051305 Err ( e) => {
13061306 yield Ok ( acme_error_event(
@@ -1323,8 +1323,8 @@ pub async fn stream_proxy_acme(
13231323 return ;
13241324 } ;
13251325
1326- let proxy_host = proxy. address. clone ( ) ;
1327- let proxy_port = proxy. port as u16 ;
1326+ let proxy_host = & proxy. address;
1327+ let proxy_port = proxy. port;
13281328 info!(
13291329 "Triggering ACME HTTP-01 via Edge gRPC TriggerAcme for domain: {domain} \
13301330 Edge={proxy_host}:{proxy_port}"
@@ -1333,16 +1333,15 @@ pub async fn stream_proxy_acme(
13331333 let ( progress_tx, mut progress_rx) =
13341334 unbounded_channel:: <AcmeStep >( ) ;
13351335 let ( result_tx, result_rx) =
1336- tokio :: sync :: oneshot:: channel:: <Result <( String , String , String ) , ( String , Vec <String >) >>( ) ;
1336+ oneshot:: channel:: <Result <( String , String , String ) , ( String , Vec <String >) >>( ) ;
13371337
13381338 let pool_clone = pool. clone( ) ;
13391339 let domain_clone = domain. clone( ) ;
13401340 let acct_creds_clone = account_credentials_json. clone( ) ;
13411341 tokio:: spawn( async move {
13421342 let result = call_proxy_trigger_acme(
13431343 & pool_clone,
1344- & proxy_host,
1345- proxy_port,
1344+ & proxy,
13461345 domain_clone,
13471346 acct_creds_clone,
13481347 progress_tx,
0 commit comments