Documentation
¶
Index ¶
- Constants
- func NewConditionController(instanceName string, provider Provider, deployer statemachine.Deployer, ...) factory.Controller
- func NewKMSPreflightController(instanceName string, provider Provider, ...) factory.Controller
- func NewKeyController(instanceName string, unsupportedConfigPrefix []string, provider Provider, ...) factory.Controller
- func NewMigrationController(instanceName string, provider Provider, deployer statemachine.Deployer, ...) factory.Controller
- func NewPruneController(instanceName string, provider Provider, deployer statemachine.Deployer, ...) factory.Controller
- func NewStateController(instanceName string, provider Provider, deployer statemachine.Deployer, ...) factory.Controller
- type KMSPreflightDeployer
- type Provider
Constants ¶
const ( // KMSPreflightConfigHashPodCondition carries the config hash the pod was // deployed for. The controller compares this against the required hash to // detect stale pods from a previous config. KMSPreflightConfigHashPodCondition corev1.PodConditionType = "KMSPreflightConfigHash" // KMSPreflightResultPodCondition carries the outcome of the preflight check. // Status True means the check passed; False means it failed, with details // in the condition message. KMSPreflightResultPodCondition corev1.PodConditionType = "KMSPreflightResult" // KMSPreflightKEKIDPodCondition carries the current key encryption key (KEK) // ID reported by the KMS plugin during the preflight evaluation. KMSPreflightKEKIDPodCondition corev1.PodConditionType = "KMSPreflightKekID" )
Pod readiness gate condition types set by the preflight checker running inside the pod. The checker PATCHes its own pod status with these conditions.
Variables ¶
This section is empty.
Functions ¶
func NewConditionController ¶
func NewConditionController( instanceName string, provider Provider, deployer statemachine.Deployer, preconditionsFulfilledFn preconditionsFulfilled, operatorClient operatorv1helpers.OperatorClient, apiServerConfigInformer configv1informers.APIServerInformer, kubeInformersForNamespaces operatorv1helpers.KubeInformersForNamespaces, secretClient corev1client.SecretsGetter, encryptionSecretSelector metav1.ListOptions, eventRecorder events.Recorder, ) factory.Controller
func NewKMSPreflightController ¶
func NewKMSPreflightController( instanceName string, provider Provider, preconditionsFulfilledFn preconditionsFulfilled, deployer KMSPreflightDeployer, operatorClient operatorv1helpers.OperatorClient, apiServerClient configv1client.APIServerInterface, apiServerInformer configv1informers.APIServerInformer, coreClient corev1client.CoreV1Interface, eventRecorder events.Recorder, ) factory.Controller
NewKMSPreflightController validates KMS configuration before a key is created.
Coordination with the key-controller:
The key-controller writes a hash of the current KMS config to operator status as the EncryptionKMSPreflightRequired condition (hash in the message). This controller reads that hash, runs preflight checks, and on success sets the EncryptionKMSPreflightSucceeded condition (same hash in the message). The key-controller waits for the two hashes to match before creating a key.
This is the same pattern used by the revision and installer controllers: the revision controller writes LatestAvailableRevision, the installer controller reads it and acts.
Without this protocol the following race can occur:
- Preflight passes for config A, hash A written to operator status.
- Key-controller reads hash A, starts creating a key for config A.
- Config changes to B.
- Preflight controller syncs, sees config B, does not yet see the key for A (key-controller is in the process of creating the key), runs preflight for B, overwrites status with hash B.
- The key created in step 2 was for config A but status now says B.
Letting the key-controller own EncryptionKMSPreflightRequired and this controller own EncryptionKMSPreflightSucceeded solves this. If the config changes mid-flight the key-controller posts a new hash and the preflight controller sees the mismatch and waits.
Example 1: config changes before key is created
- User creates KMS config A.
- Key-controller computes hash A, writes EncryptionKMSPreflightRequired=A.
- Preflight controller sees required=A, starts checking A.
- User changes config to A2 (minor variation, different hash).
- Key-controller computes hash A2, writes EncryptionKMSPreflightRequired=A2.
- Preflight controller sees required=A2, starts checking A2.
- Key-controller does not create a key until succeeded=A2.
Example 2: config changes after key is created
- User creates KMS config A.
- Key-controller computes hash A, writes EncryptionKMSPreflightRequired=A.
- Preflight controller checks A, succeeds, writes EncryptionKMSPreflightSucceeded=A.
- Key-controller sees required=A matches succeeded=A, creates key for A.
- User changes config to A2 (or B).
- Key-controller waits until the key for A completes the full cycle (read, write, migrated) before creating a new key. No preflight done at this stage.
Preflight workload:
A deployer interface abstracts the workload creation. Each operator provides its own implementation that knows how to install, get status, clean up the preflight workload, and wire the credentials needed to update pod status. The workload type matches the API server it validates (static pod for kas-o, Deployment for aggregated API servers).
When an existing KMS plugin is already configured, the checker runs the new plugin alongside the existing one to catch co-existence issues (e.g., metric port collisions). When no plugin is configured yet, it runs the new plugin alone. The sync method reads existing encryption key secrets to determine whether a plugin is already configured.
The pod uses readiness gates to post check results back to the controller. To set the readiness gate condition, the pod PATCHes its own status using credentials wired by the deployer. The controller reads these enhanced pod statuses to update its own operator status, which is propagated to end users.
After a successful check the preflight pod is kept for a short period (e.g. 1h) so that its logs can be inspected, then cleaned up by a subsequent sync.
func NewKeyController ¶
func NewKeyController( instanceName string, unsupportedConfigPrefix []string, provider Provider, deployer statemachine.Deployer, preconditionsFulfilledFn preconditionsFulfilled, operatorClient operatorv1helpers.OperatorClient, apiServerClient configv1client.APIServerInterface, apiServerInformer configv1informers.APIServerInformer, kubeInformersForNamespaces operatorv1helpers.KubeInformersForNamespaces, secretClient corev1client.SecretsGetter, configMapClient corev1client.ConfigMapsGetter, encryptionSecretSelector metav1.ListOptions, eventRecorder events.Recorder, ) factory.Controller
func NewMigrationController ¶
func NewMigrationController( instanceName string, provider Provider, deployer statemachine.Deployer, preconditionsFulfilledFn preconditionsFulfilled, migrator migrators.Migrator, operatorClient operatorv1helpers.OperatorClient, apiServerConfigInformer configv1informers.APIServerInformer, kubeInformersForNamespaces operatorv1helpers.KubeInformersForNamespaces, secretClient corev1client.SecretsGetter, encryptionSecretSelector metav1.ListOptions, eventRecorder events.Recorder, ) factory.Controller
func NewPruneController ¶
func NewPruneController( instanceName string, provider Provider, deployer statemachine.Deployer, preconditionsFulfilledFn preconditionsFulfilled, operatorClient operatorv1helpers.OperatorClient, apiServerConfigInformer configv1informers.APIServerInformer, kubeInformersForNamespaces operatorv1helpers.KubeInformersForNamespaces, secretClient corev1client.SecretsGetter, encryptionSecretSelector metav1.ListOptions, eventRecorder events.Recorder, ) factory.Controller
func NewStateController ¶
func NewStateController( instanceName string, provider Provider, deployer statemachine.Deployer, preconditionsFulfilledFn preconditionsFulfilled, operatorClient operatorv1helpers.OperatorClient, apiServerConfigInformer configv1informers.APIServerInformer, kubeInformersForNamespaces operatorv1helpers.KubeInformersForNamespaces, secretClient corev1client.SecretsGetter, encryptionSecretSelector metav1.ListOptions, eventRecorder events.Recorder, ) factory.Controller
Types ¶
type KMSPreflightDeployer ¶
type KMSPreflightDeployer interface {
// Deploy creates the preflight workload with the given config hash
// and encryption configuration. It is idempotent.
Deploy(ctx context.Context, configHash string, encryptionConfiguration *corev1.Secret) error
// Status returns the current pod status of the preflight workload.
// It returns an apierrors.IsNotFound error when no preflight pod exists.
Status(ctx context.Context) (corev1.PodStatus, error)
// Cleanup removes all resources created by Deploy.
Cleanup(ctx context.Context) error
}
KMSPreflightDeployer abstracts the lifecycle of a preflight workload that validates KMS plugin configuration before an encryption key is created. All methods are idempotent.
Deploy creates all resources the workload needs (ServiceAccount, Secret, RBAC, Pod). The controller only calls Deploy when Status reports no pod exists, so no running pod can be affected.
Cleanup removes all resources created by Deploy.
type Provider ¶
type Provider interface {
// EncryptedGRs returns resources that need to be encrypted
EncryptedGRs() []schema.GroupResource
// ShouldRunEncryptionControllers indicates whether external preconditions are satisfied so that encryption controllers can start synchronizing
ShouldRunEncryptionControllers() (bool, error)
}
Provider abstracts external dependencies and preconditions that need to be dynamic during a downgrade/upgrade