Skip to content

Commit f3b4c7d

Browse files
authored
feat(kms): align RustFS KMS env and encryption validation (#102)
Made-with: Cursor
1 parent a94f443 commit f3b4c7d

11 files changed

Lines changed: 161 additions & 220 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424

2525
- **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).
2626

27+
- **Encryption validation on reconcile**: [`validate_kms_secret`](src/context.rs) now runs whenever `spec.encryption.enabled` is true (previously skipped when `kmsSecret` was unset).
28+
2729
### Changed
2830

31+
- **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.
32+
33+
- **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).
34+
35+
- **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).
36+
2937
- **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).
3038
- **4-node deploy**: Help text moved to an early heredoc (avoids trailing `case`/parse issues); see script header.
3139
- **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).

console-web/app/(dashboard)/tenants/[namespace]/[name]/tenant-detail-client.tsx

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
108108
namespace: "",
109109
prefix: "",
110110
authType: "token",
111-
tlsSkipVerify: false,
112-
customCertificates: false,
113111
})
114112
const [encAppRole, setEncAppRole] = useState({
115113
engine: "",
@@ -380,8 +378,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
380378
namespace: data.vault.namespace || "",
381379
prefix: data.vault.prefix || "",
382380
authType: data.vault.authType || "token",
383-
tlsSkipVerify: data.vault.tlsSkipVerify || false,
384-
customCertificates: data.vault.customCertificates || false,
385381
})
386382
if (data.vault.appRole) {
387383
setEncAppRole({
@@ -428,8 +424,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
428424
namespace: encVault.namespace || undefined,
429425
prefix: encVault.prefix || undefined,
430426
authType: encVault.authType || undefined,
431-
tlsSkipVerify: encVault.tlsSkipVerify || undefined,
432-
customCertificates: encVault.customCertificates || undefined,
433427
}
434428
if (encVault.authType === "approle") {
435429
body.vault.appRole = {
@@ -951,32 +945,6 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
951945
/>
952946
</div>
953947
</div>
954-
<div className="flex items-center gap-6">
955-
<div className="flex items-center gap-3">
956-
<label htmlFor="vault-tls-skip" className="text-sm">
957-
{t("Skip TLS Verification")}
958-
</label>
959-
<input
960-
id="vault-tls-skip"
961-
type="checkbox"
962-
checked={encVault.tlsSkipVerify}
963-
onChange={(e) => setEncVault((v) => ({ ...v, tlsSkipVerify: e.target.checked }))}
964-
className="h-4 w-4 rounded border-border"
965-
/>
966-
</div>
967-
<div className="flex items-center gap-3">
968-
<label htmlFor="vault-custom-certs" className="text-sm">
969-
{t("Custom Certificates")}
970-
</label>
971-
<input
972-
id="vault-custom-certs"
973-
type="checkbox"
974-
checked={encVault.customCertificates}
975-
onChange={(e) => setEncVault((v) => ({ ...v, customCertificates: e.target.checked }))}
976-
className="h-4 w-4 rounded border-border"
977-
/>
978-
</div>
979-
</div>
980948

981949
{/* Auth type selector */}
982950
<div className="space-y-2 pt-2">
@@ -1093,21 +1061,15 @@ export function TenantDetailClient({ namespace, name, initialTab, initialYamlEdi
10931061
<div className="space-y-2">
10941062
<Label>{t("KMS Secret Name")}</Label>
10951063
<Input
1096-
placeholder={`${t("Optional")}${t("Secret containing vault-token and TLS certs")}`}
1064+
placeholder={`${t("Optional")}${t("Secret containing vault-token")}`}
10971065
value={encKmsSecretName}
10981066
onChange={(e) => setEncKmsSecretName(e.target.value)}
10991067
/>
11001068
<p className="text-xs text-muted-foreground">
11011069
{encBackend === "vault"
11021070
? encVault.authType === "approle"
1103-
? t("Secret must contain 'vault-approle-id' and 'vault-approle-secret'.") +
1104-
(encVault.customCertificates
1105-
? " " + t("Plus TLS certs: vault-ca-cert, vault-client-cert, vault-client-key.")
1106-
: "")
1107-
: t("Secret must contain key 'vault-token'.") +
1108-
(encVault.customCertificates
1109-
? " " + t("Plus TLS certs: vault-ca-cert, vault-client-cert, vault-client-key.")
1110-
: "")
1071+
? t("Secret must contain 'vault-approle-id' and 'vault-approle-secret'.")
1072+
: t("Secret must contain key 'vault-token'.")
11111073
: t("Not required for Local backend.")}
11121074
</p>
11131075
</div>

console-web/types/api.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,6 @@ export interface VaultInfo {
271271
prefix: string | null
272272
authType: string | null
273273
appRole: AppRoleInfo | null
274-
tlsSkipVerify: boolean | null
275-
customCertificates: boolean | null
276274
}
277275

278276
export interface LocalKmsInfo {
@@ -310,8 +308,6 @@ export interface UpdateEncryptionRequest {
310308
engine?: string
311309
retrySeconds?: number
312310
}
313-
tlsSkipVerify?: boolean
314-
customCertificates?: boolean
315311
}
316312
local?: {
317313
keyDirectory?: string

deploy/rustfs-operator/crds/tenant-crd.yaml

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ spec:
6666
kmsSecret:
6767
description: |-
6868
Reference to a Secret containing sensitive KMS credentials
69-
(Vault token or AppRole credentials, TLS certificates).
69+
(Vault token or AppRole credentials).
7070
nullable: true
7171
properties:
7272
name:
@@ -80,19 +80,20 @@ spec:
8080
nullable: true
8181
properties:
8282
keyDirectory:
83-
description: 'Directory for key files inside the container (default: `/data/kms-keys`).'
83+
description: |-
84+
Absolute directory for KMS key files inside the container (default: `/data/kms-keys`).
85+
Must be absolute; RustFS validates this for the local backend.
8486
nullable: true
8587
type: string
8688
masterKeyId:
87-
description: 'Master key identifier (default: `default-master-key`).'
89+
description: Default KMS key id for SSE (maps to `RUSTFS_KMS_DEFAULT_KEY_ID` in the RustFS binary).
8890
nullable: true
8991
type: string
9092
type: object
9193
pingSeconds:
9294
description: |-
93-
Interval in seconds for KMS health-check pings (default: disabled).
94-
When set, the operator stores the value; the in-process KMS library
95-
picks it up from `RUSTFS_KMS_PING_SECONDS`.
95+
Reserved for future KMS health-check tuning. Not injected into pods: the current RustFS
96+
release does not read `RUSTFS_KMS_PING_SECONDS` in the server startup path.
9697
format: int32
9798
nullable: true
9899
type: integer
@@ -125,33 +126,21 @@ spec:
125126
- null
126127
nullable: true
127128
type: string
128-
customCertificates:
129-
description: |-
130-
Enable custom TLS certificates for the Vault connection.
131-
When `true`, the operator mounts TLS certificate files from the KMS Secret
132-
and configures the corresponding environment variables.
133-
The Secret must contain: `vault-ca-cert`, `vault-client-cert`, `vault-client-key`.
134-
nullable: true
135-
type: boolean
136129
endpoint:
137130
description: Vault server endpoint (e.g. `https://vault.example.com:8200`).
138131
type: string
139132
engine:
140-
description: 'Vault KV2 engine mount path (default: `kv`).'
133+
description: KV secrets engine mount path (maps to `RUSTFS_KMS_VAULT_KV_MOUNT` in rustfs-kms; e.g. `secret`, `kv`).
141134
nullable: true
142135
type: string
143136
namespace:
144137
description: Vault namespace (Enterprise feature).
145138
nullable: true
146139
type: string
147140
prefix:
148-
description: Key prefix inside the engine.
141+
description: Key prefix inside the KV engine (maps to `RUSTFS_KMS_VAULT_KEY_PREFIX`).
149142
nullable: true
150143
type: string
151-
tlsSkipVerify:
152-
description: Skip TLS certificate verification for Vault connection.
153-
nullable: true
154-
type: boolean
155144
required:
156145
- endpoint
157146
type: object

deploy/rustfs-operator/crds/tenant.yaml

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ spec:
6666
kmsSecret:
6767
description: |-
6868
Reference to a Secret containing sensitive KMS credentials
69-
(Vault token or AppRole credentials, TLS certificates).
69+
(Vault token or AppRole credentials).
7070
nullable: true
7171
properties:
7272
name:
@@ -80,19 +80,20 @@ spec:
8080
nullable: true
8181
properties:
8282
keyDirectory:
83-
description: 'Directory for key files inside the container (default: `/data/kms-keys`).'
83+
description: |-
84+
Absolute directory for KMS key files inside the container (default: `/data/kms-keys`).
85+
Must be absolute; RustFS validates this for the local backend.
8486
nullable: true
8587
type: string
8688
masterKeyId:
87-
description: 'Master key identifier (default: `default-master-key`).'
89+
description: Default KMS key id for SSE (maps to `RUSTFS_KMS_DEFAULT_KEY_ID` in the RustFS binary).
8890
nullable: true
8991
type: string
9092
type: object
9193
pingSeconds:
9294
description: |-
93-
Interval in seconds for KMS health-check pings (default: disabled).
94-
When set, the operator stores the value; the in-process KMS library
95-
picks it up from `RUSTFS_KMS_PING_SECONDS`.
95+
Reserved for future KMS health-check tuning. Not injected into pods: the current RustFS
96+
release does not read `RUSTFS_KMS_PING_SECONDS` in the server startup path.
9697
format: int32
9798
nullable: true
9899
type: integer
@@ -125,33 +126,21 @@ spec:
125126
- null
126127
nullable: true
127128
type: string
128-
customCertificates:
129-
description: |-
130-
Enable custom TLS certificates for the Vault connection.
131-
When `true`, the operator mounts TLS certificate files from the KMS Secret
132-
and configures the corresponding environment variables.
133-
The Secret must contain: `vault-ca-cert`, `vault-client-cert`, `vault-client-key`.
134-
nullable: true
135-
type: boolean
136129
endpoint:
137130
description: Vault server endpoint (e.g. `https://vault.example.com:8200`).
138131
type: string
139132
engine:
140-
description: 'Vault KV2 engine mount path (default: `kv`).'
133+
description: KV secrets engine mount path (maps to `RUSTFS_KMS_VAULT_KV_MOUNT` in rustfs-kms; e.g. `secret`, `kv`).
141134
nullable: true
142135
type: string
143136
namespace:
144137
description: Vault namespace (Enterprise feature).
145138
nullable: true
146139
type: string
147140
prefix:
148-
description: Key prefix inside the engine.
141+
description: Key prefix inside the KV engine (maps to `RUSTFS_KMS_VAULT_KEY_PREFIX`).
149142
nullable: true
150143
type: string
151-
tlsSkipVerify:
152-
description: Skip TLS certificate verification for Vault connection.
153-
nullable: true
154-
type: boolean
155144
required:
156145
- endpoint
157146
type: object

src/console/handlers/encryption.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ pub async fn get_encryption(
5555
engine: ar.engine.clone(),
5656
retry_seconds: ar.retry_seconds,
5757
}),
58-
tls_skip_verify: v.tls_skip_verify,
59-
custom_certificates: v.custom_certificates,
6058
}),
6159
local: enc.local.as_ref().map(|l| LocalInfo {
6260
key_directory: l.key_directory.clone(),
@@ -152,8 +150,6 @@ pub async fn update_encryption(
152150
engine: ar.engine,
153151
retry_seconds: ar.retry_seconds,
154152
}),
155-
tls_skip_verify: v.tls_skip_verify,
156-
custom_certificates: v.custom_certificates,
157153
})
158154
} else {
159155
None

src/console/models/encryption.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ pub struct VaultInfo {
3838
pub prefix: Option<String>,
3939
pub auth_type: Option<String>,
4040
pub app_role: Option<AppRoleInfo>,
41-
pub tls_skip_verify: Option<bool>,
42-
pub custom_certificates: Option<bool>,
4341
}
4442

4543
/// AppRole non-sensitive fields.
@@ -90,8 +88,6 @@ pub struct UpdateVaultRequest {
9088
pub prefix: Option<String>,
9189
pub auth_type: Option<String>,
9290
pub app_role: Option<UpdateAppRoleRequest>,
93-
pub tls_skip_verify: Option<bool>,
94-
pub custom_certificates: Option<bool>,
9591
}
9692

9793
#[derive(Debug, Deserialize, ToSchema)]

0 commit comments

Comments
 (0)