(
settings: &ClusterSettings,
tls_dir: &Path,
)
| 311 | } |
| 312 | |
| 313 | fn bootstrap_credentials( |
| 314 | settings: &ClusterSettings, |
| 315 | tls_dir: &Path, |
| 316 | ) -> crate::Result<TlsCredentials> { |
| 317 | fs::create_dir_all(tls_dir).map_err(|e| crate::Error::Config { |
| 318 | detail: format!("create tls dir {}: {e}", tls_dir.display()), |
| 319 | })?; |
| 320 | |
| 321 | // Multi-SAN cert: one cert satisfies both the fixed cluster SNI |
| 322 | // (`"nodedb"`, required by the QUIC client config) AND the |
| 323 | // per-node identity (`node-<id>`), so future CRL-based revocation |
| 324 | // can target a specific node without tearing down the fleet. |
| 325 | let node_san = format!("node-{}", settings.node_id); |
| 326 | let (ca, creds) = nodedb_cluster::generate_node_credentials_multi_san(&[ |
| 327 | &node_san, |
| 328 | nodedb_cluster::transport::config::SNI_HOSTNAME, |
| 329 | ]) |
| 330 | .map_err(|e| crate::Error::Config { |
| 331 | detail: format!("bootstrap cluster CA: {e}"), |
| 332 | })?; |
| 333 | |
| 334 | write_pem_cert(&tls_dir.join(CA_CERT_FILE), ca.cert_der().as_ref())?; |
| 335 | // Persist the CA key so `nodedb regen-certs` can reissue node |
| 336 | // certs under the same CA. 0600 perms enforced by |
| 337 | // `write_pem_private_key`. |
| 338 | write_pem_private_key(&tls_dir.join(CA_KEY_FILE), &ca.key_pair_pkcs8_der())?; |
| 339 | write_pem_cert(&tls_dir.join(NODE_CERT_FILE), creds.cert.as_ref())?; |
| 340 | write_pem_private_key(&tls_dir.join(NODE_KEY_FILE), creds.key.secret_der())?; |
| 341 | write_cluster_secret(&tls_dir.join(CLUSTER_SECRET_FILE), &creds.cluster_secret)?; |
| 342 | |
| 343 | // Load the (empty-by-default) overlap-CA set so the bootstrap path |
| 344 | // behaves the same as a reload — any `ca.d/` pre-seeded by the |
| 345 | // operator is honoured on first start. |
| 346 | let mut creds = creds; |
| 347 | creds.additional_ca_certs = load_extra_cas(tls_dir)?; |
| 348 | Ok(creds) |
| 349 | } |
| 350 | |
| 351 | fn read_cluster_secret(path: &Path) -> crate::Result<[u8; CLUSTER_SECRET_LEN]> { |
| 352 | ensure_secret_file_perms(path)?; |
no test coverage detected