Package
Which package does this affect? [x] operator [x] crd [ ] docs
Problem / Motivation
selector.names est optionnel, et son absence a un comportement large et implicite :
// api/ferrvault/v1alpha1/secretspec_types.go
// Names is an explicit list of secret keys to sync. When empty, every
// secret in the vault is synced.
//
// +optional
Names []string `json:"names,omitempty"`
// internal/controller/ferrvaultsecret_controller.go:107
reveal, err = ffc.RevealFromVault(ctx, cr.Spec.Vault, cr.Spec.Selector.Names)
Combiné au motif habituel côté consommateur (envFrom: secretRef), toute clé présente dans la vault devient une variable d'environnement du pod. Un administrateur de cluster n'a aujourd'hui aucun moyen d'interdire ce cas.
Deux conséquences, la seconde étant la plus gênante :
-
Portée initiale trop large. Cas réel rencontré cette semaine sur l'instance FerrTrack interne : la vault ferrtrack, environnement internal, contient 9 clés. L'API n'a besoin que de JWT_ISSUER et JWT_SECRET ; les 7 autres sont les identifiants de la GitHub App, dont GITHUB_APP_PRIVATE_KEY_PEM. Sans selector, cette clé privée se retrouve dans l'environnement du pod de l'API.
-
Élargissement silencieux dans le temps. Ajouter une clé à la vault modifie l'environnement de tous les pods qui la consomment sans selector, sans changement de CR, sans diff, sans revue. Le rayon d'action d'un secret grandit hors du dépôt GitOps, ce qui est exactement ce qu'on cherche à éviter en le versionnant.
Le comportement actuel est un défaut raisonnable pour démarrer vite. Ce qui manque, c'est la possibilité de le refuser à l'échelle d'un cluster.
Proposed solution
Un flag d'opérateur, sur le modèle de --default-refresh-interval qui existe déjà :
--require-selector (défaut: false)
Quand il est actif, une FerrVaultSecret dont selector.names est vide n'est pas synchronisée. Le Secret cible n'est ni créé ni modifié, et la condition passe à :
Ready=False reason=SelectorRequired
message="selector.names is required (operator started with --require-selector)"
SelectorRequired s'aligne sur les motifs existants (MissingKeys, InvalidConnection, AuthFailed, ConnectionNotFound).
Le défaut reste false pour ne rien casser. Les clusters qui veulent la contrainte l'activent, et les CR existantes deviennent visiblement non conformes plutôt que de changer de comportement en silence.
Acceptance
- Avec
--require-selector, une FerrVaultSecret sans selector.names reste Ready=False avec reason=SelectorRequired, et le Secret cible n'est pas écrit.
- Sans le flag, le comportement actuel est strictement inchangé.
- Une
FerrVaultSecret avec un selector.names non vide se comporte pareil dans les deux modes.
- Un test couvre le passage de non conforme à conforme : ajouter le
selector fait repasser la CR en Ready=True sans redémarrage de l'opérateur.
Out of scope
- Rendre
selector obligatoire dans le schéma du CRD. Ce serait une rupture pour toutes les CR existantes et empêcherait le mode permissif.
- Une politique par connexion ou par namespace. Le flag global couvre le besoin ; un affinement pourra suivre s'il se révèle nécessaire.
Alternatives considered
Refus à l'admission plutôt qu'à la réconciliation. C'est la meilleure expérience utilisateur : kubectl apply échoue tout de suite au lieu de laisser une CR en Ready=False. Cela relève de #41, qui propose déjà un ValidatingWebhookConfiguration. Les deux sont complémentaires : le webhook attrape à l'écriture, le flag protège les clusters qui ne le déploient pas, et reste le filet quand une CR a été appliquée avant l'installation du webhook. Si #41 est implémenté d'abord, cette règle a naturellement sa place dedans, le flag servant alors à l'activer.
Avertissement sans blocage. Un simple log ou un événement quand selector est vide. Moins intrusif, mais sans effet réel : le cas problématique passe inaperçu jusqu'à l'audit.
Package
Which package does this affect? [x] operator [x] crd [ ] docs
Problem / Motivation
selector.namesest optionnel, et son absence a un comportement large et implicite :Combiné au motif habituel côté consommateur (
envFrom: secretRef), toute clé présente dans la vault devient une variable d'environnement du pod. Un administrateur de cluster n'a aujourd'hui aucun moyen d'interdire ce cas.Deux conséquences, la seconde étant la plus gênante :
Portée initiale trop large. Cas réel rencontré cette semaine sur l'instance FerrTrack interne : la vault
ferrtrack, environnementinternal, contient 9 clés. L'API n'a besoin que deJWT_ISSUERetJWT_SECRET; les 7 autres sont les identifiants de la GitHub App, dontGITHUB_APP_PRIVATE_KEY_PEM. Sansselector, cette clé privée se retrouve dans l'environnement du pod de l'API.Élargissement silencieux dans le temps. Ajouter une clé à la vault modifie l'environnement de tous les pods qui la consomment sans
selector, sans changement de CR, sans diff, sans revue. Le rayon d'action d'un secret grandit hors du dépôt GitOps, ce qui est exactement ce qu'on cherche à éviter en le versionnant.Le comportement actuel est un défaut raisonnable pour démarrer vite. Ce qui manque, c'est la possibilité de le refuser à l'échelle d'un cluster.
Proposed solution
Un flag d'opérateur, sur le modèle de
--default-refresh-intervalqui existe déjà :Quand il est actif, une
FerrVaultSecretdontselector.namesest vide n'est pas synchronisée. Le Secret cible n'est ni créé ni modifié, et la condition passe à :SelectorRequireds'aligne sur les motifs existants (MissingKeys,InvalidConnection,AuthFailed,ConnectionNotFound).Le défaut reste
falsepour ne rien casser. Les clusters qui veulent la contrainte l'activent, et les CR existantes deviennent visiblement non conformes plutôt que de changer de comportement en silence.Acceptance
--require-selector, uneFerrVaultSecretsansselector.namesresteReady=Falseavecreason=SelectorRequired, et le Secret cible n'est pas écrit.FerrVaultSecretavec unselector.namesnon vide se comporte pareil dans les deux modes.selectorfait repasser la CR enReady=Truesans redémarrage de l'opérateur.Out of scope
selectorobligatoire dans le schéma du CRD. Ce serait une rupture pour toutes les CR existantes et empêcherait le mode permissif.Alternatives considered
Refus à l'admission plutôt qu'à la réconciliation. C'est la meilleure expérience utilisateur :
kubectl applyéchoue tout de suite au lieu de laisser une CR enReady=False. Cela relève de #41, qui propose déjà unValidatingWebhookConfiguration. Les deux sont complémentaires : le webhook attrape à l'écriture, le flag protège les clusters qui ne le déploient pas, et reste le filet quand une CR a été appliquée avant l'installation du webhook. Si #41 est implémenté d'abord, cette règle a naturellement sa place dedans, le flag servant alors à l'activer.Avertissement sans blocage. Un simple log ou un événement quand
selectorest vide. Moins intrusif, mais sans effet réel : le cas problématique passe inaperçu jusqu'à l'audit.