11use std:: {
22 net:: SocketAddr ,
3+ path:: { Path , PathBuf } ,
34 sync:: {
45 Arc , Mutex ,
56 atomic:: { AtomicBool , Ordering } ,
@@ -12,7 +13,11 @@ use defguard_version::{
1213 server:: { DefguardVersionLayer , grpc:: DefguardVersionInterceptor } ,
1314} ;
1415use rustls_pki_types:: { CertificateDer , UnixTime } ;
15- use tokio:: sync:: { mpsc, oneshot} ;
16+ use tokio:: {
17+ fs:: OpenOptions ,
18+ io:: AsyncWriteExt ,
19+ sync:: { mpsc, oneshot} ,
20+ } ;
1621use tokio_stream:: wrappers:: UnboundedReceiverStream ;
1722use tonic:: { Request , Response , Status , service:: InterceptorLayer , transport:: Server } ;
1823use webpki:: { KeyUsage , anchor_from_trusted_cert} ;
@@ -27,6 +32,11 @@ use crate::{
2732
2833const AUTH_HEADER : & str = "authorization" ;
2934
35+ pub const GRPC_CERT_NAME : & str = "proxy_grpc_cert.pem" ;
36+ pub const GRPC_KEY_NAME : & str = "proxy_grpc_key.pem" ;
37+ pub const GRPC_CA_CERT_NAME : & str = "grpc_ca_cert.pem" ;
38+ pub const CORE_CLIENT_CERT_NAME : & str = "core_client_cert.pem" ;
39+
3040/// Verify that both `component_der` and `core_client_der` are signed by `ca_der`.
3141///
3242/// Uses ECDSA P-256 via `aws-lc-rs` (Linux-only deployment; FIPS-capable).
@@ -88,13 +98,104 @@ fn validate_cert_bundle(
8898 Ok ( ( ) )
8999}
90100
101+ async fn save_tls_certs ( tls_config : & TlsConfig , cert_dir : & Path ) -> Result < ( ) , String > {
102+ let cert_path = cert_dir. join ( GRPC_CERT_NAME ) ;
103+ let key_path = cert_dir. join ( GRPC_KEY_NAME ) ;
104+ let ca_cert_path = cert_dir. join ( GRPC_CA_CERT_NAME ) ;
105+ let client_cert_path = cert_dir. join ( CORE_CLIENT_CERT_NAME ) ;
106+
107+ let mut options = OpenOptions :: new ( ) ;
108+ options. write ( true ) . create ( true ) . truncate ( true ) ;
109+ #[ cfg( unix) ]
110+ options. mode ( 0o600 ) ; // rw-------
111+
112+ // PEM-encode the Core client certificate DER for serial pinning on restart.
113+ let core_client_cert_pem = defguard_certs:: der_to_pem (
114+ & tls_config. core_client_cert_der ,
115+ defguard_certs:: PemLabel :: Certificate ,
116+ )
117+ . map_err ( |err| format ! ( "Failed to PEM-encode Core client certificate: {err}" ) ) ?;
118+
119+ // Write component (server) certificate.
120+ options
121+ . clone ( )
122+ . open ( & cert_path)
123+ . await
124+ . map_err ( |err| {
125+ format ! (
126+ "Cannot open certificate file {}: {err}" ,
127+ cert_path. display( )
128+ )
129+ } ) ?
130+ . write_all ( tls_config. grpc_cert_pem . as_bytes ( ) )
131+ . await
132+ . map_err ( |err| {
133+ format ! (
134+ "Cannot write certificate file {}: {err}" ,
135+ cert_path. display( )
136+ )
137+ } ) ?;
138+
139+ // Write private key.
140+ options
141+ . clone ( )
142+ . open ( & key_path)
143+ . await
144+ . map_err ( |err| format ! ( "Cannot open key file {}: {err}" , key_path. display( ) ) ) ?
145+ . write_all ( tls_config. grpc_key_pem . as_bytes ( ) )
146+ . await
147+ . map_err ( |err| format ! ( "Cannot write key file {}: {err}" , key_path. display( ) ) ) ?;
148+
149+ // Write CA certificate.
150+ options
151+ . clone ( )
152+ . open ( & ca_cert_path)
153+ . await
154+ . map_err ( |err| {
155+ format ! (
156+ "Cannot open CA certificate file {}: {err}" ,
157+ ca_cert_path. display( )
158+ )
159+ } ) ?
160+ . write_all ( tls_config. grpc_ca_cert_pem . as_bytes ( ) )
161+ . await
162+ . map_err ( |err| {
163+ format ! (
164+ "Cannot write CA certificate file {}: {err}" ,
165+ ca_cert_path. display( )
166+ )
167+ } ) ?;
168+
169+ // Write Core client certificate (PEM) for serial pinning on restart.
170+ options
171+ . open ( & client_cert_path)
172+ . await
173+ . map_err ( |err| {
174+ format ! (
175+ "Cannot open Core client certificate file {}: {err}" ,
176+ client_cert_path. display( )
177+ )
178+ } ) ?
179+ . write_all ( core_client_cert_pem. as_bytes ( ) )
180+ . await
181+ . map_err ( |err| {
182+ format ! (
183+ "Cannot write Core client certificate file {}: {err}" ,
184+ client_cert_path. display( )
185+ )
186+ } ) ?;
187+
188+ Ok ( ( ) )
189+ }
190+
91191pub ( crate ) struct ProxySetupServer {
92192 key_pair : Arc < Mutex < Option < defguard_certs:: RcGenKeyPair > > > ,
93193 logs_rx : LogsReceiver ,
94194 current_session_token : Arc < Mutex < Option < String > > > ,
95195 setup_tx : Arc < tokio:: sync:: Mutex < Option < oneshot:: Sender < TlsConfig > > > > ,
96196 setup_rx : Arc < tokio:: sync:: Mutex < oneshot:: Receiver < TlsConfig > > > ,
97197 adoption_expired : Arc < AtomicBool > ,
198+ cert_dir : Arc < PathBuf > ,
98199}
99200
100201impl Clone for ProxySetupServer {
@@ -106,12 +207,13 @@ impl Clone for ProxySetupServer {
106207 setup_tx : Arc :: clone ( & self . setup_tx ) ,
107208 setup_rx : Arc :: clone ( & self . setup_rx ) ,
108209 adoption_expired : Arc :: clone ( & self . adoption_expired ) ,
210+ cert_dir : Arc :: clone ( & self . cert_dir ) ,
109211 }
110212 }
111213}
112214
113215impl ProxySetupServer {
114- pub fn new ( logs_rx : LogsReceiver ) -> Self {
216+ pub fn new ( logs_rx : LogsReceiver , cert_dir : PathBuf ) -> Self {
115217 let ( setup_tx, setup_rx) = oneshot:: channel ( ) ;
116218 Self {
117219 key_pair : Arc :: new ( Mutex :: new ( None ) ) ,
@@ -120,6 +222,7 @@ impl ProxySetupServer {
120222 setup_tx : Arc :: new ( tokio:: sync:: Mutex :: new ( Some ( setup_tx) ) ) ,
121223 setup_rx : Arc :: new ( tokio:: sync:: Mutex :: new ( setup_rx) ) ,
122224 adoption_expired : Arc :: new ( AtomicBool :: new ( false ) ) ,
225+ cert_dir : Arc :: new ( cert_dir) ,
123226 }
124227 }
125228
@@ -490,6 +593,16 @@ impl proxy_setup_server::ProxySetup for ProxySetupServer {
490593 core_client_cert_der : bundle. core_client_cert_der ,
491594 } ;
492595
596+ debug ! ( "Saving TLS certificate files to disk" ) ;
597+ if let Err ( err) = save_tls_certs ( & configuration, & self . cert_dir ) . await {
598+ error ! ( "Failed to save TLS certificates: {err}" ) ;
599+ self . clear_setup_session ( ) ;
600+ return Err ( Status :: internal ( format ! (
601+ "Failed to save TLS certificates: {err}"
602+ ) ) ) ;
603+ }
604+ debug ! ( "TLS certificate files saved successfully" ) ;
605+
493606 debug ! ( "Passing configuration to gRPC server for finalization" ) ;
494607 let Some ( sender) = self . setup_tx . lock ( ) . await . take ( ) else {
495608 error ! ( "Setup channel sender already consumed" ) ;
0 commit comments