rustfs_tls_runtime/
lib.rs1pub mod certs;
16pub mod config;
17pub mod coordinator;
18pub mod debug;
19pub mod error;
20pub mod fingerprint;
21pub mod material;
22pub mod metrics;
23pub mod outbound;
24pub mod server;
25pub mod source;
26pub mod state;
27
28pub use certs::{
29 CertDirectoryLoadOptions, TlsCertPairInspection, TlsCertPairStatus, TlsDirectoryInspection, TlsDomainInspection,
30 WebPkiClientVerifierOptions, build_webpki_client_verifier, create_multi_cert_resolver, inspect_cert_directory,
31 load_all_certs_from_directory, load_cert_bundle_der_bytes, load_certs, load_private_key,
32};
33pub use config::{ReloadApplyHint, ReloadDetectMode, TlsReloadOptions};
34pub use coordinator::{TlsConsumer, TlsReloadCoordinator};
35pub use debug::{TlsConsumerStatusItem, TlsDebugStatusResponse, TlsDebugStatusResponseBuilder};
36pub use error::TlsRuntimeError;
37pub use fingerprint::TlsFingerprint;
38pub use material::{OutboundTlsMaterial, ServerTlsMaterial, TlsMaterialSnapshot};
39pub use metrics::{
40 TLS_OUTBOUND_GLOBAL_CONSUMER, TLS_RUNTIME_FOUNDATION_CONSUMER, init_tls_metrics, record_tls_consumer_stale_generation,
41 record_tls_generation, record_tls_publication_fail, record_tls_reload_result, record_tls_reload_skipped,
42};
43pub use outbound::{
44 GlobalOutboundTlsStateSummary, GlobalPublishedOutboundTlsState, load_global_outbound_tls_generation,
45 load_global_outbound_tls_state, publish_global_outbound_tls_state, summarize_global_outbound_tls_state,
46};
47pub use server::{ReloadableServerCertResolver, spawn_server_cert_reload_loop};
48pub use source::{TlsFileLayout, TlsSource, TlsSourceKind};
49pub use state::OutboundOnlySnapshotArgs;
50pub use state::{TlsGeneration, TlsPublishedState, TlsReloadRuntimeState, TlsRuntimeStatusSnapshot};
51pub use state::{TlsRuntimeConsumerSection, TlsRuntimeOutboundSection, TlsRuntimeRuntimeSection, TlsRuntimeServerSection};
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use rcgen::generate_simple_self_signed;
57 use std::collections::HashMap;
58
59 #[test]
60 fn tls_source_requires_existing_directory() {
61 let source = TlsSource::from_directory("/definitely/missing/rustfs/tls-runtime-test");
62 let err = source.validate_directory().expect_err("missing directory should fail");
63 assert!(matches!(err, TlsRuntimeError::DirectoryNotFound { .. }));
64 }
65
66 #[test]
67 fn fingerprint_changes_when_server_material_changes() {
68 let cert_a = generate_simple_self_signed(vec!["a.example.com".to_string()]).expect("cert A should generate");
69 let cert_b = generate_simple_self_signed(vec!["b.example.com".to_string()]).expect("cert B should generate");
70
71 let single_a = ServerTlsMaterial::SingleCert {
72 certs: vec![cert_a.cert.der().clone()],
73 key: rustls::pki_types::PrivateKeyDer::try_from(cert_a.signing_key.serialize_der()).expect("key A should convert"),
74 };
75 let single_b = ServerTlsMaterial::SingleCert {
76 certs: vec![cert_b.cert.der().clone()],
77 key: rustls::pki_types::PrivateKeyDer::try_from(cert_b.signing_key.serialize_der()).expect("key B should convert"),
78 };
79
80 let bytes_a = match &single_a {
81 ServerTlsMaterial::SingleCert { certs, key } => {
82 let mut bytes = Vec::new();
83 for cert in certs {
84 bytes.extend_from_slice(cert.as_ref());
85 }
86 bytes.extend_from_slice(key.secret_der());
87 bytes
88 }
89 ServerTlsMaterial::MultiCert { .. } => unreachable!(),
90 };
91 let bytes_b = match &single_b {
92 ServerTlsMaterial::SingleCert { certs, key } => {
93 let mut bytes = Vec::new();
94 for cert in certs {
95 bytes.extend_from_slice(cert.as_ref());
96 }
97 bytes.extend_from_slice(key.secret_der());
98 bytes
99 }
100 ServerTlsMaterial::MultiCert { .. } => unreachable!(),
101 };
102
103 let fp_a = TlsFingerprint::from_optional_bytes(Some(&bytes_a), None, None, None, None);
104 let fp_b = TlsFingerprint::from_optional_bytes(Some(&bytes_b), None, None, None, None);
105 assert_ne!(fp_a, fp_b);
106 }
107
108 #[tokio::test]
109 async fn coordinator_can_publish_initial_state() {
110 let source = TlsSource::from_directory(std::env::temp_dir());
111 let coordinator = TlsReloadCoordinator::new(source.clone(), TlsReloadOptions::default());
112 let snapshot = TlsMaterialSnapshot {
113 source,
114 server: Some(ServerTlsMaterial::MultiCert {
115 cert_key_pairs: HashMap::new(),
116 }),
117 outbound: OutboundTlsMaterial {
118 root_ca_pem: Vec::new(),
119 mtls_identity: None,
120 },
121 fingerprint: TlsFingerprint::default(),
122 };
123
124 let published = coordinator.publish_initial_state(snapshot).await;
125 assert_eq!(published.generation, TlsGeneration(1));
126 }
127}