@@ -271,6 +271,84 @@ impl PolicyServer {
271
271
}
272
272
}
273
273
274
+ // Load the ServerConfig to be used by the Policy Server configuring the server
275
+ // certificate and mTLS when necessary
276
+ //
277
+ // RustlsConfig does not offer a function to load the client CA certificate together with the
278
+ // service certificates. Therefore, we need to load everything and build the ServerConfig
279
+ async fn build_tls_server_config ( tls_config : & TlsConfig ) -> Result < rustls:: ServerConfig > {
280
+ use std:: { fs:: File , io:: BufReader } ;
281
+
282
+ use rustls:: { server:: WebPkiClientVerifier , RootCertStore , ServerConfig } ;
283
+ use rustls_pemfile:: Item ;
284
+ use rustls_pki_types:: { CertificateDer , PrivateKeyDer } ;
285
+
286
+ let cert_file = & mut BufReader :: new ( File :: open ( tls_config. cert_file . clone ( ) ) ?) ;
287
+ let key_file = & mut BufReader :: new ( File :: open ( tls_config. key_file . clone ( ) ) ?) ;
288
+ let cert: Vec < CertificateDer > = rustls_pemfile:: certs ( cert_file)
289
+ . filter_map ( |it| {
290
+ if let Err ( ref e) = it {
291
+ warn ! ( "Cannot parse certificate: {e}" ) ;
292
+ return None ;
293
+ }
294
+ it. ok ( )
295
+ } )
296
+ . collect ( ) ;
297
+ if cert. len ( ) > 1 {
298
+ return Err ( anyhow ! ( "Multiple certificates provided in cert file" ) ) ;
299
+ }
300
+ let mut key_vec: Vec < Vec < u8 > > = rustls_pemfile:: read_all ( key_file)
301
+ . filter_map ( |i| match i. ok ( ) ? {
302
+ Item :: Sec1Key ( key) => Some ( key. secret_sec1_der ( ) . to_vec ( ) ) ,
303
+ Item :: Pkcs1Key ( key) => Some ( key. secret_pkcs1_der ( ) . to_vec ( ) ) ,
304
+ Item :: Pkcs8Key ( key) => Some ( key. secret_pkcs8_der ( ) . to_vec ( ) ) ,
305
+ _ => {
306
+ info ! ( "Ignoring non-key item in key file" ) ;
307
+ None
308
+ }
309
+ } )
310
+ . collect ( ) ;
311
+ if key_vec. is_empty ( ) {
312
+ return Err ( anyhow ! ( "No key provided in key file" ) ) ;
313
+ }
314
+ if key_vec. len ( ) > 1 {
315
+ return Err ( anyhow ! ( "Multiple keys provided in key file" ) ) ;
316
+ }
317
+ let key = PrivateKeyDer :: try_from ( key_vec. pop ( ) . unwrap ( ) )
318
+ . map_err ( |e| anyhow ! ( "Cannot parse server key: {e}" ) ) ?;
319
+
320
+ let config = if let Some ( client_ca_cert_file_path) = tls_config. client_ca_cert_file . clone ( ) {
321
+ // we have the client CA. Therefore, we should enable mTLS.
322
+ let client_ca_cert_file = & mut BufReader :: new ( File :: open ( client_ca_cert_file_path) ?) ;
323
+
324
+ let mut ca_certs = RootCertStore :: empty ( ) ;
325
+ let client_ca_certs: Vec < _ > = rustls_pemfile:: certs ( client_ca_cert_file)
326
+ . filter_map ( |it| {
327
+ if let Err ( ref e) = it {
328
+ warn ! ( "Cannot parse client CA certificate: {e}" ) ;
329
+ }
330
+ it. ok ( )
331
+ } )
332
+ . collect ( ) ;
333
+ let ( cert_added, cert_ignored) = ca_certs. add_parsable_certificates ( client_ca_certs) ;
334
+ info ! (
335
+ client_ca_certs_added = cert_added,
336
+ client_ca_certs_ignored = cert_ignored,
337
+ "Loaded client CA certificates"
338
+ ) ;
339
+ let client_verifier = WebPkiClientVerifier :: builder ( Arc :: new ( ca_certs) ) . build ( ) ?;
340
+
341
+ ServerConfig :: builder ( )
342
+ . with_client_cert_verifier ( client_verifier)
343
+ . with_single_cert ( cert, key) ?
344
+ } else {
345
+ ServerConfig :: builder ( )
346
+ . with_no_client_auth ( )
347
+ . with_single_cert ( cert, key) ?
348
+ } ;
349
+ Ok ( config)
350
+ }
351
+
274
352
/// There's no watching of the certificate files on non-linux platforms
275
353
/// since we rely on inotify to watch for changes
276
354
#[ cfg( not( target_os = "linux" ) ) ]
@@ -293,24 +371,36 @@ async fn create_tls_config_and_watch_certificate_changes(
293
371
) -> Result < RustlsConfig > {
294
372
use :: tracing:: error;
295
373
296
- let cert_file = tls_config. cert_file . clone ( ) ;
297
- let key_file = tls_config. key_file . clone ( ) ;
374
+ let cert_file_path = tls_config. cert_file . clone ( ) ;
375
+ let key_file_path = tls_config. key_file . clone ( ) ;
376
+ let client_ca_cert_path = tls_config. client_ca_cert_file . clone ( ) ;
377
+
378
+ let config = build_tls_server_config ( & tls_config) . await ?;
298
379
299
- let rust_config =
300
- RustlsConfig :: from_pem_file ( tls_config. cert_file , tls_config. key_file ) . await ?;
380
+ let rust_config = RustlsConfig :: from_config ( Arc :: new ( config) ) ;
301
381
let reloadable_rust_config = rust_config. clone ( ) ;
302
382
303
383
let inotify =
304
384
inotify:: Inotify :: init ( ) . map_err ( |e| anyhow ! ( "Cannot initialize inotify: {e}" ) ) ?;
305
385
let cert_watch = inotify
306
386
. watches ( )
307
- . add ( cert_file . clone ( ) , inotify:: WatchMask :: CLOSE_WRITE )
387
+ . add ( cert_file_path . clone ( ) , inotify:: WatchMask :: CLOSE_WRITE )
308
388
. map_err ( |e| anyhow ! ( "Cannot watch certificate file: {e}" ) ) ?;
309
389
let key_watch = inotify
310
390
. watches ( )
311
- . add ( key_file . clone ( ) , inotify:: WatchMask :: CLOSE_WRITE )
391
+ . add ( key_file_path . clone ( ) , inotify:: WatchMask :: CLOSE_WRITE )
312
392
. map_err ( |e| anyhow ! ( "Cannot watch key file: {e}" ) ) ?;
313
393
394
+ let mut client_cert_watch = None ;
395
+ if let Some ( ref client_cert_file) = client_ca_cert_path {
396
+ client_cert_watch = Some (
397
+ inotify
398
+ . watches ( )
399
+ . add ( client_cert_file. clone ( ) , inotify:: WatchMask :: CLOSE_WRITE )
400
+ . map_err ( |e| anyhow ! ( "Cannot watch client certificate file: {e}" ) ) ?,
401
+ ) ;
402
+ }
403
+
314
404
let buffer = [ 0 ; 1024 ] ;
315
405
let stream = inotify
316
406
. into_event_stream ( buffer)
@@ -320,6 +410,7 @@ async fn create_tls_config_and_watch_certificate_changes(
320
410
tokio:: pin!( stream) ;
321
411
let mut cert_changed = false ;
322
412
let mut key_changed = false ;
413
+ let mut client_cert_changed = false ;
323
414
324
415
while let Some ( event) = stream. next ( ) . await {
325
416
let event = match event {
@@ -338,18 +429,29 @@ async fn create_tls_config_and_watch_certificate_changes(
338
429
info ! ( "TLS key file has been modified" ) ;
339
430
key_changed = true ;
340
431
}
432
+ if let Some ( ref client_cert_watch) = client_cert_watch {
433
+ if event. wd == * client_cert_watch {
434
+ info ! ( "TLS client certificate file has been modified" ) ;
435
+ client_cert_changed = true ;
436
+ }
437
+ }
341
438
342
- if key_changed && cert_changed {
343
- info ! ( "reloading TLS certificate" ) ;
439
+ // if both the certificate and the key have been changed or there is no change in the
440
+ // server cert and key, but the client cert changed, reload the certificate
441
+ if ( key_changed && cert_changed)
442
+ || ( client_cert_changed && ( key_changed == cert_changed) )
443
+ {
444
+ info ! ( "reloading TLS certificates" ) ;
344
445
345
446
cert_changed = false ;
346
447
key_changed = false ;
347
- if let Err ( e) = reloadable_rust_config
348
- . reload_from_pem_file ( cert_file. clone ( ) , key_file. clone ( ) )
349
- . await
350
- {
448
+ client_cert_changed = false ;
449
+ let server_config = build_tls_server_config ( & tls_config) . await ;
450
+ if let Err ( e) = server_config {
351
451
error ! ( "Failed to reload TLS certificate: {}" , e) ;
452
+ continue ;
352
453
}
454
+ reloadable_rust_config. reload_from_config ( Arc :: new ( server_config. unwrap ( ) ) )
353
455
}
354
456
}
355
457
} ) ;
0 commit comments