- netboot-base.nix with SSH key auth - Launch scripts for node01/02/03 - Node configuration.nix and disko.nix - Nix modules for first-boot automation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
146 lines
6.4 KiB
Markdown
146 lines
6.4 KiB
Markdown
# Unified Configuration Guidelines
|
|
|
|
This document outlines the standardized approach for managing configuration across all components of the Cloud project. Adhering to these guidelines ensures consistency, maintainability, and ease of operation for all services.
|
|
|
|
## 1. Layered Configuration with `config-rs`
|
|
|
|
All components MUST use the `config-rs` crate for managing application settings. This allows for a robust, layered configuration system with clear precedence:
|
|
|
|
1. **Defaults:** Sensible, hard-coded default values provided by the application. These are the lowest precedence.
|
|
2. **Environment Variables:** Values loaded from environment variables. These override defaults.
|
|
3. **Configuration Files:** Values loaded from a TOML configuration file. These override environment variables and defaults.
|
|
4. **Command-Line Arguments:** Values provided via command-line arguments. These are the highest precedence and always override all other sources.
|
|
|
|
### Implementation Details:
|
|
|
|
* **`ServerConfig::default()` as base:** Use `toml::to_string(&MyServerConfig::default())` to provide the base default configuration to `config-rs`. This ensures `Default` implementations are the source of truth for base settings.
|
|
* **Workspace Dependency:** The `config` crate should be a `[workspace.dependencies]` entry in the component's `Cargo.toml`, and member crates should reference it with `config.workspace = true`.
|
|
|
|
## 2. Configuration File Format: TOML
|
|
|
|
All configuration files MUST be in the [TOML](https://toml.io/en/) format.
|
|
|
|
* `config-rs` should be configured to read TOML files (`config::FileFormat::Toml`).
|
|
* Configuration structs MUST derive `serde::Serialize` and `serde::Deserialize` to enable `config-rs` to populate them.
|
|
|
|
## 3. Command-Line Argument Overrides with `clap`
|
|
|
|
All components MUST use `clap::Parser` for parsing command-line arguments.
|
|
|
|
* Critical configuration parameters MUST be exposed as CLI arguments.
|
|
* CLI arguments are applied *after* `config-rs` has loaded all other configuration sources, ensuring they have the highest precedence. This typically involves manually setting fields in the deserialized configuration struct if `Option<T>` arguments are provided.
|
|
|
|
## 4. Consistent Environment Variable Prefixes
|
|
|
|
All components MUST use a consistent naming convention for environment variables.
|
|
|
|
* **Prefix Format:** `UPPERCASE_COMPONENT_NAME_` (e.g., `CHAINFIRE_`, `FLAREDB_`, `IAM_`).
|
|
* **Nested Fields:** Use double underscores (`__`) to represent nested fields in the configuration structure.
|
|
* Example: For `network.api_addr`, the environment variable would be `CHAINFIRE_NETWORK__API_ADDR`.
|
|
* **Case Conversion:** Configure `config-rs` to convert environment variable names to `snake_case` to match Rust struct field names (`.convert_case(config::Case::Snake)`).
|
|
|
|
## 5. Configuration Struct Guidelines
|
|
|
|
* **Top-Level `ServerConfig`:** Each executable component (e.g., `chainfire-server`, `flaredb-server`) should have a single top-level `ServerConfig` (or similar name) struct that encapsulates all its settings.
|
|
* **Modularity:** Break down `ServerConfig` into smaller, logical sub-structs (e.g., `NodeConfig`, `NetworkConfig`, `StorageConfig`, `ClusterConfig`) to improve readability and maintainability.
|
|
* **`Default` Implementation:** All configuration structs and their sub-structs MUST implement `Default` to provide sensible starting values.
|
|
* **Doc Comments:** Use clear doc comments for all configuration fields, explaining their purpose and acceptable values.
|
|
|
|
## 6. TLS/mTLS Configuration (Security)
|
|
|
|
All services MUST support optional TLS configuration for production deployments. The TLS configuration pattern ensures consistent security across all components.
|
|
|
|
### Standard TLS Configuration Structure
|
|
|
|
```rust
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// TLS configuration for gRPC servers
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct TlsConfig {
|
|
/// Path to server certificate file (PEM format)
|
|
pub cert_file: String,
|
|
|
|
/// Path to server private key file (PEM format)
|
|
pub key_file: String,
|
|
|
|
/// Path to CA certificate file for client verification (optional, enables mTLS)
|
|
pub ca_file: Option<String>,
|
|
|
|
/// Require client certificates (mTLS mode)
|
|
#[serde(default)]
|
|
pub require_client_cert: bool,
|
|
}
|
|
```
|
|
|
|
### Integration Pattern
|
|
|
|
Services should include `tls: Option<TlsConfig>` in their server configuration:
|
|
|
|
```rust
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ServerSettings {
|
|
/// Listen address
|
|
pub addr: SocketAddr,
|
|
|
|
/// TLS configuration (optional)
|
|
pub tls: Option<TlsConfig>,
|
|
}
|
|
```
|
|
|
|
### Server Builder Pattern (tonic)
|
|
|
|
```rust
|
|
use tonic::transport::{Server, ServerTlsConfig, Identity, Certificate};
|
|
|
|
let mut server = Server::builder();
|
|
|
|
if let Some(tls_config) = &config.server.tls {
|
|
let cert = tokio::fs::read(&tls_config.cert_file).await?;
|
|
let key = tokio::fs::read(&tls_config.key_file).await?;
|
|
let server_identity = Identity::from_pem(cert, key);
|
|
|
|
let tls = if tls_config.require_client_cert {
|
|
// mTLS: require and verify client certificates
|
|
let ca_cert = tokio::fs::read(
|
|
tls_config.ca_file.as_ref()
|
|
.ok_or("ca_file required when require_client_cert=true")?
|
|
).await?;
|
|
let ca = Certificate::from_pem(ca_cert);
|
|
|
|
ServerTlsConfig::new()
|
|
.identity(server_identity)
|
|
.client_ca_root(ca)
|
|
} else {
|
|
// TLS only: no client certificate required
|
|
ServerTlsConfig::new()
|
|
.identity(server_identity)
|
|
};
|
|
|
|
server = server.tls_config(tls)?;
|
|
}
|
|
|
|
server.add_service(my_service).serve(config.server.addr).await?;
|
|
```
|
|
|
|
### TOML Configuration Example
|
|
|
|
```toml
|
|
[server]
|
|
addr = "0.0.0.0:50051"
|
|
|
|
[server.tls]
|
|
cert_file = "/etc/centra-cloud/certs/iam/server.crt"
|
|
key_file = "/etc/centra-cloud/certs/iam/server.key"
|
|
ca_file = "/etc/centra-cloud/certs/ca.crt"
|
|
require_client_cert = true # Enable mTLS
|
|
```
|
|
|
|
### Certificate Management
|
|
|
|
- **Development:** Use `scripts/generate-dev-certs.sh` to create self-signed CA and service certificates
|
|
- **Production:** Integrate with external PKI or use cert-manager for automated rotation
|
|
- **Storage:** Certificates stored in `/etc/centra-cloud/certs/` (NixOS managed)
|
|
- **Permissions:** Private keys must be readable only by service user (chmod 600)
|
|
|
|
By following these guidelines, we aim to achieve a unified, operator-friendly, and robust configuration system across the entire Cloud project.
|