@@ -283,6 +283,8 @@ type SecretsStoreCSIDriverConfigSpec struct {
283283
284284 // tokenRequests controls service account token configuration for
285285 // workload identity federation (WIF) with cloud providers.
286+ // When omitted, the operator preserves any existing tokenRequests
287+ // already configured on the CSIDriver object without modification.
286288 // +optional
287289 TokenRequests *SecretsStoreTokenRequests `json:"tokenRequests,omitempty"`
288290}
@@ -328,15 +330,18 @@ type SecretsStoreTokenRequests struct {
328330
329331// ManagedTokenRequests holds the configuration for operator-managed
330332// service account token requests.
333+ // +kubebuilder:validation:MinProperties=1
331334type ManagedTokenRequests struct {
332335 // audiences specifies service account token audiences that kubelet will
333336 // provide to the CSI driver during NodePublishVolume calls. These tokens
334337 // enable workload identity federation (WIF) with cloud providers such as
335338 // AWS, Azure, and GCP.
339+ // When empty, the operator clears all tokenRequests from the CSIDriver object.
336340 // +optional
337- // +listType=atomic
341+ // +listType=map
342+ // +listMapKey=audience
338343 // +kubebuilder:validation:MaxItems=10
339- Audiences []SecretsStoreTokenRequest `json:"audiences,omitempty"`
344+ Audiences * []SecretsStoreTokenRequest `json:"audiences,omitempty"`
340345}
341346
342347// SecretRotationType determines the secret rotation behavior for the
@@ -371,16 +376,20 @@ type SecretsStoreSecretRotation struct {
371376 // custom holds the custom rotation configuration.
372377 // Only valid when type is "Custom".
373378 // +optional
374- Custom * CustomSecretRotation `json:"custom,omitempty "`
379+ Custom CustomSecretRotation `json:"custom,omitzero "`
375380}
376381
377382// CustomSecretRotation holds configuration for custom secret rotation behavior.
383+ // +kubebuilder:validation:MinProperties=1
378384type CustomSecretRotation struct {
379385 // rotationPollIntervalSeconds is the minimum time in seconds between
380386 // secret rotation attempts. The driver skips provider calls if less than
381387 // this interval has elapsed since the last successful rotation.
382- // When omitted, the platform chooses a reasonable default (currently 120).
383- // +default=120
388+ // Must be at least 1 second and no more than 31560000 seconds (~1 year).
389+ // When omitted, this means no opinion and the platform is left to choose a
390+ // reasonable default, which is subject to change over time.
391+ // +kubebuilder:validation:Minimum=1
392+ // +kubebuilder:validation:Maximum=31560000
384393 // +optional
385394 RotationPollIntervalSeconds *int32 `json:"rotationPollIntervalSeconds,omitempty"`
386395}
@@ -400,13 +409,13 @@ type SecretsStoreTokenRequest struct {
400409 // expirationSeconds is the requested duration of validity of the
401410 // service account token. The token issuer may return a token with
402411 // a different validity duration.
403- // When omitted, the token expiration is determined by the kube-apiserver
404- // (defaults to 1 hour). Must be at least 600 seconds (10 minutes) and
405- // no more than 4294967296 (1 << 32) seconds .
412+ // When omitted, the token expiration is determined by the kube-apiserver.
413+ // Must be at least 600 seconds (10 minutes) and no more than 315360000
414+ // seconds (~10 years) .
406415 // +kubebuilder:validation:Minimum=600
407- // +kubebuilder:validation:Maximum=4294967296
416+ // +kubebuilder:validation:Maximum=315360000
408417 // +optional
409- ExpirationSeconds * int64 `json:"expirationSeconds,omitempty"`
418+ ExpirationSeconds int64 `json:"expirationSeconds,omitempty"`
410419}
411420```
412421
@@ -460,16 +469,24 @@ spec:
460469# ### Validation Rules
461470
462471- ` secretsStore` must be set if and only if `driverType` is `SecretsStore`
463- - ` rotationPollIntervalSeconds` defaults to 120 seconds (2 minutes). No minimum
464- is enforced at the API level; the administrator is trusted to choose an appropriate value.
472+ - `SecretsStoreCSIDriverConfigSpec` has `MinProperties=1` to prevent `secretsStore : {}`.
473+ - ` rotationPollIntervalSeconds` must be between 1 and 31560000 (~1 year). When omitted,
474+ the platform chooses a reasonable default (subject to change over time).
475+ - ` expirationSeconds` must be between 600 (10 minutes) and 315360000 (~10 years).
476+ - ` audiences` entries must have unique `audience` values, enforced automatically via
477+ ` +listType=map` with `+listMapKey=audience`. This also enables SSA patch operations
478+ (e.g., adding a single audience without replacing the full list).
479+ - `ManagedTokenRequests` has `MinProperties=1` to prevent `managed : {}`. The only valid
480+ way to clear WIF configuration is `managed : { audiences: [] }` (explicit empty list).
481+ - `CustomSecretRotation` has `MinProperties=1` to prevent `custom : {}`.
465482- `tokenRequests.type` is immutable once set to `"Managed"` :
466483 - The `type` field cannot be changed from `"Managed"` back to `"Unmanaged"` (CEL
467484 transition rule on the struct : ` !has(oldSelf.type) || oldSelf.type != 'Managed' || self.type == 'Managed'` ).
468485 - The `tokenRequests` struct cannot be removed from `secretsStore` if its `type`
469486 was `"Managed"` (CEL rule on the parent struct prevents removal).
470487 - This is a one-way transition : once the operator takes ownership of `tokenRequests`,
471488 the administrator cannot revert to unmanaged mode. To clear WIF configuration,
472- set `type : " Managed " ` with ` managed.audiences` set to an empty list instead .
489+ set `managed.audiences` to an empty list (`audiences : []`) .
473490- `secretRotation` and `tokenRequests` are discriminated unions :
474491 - ` secretRotation.type` is the discriminator with values `"None"` (disabled) or `"Custom"` (enabled with config).
475492 - ` tokenRequests.type` is the discriminator with values `"Managed"` or `"Unmanaged"`.
@@ -544,10 +561,11 @@ reconciliation will trigger immediately when the administrator changes the
544561
545562# ### Default Behavior and Upgrade Safety
546563
547- All new fields will have defaults that match the operator's current hardcoded
548- behavior :
564+ All new fields use "no opinion" semantics when omitted — the operator applies
565+ defaults internally (not via CRD-level `+default`) :
549566- When `secretRotation` is omitted, the operator defaults to rotation enabled with a 2-minute poll interval
550- - When `secretRotation.type` is `"Custom"`, `rotationPollIntervalSeconds` defaults to `120`
567+ - When `secretRotation.type` is `"Custom"` and `rotationPollIntervalSeconds` is omitted,
568+ the operator chooses a reasonable default (currently 120 seconds)
551569- When `tokenRequests` is omitted, the operator preserves existing CSIDriver tokenRequests (Unmanaged behavior)
552570
553571Clusters upgrading to the new operator version with no `driverConfig` set will see
0 commit comments