diff --git a/CHANGELOG.md b/CHANGELOG.md index 59029f4..39a0b09 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,8 +24,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Tenant name length**: [`validate_dns1035_label`](src/types/v1alpha1/tenant.rs) now caps `metadata.name` at **55** characters so derived names like `{name}-console` remain valid Kubernetes DNS labels (≤ 63). +- **Encryption validation on reconcile**: [`validate_kms_secret`](src/context.rs) now runs whenever `spec.encryption.enabled` is true (previously skipped when `kmsSecret` was unset). + ### Changed +- **Tenant `spec.encryption.vault`**: Removed `tlsSkipVerify` and `customCertificates` (they were never wired to `rustfs-kms`). Vault TLS should rely on system-trusted CAs or TLS upstream. The project is still pre-production; if you have old YAML with these keys, remove them before apply. + +- **KMS pod environment** ([`tenant/workloads.rs`](src/types/v1alpha1/tenant/workloads.rs)): Align variable names with the RustFS server and `rustfs-kms` (`RUSTFS_KMS_ENABLE`, `RUSTFS_KMS_VAULT_ADDRESS`, KV mount and key prefix, local `RUSTFS_KMS_KEY_DIR` / `RUSTFS_KMS_DEFAULT_KEY_ID`, etc.); remove Vault TLS certificate volume mounts; `ping_seconds` remains documented as reserved (not injected). + +- **Local KMS** ([`context.rs`](src/context.rs)): Validate absolute `keyDirectory` and require a single server replica across pools (multi-replica tenants need Vault or shared storage). + - **Deploy scripts** ([`scripts/deploy/deploy-rustfs.sh`](scripts/deploy/deploy-rustfs.sh), [`deploy-rustfs-4node.sh`](scripts/deploy/deploy-rustfs-4node.sh)): Docker builds use **layer cache by default** (`docker_build_cached`); set `RUSTFS_DOCKER_NO_CACHE=true` for a full rebuild. Documented in [`scripts/README.md`](scripts/README.md). - **4-node deploy**: Help text moved to an early heredoc (avoids trailing `case`/parse issues); see script header. - **4-node cleanup** ([`cleanup-rustfs-4node.sh`](scripts/cleanup/cleanup-rustfs-4node.sh)): Host storage dirs under `/tmp/rustfs-storage-*` may require `sudo rm -rf` after Kind (root-owned bind mounts). diff --git a/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx b/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx index 3854471..84947e9 100644 --- a/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx +++ b/console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx @@ -108,8 +108,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi namespace: "", prefix: "", authType: "token", - tlsSkipVerify: false, - customCertificates: false, }) const [encAppRole, setEncAppRole] = useState({ engine: "", @@ -380,8 +378,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi namespace: data.vault.namespace || "", prefix: data.vault.prefix || "", authType: data.vault.authType || "token", - tlsSkipVerify: data.vault.tlsSkipVerify || false, - customCertificates: data.vault.customCertificates || false, }) if (data.vault.appRole) { setEncAppRole({ @@ -428,8 +424,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi namespace: encVault.namespace || undefined, prefix: encVault.prefix || undefined, authType: encVault.authType || undefined, - tlsSkipVerify: encVault.tlsSkipVerify || undefined, - customCertificates: encVault.customCertificates || undefined, } if (encVault.authType === "approle") { body.vault.appRole = { @@ -951,32 +945,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi /> -
-
- - setEncVault((v) => ({ ...v, tlsSkipVerify: e.target.checked }))} - className="h-4 w-4 rounded border-border" - /> -
-
- - setEncVault((v) => ({ ...v, customCertificates: e.target.checked }))} - className="h-4 w-4 rounded border-border" - /> -
-
{/* Auth type selector */}
@@ -1093,21 +1061,15 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
setEncKmsSecretName(e.target.value)} />

{encBackend === "vault" ? encVault.authType === "approle" - ? t("Secret must contain 'vault-approle-id' and 'vault-approle-secret'.") + - (encVault.customCertificates - ? " " + t("Plus TLS certs: vault-ca-cert, vault-client-cert, vault-client-key.") - : "") - : t("Secret must contain key 'vault-token'.") + - (encVault.customCertificates - ? " " + t("Plus TLS certs: vault-ca-cert, vault-client-cert, vault-client-key.") - : "") + ? t("Secret must contain 'vault-approle-id' and 'vault-approle-secret'.") + : t("Secret must contain key 'vault-token'.") : t("Not required for Local backend.")}

diff --git a/console-web/types/api.ts b/console-web/types/api.ts index e350a25..008b5f6 100644 --- a/console-web/types/api.ts +++ b/console-web/types/api.ts @@ -271,8 +271,6 @@ export interface VaultInfo { prefix: string | null authType: string | null appRole: AppRoleInfo | null - tlsSkipVerify: boolean | null - customCertificates: boolean | null } export interface LocalKmsInfo { @@ -310,8 +308,6 @@ export interface UpdateEncryptionRequest { engine?: string retrySeconds?: number } - tlsSkipVerify?: boolean - customCertificates?: boolean } local?: { keyDirectory?: string diff --git a/deploy/rustfs-operator/crds/tenant-crd.yaml b/deploy/rustfs-operator/crds/tenant-crd.yaml index b6db5da..fcd8740 100644 --- a/deploy/rustfs-operator/crds/tenant-crd.yaml +++ b/deploy/rustfs-operator/crds/tenant-crd.yaml @@ -66,7 +66,7 @@ spec: kmsSecret: description: |- Reference to a Secret containing sensitive KMS credentials - (Vault token or AppRole credentials, TLS certificates). + (Vault token or AppRole credentials). nullable: true properties: name: @@ -80,19 +80,20 @@ spec: nullable: true properties: keyDirectory: - description: 'Directory for key files inside the container (default: `/data/kms-keys`).' + description: |- + Absolute directory for KMS key files inside the container (default: `/data/kms-keys`). + Must be absolute; RustFS validates this for the local backend. nullable: true type: string masterKeyId: - description: 'Master key identifier (default: `default-master-key`).' + description: Default KMS key id for SSE (maps to `RUSTFS_KMS_DEFAULT_KEY_ID` in the RustFS binary). nullable: true type: string type: object pingSeconds: description: |- - Interval in seconds for KMS health-check pings (default: disabled). - When set, the operator stores the value; the in-process KMS library - picks it up from `RUSTFS_KMS_PING_SECONDS`. + Reserved for future KMS health-check tuning. Not injected into pods: the current RustFS + release does not read `RUSTFS_KMS_PING_SECONDS` in the server startup path. format: int32 nullable: true type: integer @@ -125,19 +126,11 @@ spec: - null nullable: true type: string - customCertificates: - description: |- - Enable custom TLS certificates for the Vault connection. - When `true`, the operator mounts TLS certificate files from the KMS Secret - and configures the corresponding environment variables. - The Secret must contain: `vault-ca-cert`, `vault-client-cert`, `vault-client-key`. - nullable: true - type: boolean endpoint: description: Vault server endpoint (e.g. `https://vault.example.com:8200`). type: string engine: - description: 'Vault KV2 engine mount path (default: `kv`).' + description: KV secrets engine mount path (maps to `RUSTFS_KMS_VAULT_KV_MOUNT` in rustfs-kms; e.g. `secret`, `kv`). nullable: true type: string namespace: @@ -145,13 +138,9 @@ spec: nullable: true type: string prefix: - description: Key prefix inside the engine. + description: Key prefix inside the KV engine (maps to `RUSTFS_KMS_VAULT_KEY_PREFIX`). nullable: true type: string - tlsSkipVerify: - description: Skip TLS certificate verification for Vault connection. - nullable: true - type: boolean required: - endpoint type: object diff --git a/deploy/rustfs-operator/crds/tenant.yaml b/deploy/rustfs-operator/crds/tenant.yaml index b6db5da..fcd8740 100755 --- a/deploy/rustfs-operator/crds/tenant.yaml +++ b/deploy/rustfs-operator/crds/tenant.yaml @@ -66,7 +66,7 @@ spec: kmsSecret: description: |- Reference to a Secret containing sensitive KMS credentials - (Vault token or AppRole credentials, TLS certificates). + (Vault token or AppRole credentials). nullable: true properties: name: @@ -80,19 +80,20 @@ spec: nullable: true properties: keyDirectory: - description: 'Directory for key files inside the container (default: `/data/kms-keys`).' + description: |- + Absolute directory for KMS key files inside the container (default: `/data/kms-keys`). + Must be absolute; RustFS validates this for the local backend. nullable: true type: string masterKeyId: - description: 'Master key identifier (default: `default-master-key`).' + description: Default KMS key id for SSE (maps to `RUSTFS_KMS_DEFAULT_KEY_ID` in the RustFS binary). nullable: true type: string type: object pingSeconds: description: |- - Interval in seconds for KMS health-check pings (default: disabled). - When set, the operator stores the value; the in-process KMS library - picks it up from `RUSTFS_KMS_PING_SECONDS`. + Reserved for future KMS health-check tuning. Not injected into pods: the current RustFS + release does not read `RUSTFS_KMS_PING_SECONDS` in the server startup path. format: int32 nullable: true type: integer @@ -125,19 +126,11 @@ spec: - null nullable: true type: string - customCertificates: - description: |- - Enable custom TLS certificates for the Vault connection. - When `true`, the operator mounts TLS certificate files from the KMS Secret - and configures the corresponding environment variables. - The Secret must contain: `vault-ca-cert`, `vault-client-cert`, `vault-client-key`. - nullable: true - type: boolean endpoint: description: Vault server endpoint (e.g. `https://vault.example.com:8200`). type: string engine: - description: 'Vault KV2 engine mount path (default: `kv`).' + description: KV secrets engine mount path (maps to `RUSTFS_KMS_VAULT_KV_MOUNT` in rustfs-kms; e.g. `secret`, `kv`). nullable: true type: string namespace: @@ -145,13 +138,9 @@ spec: nullable: true type: string prefix: - description: Key prefix inside the engine. + description: Key prefix inside the KV engine (maps to `RUSTFS_KMS_VAULT_KEY_PREFIX`). nullable: true type: string - tlsSkipVerify: - description: Skip TLS certificate verification for Vault connection. - nullable: true - type: boolean required: - endpoint type: object diff --git a/src/console/handlers/encryption.rs b/src/console/handlers/encryption.rs index 52d1d0e..98b9b9e 100644 --- a/src/console/handlers/encryption.rs +++ b/src/console/handlers/encryption.rs @@ -55,8 +55,6 @@ pub async fn get_encryption( engine: ar.engine.clone(), retry_seconds: ar.retry_seconds, }), - tls_skip_verify: v.tls_skip_verify, - custom_certificates: v.custom_certificates, }), local: enc.local.as_ref().map(|l| LocalInfo { key_directory: l.key_directory.clone(), @@ -152,8 +150,6 @@ pub async fn update_encryption( engine: ar.engine, retry_seconds: ar.retry_seconds, }), - tls_skip_verify: v.tls_skip_verify, - custom_certificates: v.custom_certificates, }) } else { None diff --git a/src/console/models/encryption.rs b/src/console/models/encryption.rs index 6a5c7a2..1717eaa 100644 --- a/src/console/models/encryption.rs +++ b/src/console/models/encryption.rs @@ -38,8 +38,6 @@ pub struct VaultInfo { pub prefix: Option, pub auth_type: Option, pub app_role: Option, - pub tls_skip_verify: Option, - pub custom_certificates: Option, } /// AppRole non-sensitive fields. @@ -90,8 +88,6 @@ pub struct UpdateVaultRequest { pub prefix: Option, pub auth_type: Option, pub app_role: Option, - pub tls_skip_verify: Option, - pub custom_certificates: Option, } #[derive(Debug, Deserialize, ToSchema)] diff --git a/src/context.rs b/src/context.rs index 238c39f..69e0606 100755 --- a/src/context.rs +++ b/src/context.rs @@ -75,6 +75,31 @@ pub enum Error { Serde { source: serde_json::Error }, } +/// Validates Local KMS: absolute `keyDirectory` and at most one server replica across pools. +fn validate_local_kms_tenant( + local: Option<&types::v1alpha1::encryption::LocalKmsConfig>, + pools: &[types::v1alpha1::pool::Pool], +) -> Result<(), Error> { + let key_dir = local + .and_then(|l| l.key_directory.as_deref()) + .unwrap_or("/data/kms-keys"); + if !key_dir.starts_with('/') { + return Err(Error::KmsConfigInvalid { + message: format!( + "Local KMS keyDirectory must be an absolute path (got \"{}\")", + key_dir + ), + }); + } + let total_servers: i32 = pools.iter().map(|p| p.servers).sum(); + if total_servers > 1 { + return Err(Error::KmsConfigInvalid { + message: "Local KMS is only supported when the tenant has a single RustFS server replica (sum of pool servers must be 1). For multiple servers use Vault KMS, or use a single-server pool.".to_string(), + }); + } + Ok(()) +} + pub struct Context { pub(crate) client: kube::Client, pub(crate) recorder: Recorder, @@ -303,8 +328,9 @@ impl Context { /// Validates encryption configuration and the KMS Secret. /// /// Checks: - /// 1. Vault endpoint is non-empty when backend is Vault. - /// 2. KMS Secret exists and contains the correct keys for the auth type. + /// 1. Local KMS: absolute key directory and single replica (sum of pool servers). + /// 2. Vault endpoint is non-empty when backend is Vault. + /// 3. KMS Secret exists and contains the correct keys for the auth type. pub async fn validate_kms_secret(&self, tenant: &Tenant) -> Result<(), Error> { use crate::types::v1alpha1::encryption::{KmsBackendType, VaultAuthType}; @@ -315,6 +341,12 @@ impl Context { return Ok(()); } + // Local KMS: RustFS requires an absolute key directory; multi-replica tenants need Vault + // (or a shared filesystem) because each Pod would otherwise have its own key files. + if enc.backend == KmsBackendType::Local { + validate_local_kms_tenant(enc.local.as_ref(), &tenant.spec.pools)?; + } + // Validate Vault endpoint is non-empty and kms_secret is required for Vault if enc.backend == KmsBackendType::Vault { let endpoint_empty = enc @@ -468,3 +500,46 @@ impl Context { Ok((status.current_revision, status.update_revision)) } } + +#[cfg(test)] +mod validate_local_kms_tests { + use super::Error; + use super::validate_local_kms_tenant; + use crate::types::v1alpha1::encryption::LocalKmsConfig; + use crate::types::v1alpha1::persistence::PersistenceConfig; + use crate::types::v1alpha1::pool::Pool; + + fn pool(servers: i32) -> Pool { + Pool { + name: "p".to_string(), + servers, + persistence: PersistenceConfig { + volumes_per_server: 4, + ..Default::default() + }, + scheduling: Default::default(), + } + } + + #[test] + fn local_kms_default_key_dir_ok_single_replica() { + validate_local_kms_tenant(None, &[pool(1)]).unwrap(); + } + + #[test] + fn local_kms_rejects_relative_key_dir() { + let local = LocalKmsConfig { + key_directory: Some("data/kms".to_string()), + ..Default::default() + }; + let err = validate_local_kms_tenant(Some(&local), &[pool(1)]).unwrap_err(); + assert!(matches!(err, Error::KmsConfigInvalid { .. })); + } + + #[test] + fn local_kms_rejects_multi_pool_multi_replica() { + let local = LocalKmsConfig::default(); + let err = validate_local_kms_tenant(Some(&local), &[pool(2), pool(2)]).unwrap_err(); + assert!(matches!(err, Error::KmsConfigInvalid { .. })); + } +} diff --git a/src/reconcile.rs b/src/reconcile.rs index 2627bac..529e524 100755 --- a/src/reconcile.rs +++ b/src/reconcile.rs @@ -79,10 +79,11 @@ pub async fn reconcile_rustfs(tenant: Arc, ctx: Arc) -> Result< return Err(e.into()); } - // Validate KMS Secret if encryption is configured + // Validate encryption / KMS: Vault requires endpoint + kmsSecret (and correct keys); + // must run whenever encryption is enabled — not only when kmsSecret is set, or Vault + // without a Secret reference would skip validation entirely. if let Some(ref enc) = latest_tenant.spec.encryption && enc.enabled - && enc.kms_secret.is_some() && let Err(e) = ctx.validate_kms_secret(&latest_tenant).await { let _ = ctx diff --git a/src/types/v1alpha1/encryption.rs b/src/types/v1alpha1/encryption.rs index e5e8ba0..3da37b8 100644 --- a/src/types/v1alpha1/encryption.rs +++ b/src/types/v1alpha1/encryption.rs @@ -65,7 +65,7 @@ impl std::fmt::Display for VaultAuthType { /// Vault-specific KMS configuration. /// /// Maps to `VaultConfig` in the `rustfs-kms` crate. -/// Sensitive fields (token, TLS keys) are stored in the Secret referenced +/// Sensitive fields (Vault token or AppRole credentials) are stored in the Secret referenced /// by `EncryptionConfig::kms_secret`. #[derive(Deserialize, Serialize, Clone, Debug, KubeSchema, Default)] #[serde(rename_all = "camelCase")] @@ -73,7 +73,7 @@ pub struct VaultKmsConfig { /// Vault server endpoint (e.g. `https://vault.example.com:8200`). pub endpoint: String, - /// Vault KV2 engine mount path (default: `kv`). + /// KV secrets engine mount path (maps to `RUSTFS_KMS_VAULT_KV_MOUNT` in rustfs-kms; e.g. `secret`, `kv`). #[serde(default, skip_serializing_if = "Option::is_none")] pub engine: Option, @@ -81,7 +81,7 @@ pub struct VaultKmsConfig { #[serde(default, skip_serializing_if = "Option::is_none")] pub namespace: Option, - /// Key prefix inside the engine. + /// Key prefix inside the KV engine (maps to `RUSTFS_KMS_VAULT_KEY_PREFIX`). #[serde(default, skip_serializing_if = "Option::is_none")] pub prefix: Option, @@ -94,17 +94,6 @@ pub struct VaultKmsConfig { /// under keys `vault-approle-id` and `vault-approle-secret`. #[serde(default, skip_serializing_if = "Option::is_none")] pub app_role: Option, - - /// Skip TLS certificate verification for Vault connection. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tls_skip_verify: Option, - - /// Enable custom TLS certificates for the Vault connection. - /// When `true`, the operator mounts TLS certificate files from the KMS Secret - /// and configures the corresponding environment variables. - /// The Secret must contain: `vault-ca-cert`, `vault-client-cert`, `vault-client-key`. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub custom_certificates: Option, } /// Vault AppRole authentication settings. @@ -132,23 +121,28 @@ pub struct VaultAppRoleConfig { /// /// Maps to `LocalConfig` in the `rustfs-kms` crate. /// Keys are stored as JSON files in the specified directory. +/// +/// **RustFS binary alignment**: `key_directory` is injected as `RUSTFS_KMS_KEY_DIR` (required by +/// `rustfs` server startup). `master_key_id` maps to `RUSTFS_KMS_DEFAULT_KEY_ID` (default SSE key id), +/// not to a "master encryption passphrase" (`RUSTFS_KMS_LOCAL_MASTER_KEY` is separate in rustfs-kms). #[derive(Deserialize, Serialize, Clone, Debug, KubeSchema, Default)] #[serde(rename_all = "camelCase")] pub struct LocalKmsConfig { - /// Directory for key files inside the container (default: `/data/kms-keys`). + /// Absolute directory for KMS key files inside the container (default: `/data/kms-keys`). + /// Must be absolute; RustFS validates this for the local backend. #[serde(default, skip_serializing_if = "Option::is_none")] pub key_directory: Option, - /// Master key identifier (default: `default-master-key`). + /// Default KMS key id for SSE (maps to `RUSTFS_KMS_DEFAULT_KEY_ID` in the RustFS binary). #[serde(default, skip_serializing_if = "Option::is_none")] pub master_key_id: Option, } /// Encryption / KMS configuration for a Tenant. /// -/// When enabled, the operator injects KMS environment variables and mounts -/// the referenced Secret into all RustFS pods so that the in-process -/// `rustfs-kms` library picks them up on startup. +/// When enabled, the operator injects environment variables matching the **RustFS server** +/// (`rustfs` CLI / `init_kms_system`) and `rustfs_kms::KmsConfig::from_env()` where applicable. +/// See `Tenant::configure_kms` in `tenant/workloads.rs` for the exact variable names. /// /// Example YAML: /// ```yaml @@ -161,7 +155,6 @@ pub struct LocalKmsConfig { /// engine: "kv" /// namespace: "tenant1" /// prefix: "rustfs" -/// customCertificates: true /// kmsSecret: /// name: "my-tenant-kms-secret" /// ``` @@ -175,11 +168,6 @@ pub struct LocalKmsConfig { /// - `vault-approle-id` (required): AppRole role ID /// - `vault-approle-secret` (required): AppRole secret ID /// -/// **Vault TLS (when `customCertificates: true`):** -/// - `vault-ca-cert`: PEM-encoded CA certificate -/// - `vault-client-cert`: PEM-encoded client certificate for mTLS -/// - `vault-client-key`: PEM-encoded client private key for mTLS -/// /// **Local backend:** /// No secret keys required (keys are stored on disk). #[derive(Deserialize, Serialize, Clone, Debug, KubeSchema, Default)] @@ -202,13 +190,12 @@ pub struct EncryptionConfig { pub local: Option, /// Reference to a Secret containing sensitive KMS credentials - /// (Vault token or AppRole credentials, TLS certificates). + /// (Vault token or AppRole credentials). #[serde(default, skip_serializing_if = "Option::is_none")] pub kms_secret: Option, - /// Interval in seconds for KMS health-check pings (default: disabled). - /// When set, the operator stores the value; the in-process KMS library - /// picks it up from `RUSTFS_KMS_PING_SECONDS`. + /// Reserved for future KMS health-check tuning. Not injected into pods: the current RustFS + /// release does not read `RUSTFS_KMS_PING_SECONDS` in the server startup path. #[serde(default, skip_serializing_if = "Option::is_none")] pub ping_seconds: Option, } diff --git a/src/types/v1alpha1/tenant/workloads.rs b/src/types/v1alpha1/tenant/workloads.rs index a5db7dd..a3546c8 100755 --- a/src/types/v1alpha1/tenant/workloads.rs +++ b/src/types/v1alpha1/tenant/workloads.rs @@ -25,9 +25,6 @@ const DEFAULT_RUN_AS_USER: i64 = 10001; const DEFAULT_RUN_AS_GROUP: i64 = 10001; const DEFAULT_FS_GROUP: i64 = 10001; -const KMS_CERT_VOLUME_NAME: &str = "kms-tls"; -const KMS_CERT_MOUNT_PATH: &str = "/etc/rustfs/kms/tls"; - fn volume_claim_template_name(shard: i32) -> String { format!("{VOLUME_CLAIM_TEMPLATE_PREFIX}-{shard}") } @@ -222,6 +219,11 @@ impl Tenant { /// Build KMS-related environment variables, pod volumes and container volume mounts /// based on `spec.encryption`. /// + /// Names align with the RustFS server (`rustfs/src/init.rs`, `rustfs/src/config/cli.rs`) and + /// `rustfs_kms::KmsConfig::from_env()` (`rustfs/crates/kms/src/config.rs`) for forward compatibility. + /// The server currently reads `RUSTFS_KMS_ENABLE`, `RUSTFS_KMS_BACKEND`, `RUSTFS_KMS_KEY_DIR`, + /// `RUSTFS_KMS_DEFAULT_KEY_ID`, `RUSTFS_KMS_VAULT_ADDRESS`, and `RUSTFS_KMS_VAULT_TOKEN` on startup. + /// /// Returns `(env_vars, pod_volumes, volume_mounts)`. fn configure_kms( &self, @@ -238,17 +240,17 @@ impl Tenant { } let mut env = Vec::new(); - let mut volumes = Vec::new(); - let mut mounts = Vec::new(); + let volumes: Vec = vec![]; + let mounts: Vec = vec![]; env.push(corev1::EnvVar { - name: "RUSTFS_KMS_BACKEND".to_owned(), - value: Some(enc.backend.to_string()), + name: "RUSTFS_KMS_ENABLE".to_owned(), + value: Some("true".to_owned()), ..Default::default() }); env.push(corev1::EnvVar { - name: "RUSTFS_KMS_AUTO_START".to_owned(), - value: Some("true".to_owned()), + name: "RUSTFS_KMS_BACKEND".to_owned(), + value: Some(enc.backend.to_string()), ..Default::default() }); @@ -256,17 +258,10 @@ impl Tenant { KmsBackendType::Vault => { if let Some(ref vault) = enc.vault { env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_ENDPOINT".to_owned(), + name: "RUSTFS_KMS_VAULT_ADDRESS".to_owned(), value: Some(vault.endpoint.clone()), ..Default::default() }); - if let Some(ref engine) = vault.engine { - env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_ENGINE".to_owned(), - value: Some(engine.clone()), - ..Default::default() - }); - } if let Some(ref ns) = vault.namespace { env.push(corev1::EnvVar { name: "RUSTFS_KMS_VAULT_NAMESPACE".to_owned(), @@ -274,17 +269,23 @@ impl Tenant { ..Default::default() }); } - if let Some(ref prefix) = vault.prefix { + // Transit secrets engine mount (rustfs-kms default: `transit`). + env.push(corev1::EnvVar { + name: "RUSTFS_KMS_VAULT_MOUNT_PATH".to_owned(), + value: Some("transit".to_owned()), + ..Default::default() + }); + if let Some(ref kv_mount) = vault.engine { env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_PREFIX".to_owned(), - value: Some(prefix.clone()), + name: "RUSTFS_KMS_VAULT_KV_MOUNT".to_owned(), + value: Some(kv_mount.clone()), ..Default::default() }); } - if vault.tls_skip_verify == Some(true) { + if let Some(ref prefix) = vault.prefix { env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_TLS_SKIP_VERIFY".to_owned(), - value: Some("true".to_owned()), + name: "RUSTFS_KMS_VAULT_KEY_PREFIX".to_owned(), + value: Some(prefix.clone()), ..Default::default() }); } @@ -306,10 +307,10 @@ impl Tenant { }); if let Some(ar) = enc.vault.as_ref().and_then(|v| v.app_role.as_ref()) { - if let Some(ref engine) = ar.engine { + if let Some(ref approle_engine) = ar.engine { env.push(corev1::EnvVar { name: "RUSTFS_KMS_VAULT_APPROLE_ENGINE".to_owned(), - value: Some(engine.clone()), + value: Some(approle_engine.clone()), ..Default::default() }); } @@ -365,64 +366,6 @@ impl Tenant { ..Default::default() }); } - - // Only mount TLS certificates when explicitly enabled - let custom_certs = enc - .vault - .as_ref() - .and_then(|v| v.custom_certificates) - .unwrap_or(false); - - if custom_certs { - volumes.push(corev1::Volume { - name: KMS_CERT_VOLUME_NAME.to_string(), - secret: Some(corev1::SecretVolumeSource { - secret_name: Some(secret_ref.name.clone()), - items: Some(vec![ - corev1::KeyToPath { - key: "vault-ca-cert".to_string(), - path: "ca.crt".to_string(), - ..Default::default() - }, - corev1::KeyToPath { - key: "vault-client-cert".to_string(), - path: "client.crt".to_string(), - ..Default::default() - }, - corev1::KeyToPath { - key: "vault-client-key".to_string(), - path: "client.key".to_string(), - ..Default::default() - }, - ]), - optional: Some(true), - ..Default::default() - }), - ..Default::default() - }); - mounts.push(corev1::VolumeMount { - name: KMS_CERT_VOLUME_NAME.to_string(), - mount_path: KMS_CERT_MOUNT_PATH.to_string(), - read_only: Some(true), - ..Default::default() - }); - - env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_TLS_CA".to_owned(), - value: Some(format!("{KMS_CERT_MOUNT_PATH}/ca.crt")), - ..Default::default() - }); - env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_TLS_CERT".to_owned(), - value: Some(format!("{KMS_CERT_MOUNT_PATH}/client.crt")), - ..Default::default() - }); - env.push(corev1::EnvVar { - name: "RUSTFS_KMS_VAULT_TLS_KEY".to_owned(), - value: Some(format!("{KMS_CERT_MOUNT_PATH}/client.key")), - ..Default::default() - }); - } } } KmsBackendType::Local => { @@ -430,31 +373,30 @@ impl Tenant { let key_dir = local_cfg .and_then(|l| l.key_directory.as_deref()) .unwrap_or("/data/kms-keys"); - let master_key_id = local_cfg + let default_key_id = local_cfg .and_then(|l| l.master_key_id.as_deref()) .unwrap_or("default-master-key"); + // `rustfs` server reads `RUSTFS_KMS_KEY_DIR` (see `build_local_kms_config`). + env.push(corev1::EnvVar { + name: "RUSTFS_KMS_KEY_DIR".to_owned(), + value: Some(key_dir.to_string()), + ..Default::default() + }); + // Duplicate for `rustfs_kms::KmsConfig::from_env()` which uses `RUSTFS_KMS_LOCAL_KEY_DIR`. env.push(corev1::EnvVar { name: "RUSTFS_KMS_LOCAL_KEY_DIR".to_owned(), value: Some(key_dir.to_string()), ..Default::default() }); env.push(corev1::EnvVar { - name: "RUSTFS_KMS_LOCAL_MASTER_KEY_ID".to_owned(), - value: Some(master_key_id.to_string()), + name: "RUSTFS_KMS_DEFAULT_KEY_ID".to_owned(), + value: Some(default_key_id.to_string()), ..Default::default() }); } } - if let Some(ping) = enc.ping_seconds { - env.push(corev1::EnvVar { - name: "RUSTFS_KMS_PING_SECONDS".to_owned(), - value: Some(ping.to_string()), - ..Default::default() - }); - } - (env, volumes, mounts) }