diff --git a/config/v1/tests/apiservers.config.openshift.io/GenericKMSv2.yaml b/config/v1/tests/apiservers.config.openshift.io/GenericKMSv2.yaml new file mode 100644 index 00000000000..6aa781b1230 --- /dev/null +++ b/config/v1/tests/apiservers.config.openshift.io/GenericKMSv2.yaml @@ -0,0 +1,102 @@ +apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this +name: "APIServer GenericKMSv2 Validation" +crdName: apiservers.config.openshift.io +featureGates: +- KMSEncryption +tests: + onCreate: + - name: Should be able to create with valid GenericKMSv2 config + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: GenericKMSv2 + genericKMSv2: + operatorNamespace: vault-kms-operator + expected: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + audit: + profile: Default + encryption: + type: KMS + kms: + type: GenericKMSv2 + genericKMSv2: + operatorNamespace: vault-kms-operator + + - name: Should reject GenericKMSv2 type without genericKMSv2 config + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: GenericKMSv2 + expectedError: "genericKMSv2 config is required when kms provider type is GenericKMSv2" + + - name: Should reject genericKMSv2 config when type is Vault + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: Vault + genericKMSv2: + operatorNamespace: vault-kms-operator + vault: + kmsPluginImage: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + vaultAddress: https://vault.example.com:8200 + authentication: + type: AppRole + appRole: + secret: + name: vault-approle + vaultKeyPath: transit/keys/my-key + expectedError: "genericKMSv2 config is required when kms provider type is GenericKMSv2, and forbidden otherwise" + + - name: Should reject openshift-* operator namespace + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: GenericKMSv2 + genericKMSv2: + operatorNamespace: openshift-config + expectedError: "operatorNamespace must not be an openshift-* or kube-* system namespace" + + - name: Should reject kube-* operator namespace + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: GenericKMSv2 + genericKMSv2: + operatorNamespace: kube-system + expectedError: "operatorNamespace must not be an openshift-* or kube-* system namespace" + + - name: Should reject invalid operator namespace + initial: | + apiVersion: config.openshift.io/v1 + kind: APIServer + spec: + encryption: + type: KMS + kms: + type: GenericKMSv2 + genericKMSv2: + operatorNamespace: invalid_namespace! + expectedError: "operatorNamespace must be a valid DNS-1123 label" diff --git a/config/v1/types_kmsencryption.go b/config/v1/types_kmsencryption.go index e2f94ae1f37..22e20daafec 100644 --- a/config/v1/types_kmsencryption.go +++ b/config/v1/types_kmsencryption.go @@ -3,11 +3,14 @@ package v1 // KMSPluginConfig defines the configuration for the KMS instance // that will be used with KMS encryption // +kubebuilder:validation:XValidation:rule="self.type == 'Vault' ? has(self.vault) : !has(self.vault)",message="vault config is required when kms provider type is Vault, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="self.type == 'GenericKMSv2' ? has(self.genericKMSv2) : !has(self.genericKMSv2)",message="genericKMSv2 config is required when kms provider type is GenericKMSv2, and forbidden otherwise" // +union type KMSPluginConfig struct { // type defines the kind of platform for the KMS provider. - // Allowed values are Vault. + // Allowed values are Vault and GenericKMSv2. // When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + // When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + // operator installed in the referenced namespace. // // +unionDiscriminator // +required @@ -22,6 +25,17 @@ type KMSPluginConfig struct { // +optional Vault VaultKMSPluginConfig `json:"vault,omitempty,omitzero"` + // genericKMSv2 references an OLM-managed KMS provider operator. + // The operator publishes how to run the KMS plugin sidecar (container image and arguments). + // The platform handles deployment, lifecycle, and mounting credentials from Secrets and + // ConfigMaps in the operator namespace at well-known injection points referenced by the + // plugin arguments. + // This field must be set when type is GenericKMSv2, and must be unset otherwise. + // + // +unionMember + // +optional + GenericKMSv2 GenericKMSv2PluginConfig `json:"genericKMSv2,omitempty,omitzero"` + // --- TOMBSTONE --- // aws was a field that allowed configuring AWS KMS. // It was never implemented and has been removed. @@ -41,13 +55,17 @@ type KMSPluginConfig struct { // } // KMSProviderType is a specific supported KMS provider -// +kubebuilder:validation:Enum=Vault +// +kubebuilder:validation:Enum=Vault;GenericKMSv2 type KMSProviderType string const ( // VaultKMSProvider represents a supported KMS provider for use with HashiCorp Vault VaultKMSProvider KMSProviderType = "Vault" + // GenericKMSv2KMSProvider represents a KMS provider whose runtime configuration + // is supplied by an OLM-managed operator. + GenericKMSv2KMSProvider KMSProviderType = "GenericKMSv2" + // --- TOMBSTONE --- // AWSKMSProvider was a constant for AWS KMS support that was never implemented. // The constant name is reserved to prevent reuse. @@ -55,6 +73,27 @@ const ( // AWSKMSProvider KMSProviderType = "AWS" ) +// GenericKMSv2PluginConfig references a KMS provider operator installed via OLM. +type GenericKMSv2PluginConfig struct { + // operatorNamespace is the namespace where the KMS provider operator is installed. + // The platform reads the KMSPlugin resource named "cluster" from this namespace + // to determine the container image and arguments for the KMS plugin sidecar. + // + // Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + // in this namespace. The platform mounts them at well-known injection points + // during sidecar lifecycle management. + // + // The namespace must be a valid DNS-1123 label and must not be an openshift-* or + // kube-* system namespace. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:XValidation:rule="!format.dns1123Label().validate(self).hasValue()",message="operatorNamespace must be a valid DNS-1123 label" + // +kubebuilder:validation:XValidation:rule="!self.startsWith('openshift-') && !self.startsWith('kube-')",message="operatorNamespace must not be an openshift-* or kube-* system namespace" + // +required + OperatorNamespace string `json:"operatorNamespace,omitempty"` +} + // VaultSecretReference references a secret in the openshift-config namespace. type VaultSecretReference struct { // name is the metadata.name of the referenced secret in the openshift-config namespace. diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml index f3793fac61d..568d0603dce 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml index d06cd26ca79..831dc110fcb 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml index cce33594546..9b1a25b8236 100644 --- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml +++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/config/v1/zz_generated.deepcopy.go b/config/v1/zz_generated.deepcopy.go index 4b194b226a4..a4f64127d97 100644 --- a/config/v1/zz_generated.deepcopy.go +++ b/config/v1/zz_generated.deepcopy.go @@ -2808,6 +2808,22 @@ func (in *GenericControllerConfig) DeepCopy() *GenericControllerConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericKMSv2PluginConfig) DeepCopyInto(out *GenericKMSv2PluginConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericKMSv2PluginConfig. +func (in *GenericKMSv2PluginConfig) DeepCopy() *GenericKMSv2PluginConfig { + if in == nil { + return nil + } + out := new(GenericKMSv2PluginConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitHubIdentityProvider) DeepCopyInto(out *GitHubIdentityProvider) { *out = *in @@ -4066,6 +4082,7 @@ func (in *IntermediateTLSProfile) DeepCopy() *IntermediateTLSProfile { func (in *KMSPluginConfig) DeepCopyInto(out *KMSPluginConfig) { *out = *in out.Vault = in.Vault + out.GenericKMSv2 = in.GenericKMSv2 return } diff --git a/config/v1/zz_generated.featuregated-crd-manifests/apiservers.config.openshift.io/KMSEncryption.yaml b/config/v1/zz_generated.featuregated-crd-manifests/apiservers.config.openshift.io/KMSEncryption.yaml index 22c41067598..4cb259d9528 100644 --- a/config/v1/zz_generated.featuregated-crd-manifests/apiservers.config.openshift.io/KMSEncryption.yaml +++ b/config/v1/zz_generated.featuregated-crd-manifests/apiservers.config.openshift.io/KMSEncryption.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/config/v1/zz_generated.model_name.go b/config/v1/zz_generated.model_name.go index 043c03ef5ef..dd7ac655d6a 100644 --- a/config/v1/zz_generated.model_name.go +++ b/config/v1/zz_generated.model_name.go @@ -610,6 +610,11 @@ func (in GenericControllerConfig) OpenAPIModelName() string { return "com.github.openshift.api.config.v1.GenericControllerConfig" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in GenericKMSv2PluginConfig) OpenAPIModelName() string { + return "com.github.openshift.api.config.v1.GenericKMSv2PluginConfig" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in GitHubIdentityProvider) OpenAPIModelName() string { return "com.github.openshift.api.config.v1.GitHubIdentityProvider" diff --git a/config/v1/zz_generated.swagger_doc_generated.go b/config/v1/zz_generated.swagger_doc_generated.go index 12b839563ae..5e8ad9e0c77 100644 --- a/config/v1/zz_generated.swagger_doc_generated.go +++ b/config/v1/zz_generated.swagger_doc_generated.go @@ -2464,10 +2464,20 @@ func (Storage) SwaggerDoc() map[string]string { return map_Storage } +var map_GenericKMSv2PluginConfig = map[string]string{ + "": "GenericKMSv2PluginConfig references a KMS provider operator installed via OLM.", + "operatorNamespace": "operatorNamespace is the namespace where the KMS provider operator is installed. The platform reads the KMSPlugin resource named \"cluster\" from this namespace to determine the container image and arguments for the KMS plugin sidecar.\n\nSecrets and ConfigMaps referenced by the plugin arguments are expected to exist in this namespace. The platform mounts them at well-known injection points during sidecar lifecycle management.\n\nThe namespace must be a valid DNS-1123 label and must not be an openshift-* or kube-* system namespace.", +} + +func (GenericKMSv2PluginConfig) SwaggerDoc() map[string]string { + return map_GenericKMSv2PluginConfig +} + var map_KMSPluginConfig = map[string]string{ - "": "KMSPluginConfig defines the configuration for the KMS instance that will be used with KMS encryption", - "type": "type defines the kind of platform for the KMS provider. Allowed values are Vault. When set to Vault, the plugin connects to a HashiCorp Vault server for key management.", - "vault": "vault defines the configuration for the Vault KMS plugin. The plugin connects to a Vault Enterprise server that is managed by the user outside the purview of the control plane. This field must be set when type is Vault, and must be unset otherwise.", + "": "KMSPluginConfig defines the configuration for the KMS instance that will be used with KMS encryption", + "type": "type defines the kind of platform for the KMS provider. Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider operator installed in the referenced namespace.", + "vault": "vault defines the configuration for the Vault KMS plugin. The plugin connects to a Vault Enterprise server that is managed by the user outside the purview of the control plane. This field must be set when type is Vault, and must be unset otherwise.", + "genericKMSv2": "genericKMSv2 references an OLM-managed KMS provider operator. The operator publishes how to run the KMS plugin sidecar (container image and arguments). The platform handles deployment, lifecycle, and mounting credentials from Secrets and ConfigMaps in the operator namespace at well-known injection points referenced by the plugin arguments. This field must be set when type is GenericKMSv2, and must be unset otherwise.", } func (KMSPluginConfig) SwaggerDoc() map[string]string { diff --git a/install.go b/install.go index 6efcc1c2986..97e1739a7bf 100644 --- a/install.go +++ b/install.go @@ -57,6 +57,7 @@ import ( "github.com/openshift/api/image" "github.com/openshift/api/imageregistry" "github.com/openshift/api/kubecontrolplane" + "github.com/openshift/api/kms" "github.com/openshift/api/machine" "github.com/openshift/api/monitoring" "github.com/openshift/api/network" @@ -94,6 +95,7 @@ var ( image.Install, imageregistry.Install, kubecontrolplane.Install, + kms.Install, cloudnetwork.Install, network.Install, networkoperator.Install, diff --git a/kms/install.go b/kms/install.go new file mode 100644 index 00000000000..56ea78893c5 --- /dev/null +++ b/kms/install.go @@ -0,0 +1,26 @@ +package kms + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + kmsv1alpha1 "github.com/openshift/api/kms/v1alpha1" +) + +const ( + GroupName = "kms.openshift.io" +) + +var ( + schemeBuilder = runtime.NewSchemeBuilder(kmsv1alpha1.Install) + // Install is a function which adds every version of this group to a scheme + Install = schemeBuilder.AddToScheme +) + +func Resource(resource string) schema.GroupResource { + return schema.GroupResource{Group: GroupName, Resource: resource} +} + +func Kind(kind string) schema.GroupKind { + return schema.GroupKind{Group: GroupName, Kind: kind} +} diff --git a/kms/v1alpha1/Makefile b/kms/v1alpha1/Makefile new file mode 100644 index 00000000000..072507d54a8 --- /dev/null +++ b/kms/v1alpha1/Makefile @@ -0,0 +1,3 @@ +.PHONY: test +test: + make -C ../../tests test GINKGO_EXTRA_ARGS=--focus="kms.openshift.io/v1alpha1" diff --git a/kms/v1alpha1/doc.go b/kms/v1alpha1/doc.go new file mode 100644 index 00000000000..42e9d6adea4 --- /dev/null +++ b/kms/v1alpha1/doc.go @@ -0,0 +1,7 @@ +// +k8s:deepcopy-gen=package,register +// +k8s:defaulter-gen=TypeMeta +// +k8s:openapi-gen=true +// +k8s:openapi-model-package=com.github.openshift.api.kms.v1alpha1 + +// +groupName=kms.openshift.io +package v1alpha1 diff --git a/kms/v1alpha1/register.go b/kms/v1alpha1/register.go new file mode 100644 index 00000000000..5f400e2b6f6 --- /dev/null +++ b/kms/v1alpha1/register.go @@ -0,0 +1,39 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + GroupName = "kms.openshift.io" + GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // Install is a function which adds this version to a scheme + Install = schemeBuilder.AddToScheme + + // SchemeGroupVersion generated code relies on this name + // Deprecated + SchemeGroupVersion = GroupVersion + // AddToScheme exists solely to keep the old generators creating valid code + // DEPRECATED + AddToScheme = schemeBuilder.AddToScheme +) + +// Resource generated code relies on this being here, but it logically belongs to the group +// DEPRECATED +func Resource(resource string) schema.GroupResource { + return schema.GroupResource{Group: GroupName, Resource: resource} +} + +func addKnownTypes(scheme *runtime.Scheme) error { + metav1.AddToGroupVersion(scheme, GroupVersion) + + scheme.AddKnownTypes(GroupVersion, + &KMSPlugin{}, + &KMSPluginList{}, + ) + + return nil +} diff --git a/kms/v1alpha1/tests/kmsplugins.kms.openshift.io/KMSPlugin.yaml b/kms/v1alpha1/tests/kmsplugins.kms.openshift.io/KMSPlugin.yaml new file mode 100644 index 00000000000..7281e1da7d7 --- /dev/null +++ b/kms/v1alpha1/tests/kmsplugins.kms.openshift.io/KMSPlugin.yaml @@ -0,0 +1,197 @@ +apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this +name: "KMSPlugin" +crdName: kmsplugins.kms.openshift.io +featureGates: +- KMSEncryption +tests: + onCreate: + - name: Should be able to create a minimal KMSPlugin named cluster + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + expected: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + + - name: Should reject KMSPlugin without cluster name + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: not-cluster + namespace: vault-kms-operator + expectedError: "kmsplugin is a singleton per namespace, .metadata.name must be 'cluster'" + + onUpdate: + - name: Should accept valid runtime configuration in status + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-vault-address=https://vault.example.com:8200" + - "-vault-key-path=transit/keys/my-key" + - "-approle-secret-id-path=/var/run/kms/secrets/vault-approle/secret-id" + - "-tls-ca-file=/var/run/kms/config/vault-ca-bundle/ca-bundle.crt" + secrets: + - name: vault-approle + configMaps: + - name: vault-ca-bundle + expected: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-vault-address=https://vault.example.com:8200" + - "-vault-key-path=transit/keys/my-key" + - "-approle-secret-id-path=/var/run/kms/secrets/vault-approle/secret-id" + - "-tls-ca-file=/var/run/kms/config/vault-ca-bundle/ca-bundle.crt" + secrets: + - name: vault-approle + configMaps: + - name: vault-ca-bundle + + - name: Should reject runtime image with tag instead of digest + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin:latest + args: + - "-vault-address=https://vault.example.com:8200" + expectedStatusError: "the OCI Image reference must end with a valid '@sha256:' suffix" + + - name: Should reject runtime args containing combined listen-address flag + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-listen-address=unix:///tmp/kms.sock" + expectedStatusError: "args must not include -listen-address; the platform injects this argument" + + - name: Should reject runtime args containing split listen-address flag + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-listen-address" + - "unix:///tmp/kms.sock" + expectedStatusError: "args must not include -listen-address; the platform injects this argument" + + - name: Should reject runtime without args + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + expectedStatusError: "Required value" + + - name: Should reject invalid secret name in runtime + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-vault-address=https://vault.example.com:8200" + secrets: + - name: invalid_secret_name! + expectedStatusError: "name must be a valid DNS subdomain name" + + - name: Should reject invalid configMap name in runtime + initial: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + updated: | + apiVersion: kms.openshift.io/v1alpha1 + kind: KMSPlugin + metadata: + name: cluster + namespace: vault-kms-operator + status: + runtime: + image: registry.example.com/vault-plugin@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + args: + - "-vault-address=https://vault.example.com:8200" + configMaps: + - name: invalid_configmap! + expectedStatusError: "name must be a valid DNS subdomain name" diff --git a/kms/v1alpha1/types_kmsplugin.go b/kms/v1alpha1/types_kmsplugin.go new file mode 100644 index 00000000000..760dc6c85d9 --- /dev/null +++ b/kms/v1alpha1/types_kmsplugin.go @@ -0,0 +1,160 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:path=kmsplugins,scope=Namespaced +// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'cluster'",message="kmsplugin is a singleton per namespace, .metadata.name must be 'cluster'" +// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/TBD +// +openshift:file-pattern=cvoRunLevel=0000_20,operatorName=kube-apiserver,operatorOrdering=02 +// +openshift:compatibility-gen:level=4 +// +openshift:enable:FeatureGate=KMSEncryption + +// KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. +// A KMS provider operator installed via OLM reconciles provider-specific configuration +// and publishes the container runtime configuration in status.runtime. +// +// Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support. +type KMSPlugin struct { + metav1.TypeMeta `json:",inline"` + + // metadata is the standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +required + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec is reserved for future use. + // Operators publish runtime configuration in status.runtime. + // +optional + Spec *KMSPluginSpec `json:"spec,omitempty"` + + // status is the most recently observed status of the KMSPlugin. + // +optional + Status *KMSPluginStatus `json:"status,omitempty"` +} + +// KMSPluginSpec is reserved for future use. +// +kubebuilder:validation:MinProperties=0 +type KMSPluginSpec struct{} + +// KMSPluginStatus defines the observed status of KMSPlugin. +// +kubebuilder:validation:MinProperties=0 +type KMSPluginStatus struct { + // runtime describes how the platform should run the KMS plugin sidecar. + // The KMS provider operator must populate this before the platform can deploy + // the plugin. When omitted, the platform cannot proceed with KMS encryption. + // + // +optional + Runtime KMSPluginRuntime `json:"runtime,omitempty,omitzero"` +} + +// KMSPluginRuntime describes the container configuration for a KMS plugin sidecar. +// The platform injects -listen-address and manages lifecycle, resources, security context, +// and mounting Secrets and ConfigMaps from the operator namespace at well-known injection points. +// Operators must not set -listen-address in args, either as -listen-address= +// or as a separate -listen-address flag. +// +// +kubebuilder:validation:XValidation:rule="self.args.all(a, a != '-listen-address' && !a.startsWith('-listen-address='))",message="args must not include -listen-address; the platform injects this argument" +type KMSPluginRuntime struct { + // image is the digest-pinned OCI image for the KMS plugin. + // + // The image must be a fully qualified OCI image pull spec with a SHA256 digest. + // The format is: host[:port][/namespace]/name@sha256: + // where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. + // The total length must be between 75 and 447 characters. + // + // Short names (e.g., "vault-plugin" or "hashicorp/vault-plugin") are not allowed. + // The registry hostname must be included and must contain at least one dot. + // Image tags (e.g., ":latest", ":v1.0.0") are not allowed. + // + // +kubebuilder:validation:MinLength=75 + // +kubebuilder:validation:MaxLength=447 + // +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:' suffix, where '' is 64 characters long" + // +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme. Short names are not allowed, the registry hostname must be included." + // +required + Image string `json:"image,omitempty"` + + // args are the command-line arguments passed to the KMS plugin container. + // The platform prepends -listen-address= before these arguments. + // Arguments may reference credential files mounted by the platform at well-known + // injection points under /var/run/kms/ from Secrets and ConfigMaps in the + // operator namespace. + // + // +required + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=64 + // +kubebuilder:validation:items:MinLength=1 + // +kubebuilder:validation:items:MaxLength=4096 + Args []string `json:"args,omitempty"` + + // secrets lists Secrets in the same namespace as the KMSPlugin that the platform + // mounts at well-known injection points under /var/run/kms/secrets/. + // Plugin arguments may reference files from these mounted Secrets. + // When omitted, no Secrets are mounted. + // + // +optional + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + Secrets []KMSPluginSecretReference `json:"secrets,omitempty"` + + // configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform + // mounts at well-known injection points under /var/run/kms/config/. + // Plugin arguments may reference files from these mounted ConfigMaps. + // When omitted, no ConfigMaps are mounted. + // + // +optional + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + ConfigMaps []KMSPluginConfigMapReference `json:"configMaps,omitempty"` +} + +// KMSPluginSecretReference references a Secret in the same namespace as the KMSPlugin. +type KMSPluginSecretReference struct { + // name is the metadata.name of the referenced Secret. + // The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + // contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]([a-z0-9\\\\-]*[a-z0-9])?(\\\\.[a-z0-9]([a-z0-9\\\\-]*[a-z0-9])?)*$')",message="name must be a valid DNS subdomain name: contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character" + // +required + Name string `json:"name,omitempty"` +} + +// KMSPluginConfigMapReference references a ConfigMap in the same namespace as the KMSPlugin. +type KMSPluginConfigMapReference struct { + // name is the metadata.name of the referenced ConfigMap. + // The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + // contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]([a-z0-9\\\\-]*[a-z0-9])?(\\\\.[a-z0-9]([a-z0-9\\\\-]*[a-z0-9])?)*$')",message="name must be a valid DNS subdomain name: contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character" + // +required + Name string `json:"name,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +openshift:compatibility-gen:level=4 + +// KMSPluginList contains a list of KMSPlugins. +// +// Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support. +type KMSPluginList struct { + metav1.TypeMeta `json:",inline"` + + // metadata is the standard list's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + metav1.ListMeta `json:"metadata,omitempty"` + + // items is the list of KMSPlugins. + Items []KMSPlugin `json:"items"` +} diff --git a/kms/v1alpha1/zz_generated.crd-manifests/0000_20_kube-apiserver_02_kmsplugins.crd.yaml b/kms/v1alpha1/zz_generated.crd-manifests/0000_20_kube-apiserver_02_kmsplugins.crd.yaml new file mode 100644 index 00000000000..574ffc34889 --- /dev/null +++ b/kms/v1alpha1/zz_generated.crd-manifests/0000_20_kube-apiserver_02_kmsplugins.crd.yaml @@ -0,0 +1,182 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/TBD + api.openshift.io/merged-by-featuregates: "true" + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + release.openshift.io/feature-set: CustomNoUpgrade,DevPreviewNoUpgrade,TechPreviewNoUpgrade + name: kmsplugins.kms.openshift.io +spec: + group: kms.openshift.io + names: + kind: KMSPlugin + listKind: KMSPluginList + plural: kmsplugins + singular: kmsplugin + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. + A KMS provider operator installed via OLM reconciles provider-specific configuration + and publishes the container runtime configuration in status.runtime. + + Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + spec is reserved for future use. + Operators publish runtime configuration in status.runtime. + minProperties: 0 + type: object + status: + description: status is the most recently observed status of the KMSPlugin. + minProperties: 0 + properties: + runtime: + description: |- + runtime describes how the platform should run the KMS plugin sidecar. + The KMS provider operator must populate this before the platform can deploy + the plugin. When omitted, the platform cannot proceed with KMS encryption. + properties: + args: + description: |- + args are the command-line arguments passed to the KMS plugin container. + The platform prepends -listen-address= before these arguments. + Arguments may reference credential files mounted by the platform at well-known + injection points under /var/run/kms/ from Secrets and ConfigMaps in the + operator namespace. + items: + maxLength: 4096 + minLength: 1 + type: string + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + configMaps: + description: |- + configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform + mounts at well-known injection points under /var/run/kms/config/. + Plugin arguments may reference files from these mounted ConfigMaps. + When omitted, no ConfigMaps are mounted. + items: + description: KMSPluginConfigMapReference references a ConfigMap + in the same namespace as the KMSPlugin. + properties: + name: + description: |- + name is the metadata.name of the referenced ConfigMap. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain + no more than 253 characters, contain only lowercase + alphanumeric characters, ''-'' or ''.'', and start and + end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)*$') + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + image: + description: |- + image is the digest-pinned OCI image for the KMS plugin. + + The image must be a fully qualified OCI image pull spec with a SHA256 digest. + The format is: host[:port][/namespace]/name@sha256: + where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. + The total length must be between 75 and 447 characters. + + Short names (e.g., "vault-plugin" or "hashicorp/vault-plugin") are not allowed. + The registry hostname must be included and must contain at least one dot. + Image tags (e.g., ":latest", ":v1.0.0") are not allowed. + maxLength: 447 + minLength: 75 + type: string + x-kubernetes-validations: + - message: the OCI Image reference must end with a valid '@sha256:' + suffix, where '' is 64 characters long + rule: (self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$')) + - message: the OCI Image name should follow the host[:port][/namespace]/name + format, resembling a valid URL without the scheme. Short names + are not allowed, the registry hostname must be included. + rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$')) + secrets: + description: |- + secrets lists Secrets in the same namespace as the KMSPlugin that the platform + mounts at well-known injection points under /var/run/kms/secrets/. + Plugin arguments may reference files from these mounted Secrets. + When omitted, no Secrets are mounted. + items: + description: KMSPluginSecretReference references a Secret in + the same namespace as the KMSPlugin. + properties: + name: + description: |- + name is the metadata.name of the referenced Secret. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain + no more than 253 characters, contain only lowercase + alphanumeric characters, ''-'' or ''.'', and start and + end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)*$') + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - args + - image + type: object + x-kubernetes-validations: + - message: args must not include -listen-address; the platform injects + this argument + rule: self.args.all(a, a != '-listen-address' && !a.startsWith('-listen-address=')) + type: object + required: + - metadata + type: object + x-kubernetes-validations: + - message: kmsplugin is a singleton per namespace, .metadata.name must be + 'cluster' + rule: self.metadata.name == 'cluster' + served: true + storage: true + subresources: + status: {} diff --git a/kms/v1alpha1/zz_generated.crd-manifests/doc.go b/kms/v1alpha1/zz_generated.crd-manifests/doc.go new file mode 100644 index 00000000000..073f7c45a1c --- /dev/null +++ b/kms/v1alpha1/zz_generated.crd-manifests/doc.go @@ -0,0 +1 @@ +package kms_v1alpha1_crdmanifests diff --git a/kms/v1alpha1/zz_generated.deepcopy.go b/kms/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..0da8daa6985 --- /dev/null +++ b/kms/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,175 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by codegen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPlugin) DeepCopyInto(out *KMSPlugin) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(KMSPluginSpec) + **out = **in + } + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(KMSPluginStatus) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPlugin. +func (in *KMSPlugin) DeepCopy() *KMSPlugin { + if in == nil { + return nil + } + out := new(KMSPlugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KMSPlugin) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginConfigMapReference) DeepCopyInto(out *KMSPluginConfigMapReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginConfigMapReference. +func (in *KMSPluginConfigMapReference) DeepCopy() *KMSPluginConfigMapReference { + if in == nil { + return nil + } + out := new(KMSPluginConfigMapReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginList) DeepCopyInto(out *KMSPluginList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KMSPlugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginList. +func (in *KMSPluginList) DeepCopy() *KMSPluginList { + if in == nil { + return nil + } + out := new(KMSPluginList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KMSPluginList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginRuntime) DeepCopyInto(out *KMSPluginRuntime) { + *out = *in + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]KMSPluginSecretReference, len(*in)) + copy(*out, *in) + } + if in.ConfigMaps != nil { + in, out := &in.ConfigMaps, &out.ConfigMaps + *out = make([]KMSPluginConfigMapReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginRuntime. +func (in *KMSPluginRuntime) DeepCopy() *KMSPluginRuntime { + if in == nil { + return nil + } + out := new(KMSPluginRuntime) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginSecretReference) DeepCopyInto(out *KMSPluginSecretReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginSecretReference. +func (in *KMSPluginSecretReference) DeepCopy() *KMSPluginSecretReference { + if in == nil { + return nil + } + out := new(KMSPluginSecretReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginSpec) DeepCopyInto(out *KMSPluginSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginSpec. +func (in *KMSPluginSpec) DeepCopy() *KMSPluginSpec { + if in == nil { + return nil + } + out := new(KMSPluginSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KMSPluginStatus) DeepCopyInto(out *KMSPluginStatus) { + *out = *in + in.Runtime.DeepCopyInto(&out.Runtime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KMSPluginStatus. +func (in *KMSPluginStatus) DeepCopy() *KMSPluginStatus { + if in == nil { + return nil + } + out := new(KMSPluginStatus) + in.DeepCopyInto(out) + return out +} diff --git a/kms/v1alpha1/zz_generated.featuregated-crd-manifests.yaml b/kms/v1alpha1/zz_generated.featuregated-crd-manifests.yaml new file mode 100644 index 00000000000..074f424825a --- /dev/null +++ b/kms/v1alpha1/zz_generated.featuregated-crd-manifests.yaml @@ -0,0 +1,23 @@ +kmsplugins.kms.openshift.io: + Annotations: {} + ApprovedPRNumber: https://github.com/openshift/api/pull/TBD + CRDName: kmsplugins.kms.openshift.io + Capability: "" + Category: "" + FeatureGates: + - KMSEncryption + FilenameOperatorName: kube-apiserver + FilenameOperatorOrdering: "02" + FilenameRunLevel: "0000_20" + GroupName: kms.openshift.io + HasStatus: true + KindName: KMSPlugin + Labels: {} + PluralName: kmsplugins + PrinterColumns: [] + Scope: Namespaced + ShortNames: null + TopLevelFeatureGates: + - KMSEncryption + Version: v1alpha1 + diff --git a/kms/v1alpha1/zz_generated.featuregated-crd-manifests/kmsplugins.kms.openshift.io/KMSEncryption.yaml b/kms/v1alpha1/zz_generated.featuregated-crd-manifests/kmsplugins.kms.openshift.io/KMSEncryption.yaml new file mode 100644 index 00000000000..a28b3a796e3 --- /dev/null +++ b/kms/v1alpha1/zz_generated.featuregated-crd-manifests/kmsplugins.kms.openshift.io/KMSEncryption.yaml @@ -0,0 +1,182 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/TBD + api.openshift.io/filename-cvo-runlevel: "0000_20" + api.openshift.io/filename-operator: kube-apiserver + api.openshift.io/filename-ordering: "02" + feature-gate.release.openshift.io/KMSEncryption: "true" + name: kmsplugins.kms.openshift.io +spec: + group: kms.openshift.io + names: + kind: KMSPlugin + listKind: KMSPluginList + plural: kmsplugins + singular: kmsplugin + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. + A KMS provider operator installed via OLM reconciles provider-specific configuration + and publishes the container runtime configuration in status.runtime. + + Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + spec is reserved for future use. + Operators publish runtime configuration in status.runtime. + minProperties: 0 + type: object + status: + description: status is the most recently observed status of the KMSPlugin. + minProperties: 0 + properties: + runtime: + description: |- + runtime describes how the platform should run the KMS plugin sidecar. + The KMS provider operator must populate this before the platform can deploy + the plugin. When omitted, the platform cannot proceed with KMS encryption. + properties: + args: + description: |- + args are the command-line arguments passed to the KMS plugin container. + The platform prepends -listen-address= before these arguments. + Arguments may reference credential files mounted by the platform at well-known + injection points under /var/run/kms/ from Secrets and ConfigMaps in the + operator namespace. + items: + maxLength: 4096 + minLength: 1 + type: string + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + configMaps: + description: |- + configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform + mounts at well-known injection points under /var/run/kms/config/. + Plugin arguments may reference files from these mounted ConfigMaps. + When omitted, no ConfigMaps are mounted. + items: + description: KMSPluginConfigMapReference references a ConfigMap + in the same namespace as the KMSPlugin. + properties: + name: + description: |- + name is the metadata.name of the referenced ConfigMap. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain + no more than 253 characters, contain only lowercase + alphanumeric characters, ''-'' or ''.'', and start and + end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)*$') + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + image: + description: |- + image is the digest-pinned OCI image for the KMS plugin. + + The image must be a fully qualified OCI image pull spec with a SHA256 digest. + The format is: host[:port][/namespace]/name@sha256: + where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. + The total length must be between 75 and 447 characters. + + Short names (e.g., "vault-plugin" or "hashicorp/vault-plugin") are not allowed. + The registry hostname must be included and must contain at least one dot. + Image tags (e.g., ":latest", ":v1.0.0") are not allowed. + maxLength: 447 + minLength: 75 + type: string + x-kubernetes-validations: + - message: the OCI Image reference must end with a valid '@sha256:' + suffix, where '' is 64 characters long + rule: (self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$')) + - message: the OCI Image name should follow the host[:port][/namespace]/name + format, resembling a valid URL without the scheme. Short names + are not allowed, the registry hostname must be included. + rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$')) + secrets: + description: |- + secrets lists Secrets in the same namespace as the KMSPlugin that the platform + mounts at well-known injection points under /var/run/kms/secrets/. + Plugin arguments may reference files from these mounted Secrets. + When omitted, no Secrets are mounted. + items: + description: KMSPluginSecretReference references a Secret in + the same namespace as the KMSPlugin. + properties: + name: + description: |- + name is the metadata.name of the referenced Secret. + The name must be a valid DNS subdomain name: it must contain no more than 253 characters, + contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'name must be a valid DNS subdomain name: contain + no more than 253 characters, contain only lowercase + alphanumeric characters, ''-'' or ''.'', and start and + end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)*$') + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + required: + - args + - image + type: object + x-kubernetes-validations: + - message: args must not include -listen-address; the platform injects + this argument + rule: self.args.all(a, a != '-listen-address' && !a.startsWith('-listen-address=')) + type: object + required: + - metadata + type: object + x-kubernetes-validations: + - message: kmsplugin is a singleton per namespace, .metadata.name must be + 'cluster' + rule: self.metadata.name == 'cluster' + served: true + storage: true + subresources: + status: {} diff --git a/kms/v1alpha1/zz_generated.model_name.go b/kms/v1alpha1/zz_generated.model_name.go new file mode 100644 index 00000000000..abdc538df9c --- /dev/null +++ b/kms/v1alpha1/zz_generated.model_name.go @@ -0,0 +1,41 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by codegen. DO NOT EDIT. + +package v1alpha1 + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPlugin) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPlugin" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginConfigMapReference) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginConfigMapReference" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginList) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginList" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginRuntime) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginRuntime" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginSecretReference) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginSecretReference" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginSpec) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginSpec" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in KMSPluginStatus) OpenAPIModelName() string { + return "com.github.openshift.api.kms.v1alpha1.KMSPluginStatus" +} diff --git a/kms/v1alpha1/zz_generated.swagger_doc_generated.go b/kms/v1alpha1/zz_generated.swagger_doc_generated.go new file mode 100644 index 00000000000..b754d6325fd --- /dev/null +++ b/kms/v1alpha1/zz_generated.swagger_doc_generated.go @@ -0,0 +1,82 @@ +package v1alpha1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE +var map_KMSPlugin = map[string]string{ + "": "KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. A KMS provider operator installed via OLM reconciles provider-specific configuration and publishes the container runtime configuration in status.runtime.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + "metadata": "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "spec": "spec is reserved for future use. Operators publish runtime configuration in status.runtime.", + "status": "status is the most recently observed status of the KMSPlugin.", +} + +func (KMSPlugin) SwaggerDoc() map[string]string { + return map_KMSPlugin +} + +var map_KMSPluginConfigMapReference = map[string]string{ + "": "KMSPluginConfigMapReference references a ConfigMap in the same namespace as the KMSPlugin.", + "name": "name is the metadata.name of the referenced ConfigMap. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", +} + +func (KMSPluginConfigMapReference) SwaggerDoc() map[string]string { + return map_KMSPluginConfigMapReference +} + +var map_KMSPluginList = map[string]string{ + "": "KMSPluginList contains a list of KMSPlugins.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + "metadata": "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "items": "items is the list of KMSPlugins.", +} + +func (KMSPluginList) SwaggerDoc() map[string]string { + return map_KMSPluginList +} + +var map_KMSPluginRuntime = map[string]string{ + "": "KMSPluginRuntime describes the container configuration for a KMS plugin sidecar. The platform injects -listen-address and manages lifecycle, resources, security context, and mounting Secrets and ConfigMaps from the operator namespace at well-known injection points. Operators must not set -listen-address in args, either as -listen-address= or as a separate -listen-address flag.", + "image": "image is the digest-pinned OCI image for the KMS plugin.\n\nThe image must be a fully qualified OCI image pull spec with a SHA256 digest. The format is: host[:port][/namespace]/name@sha256: where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. The total length must be between 75 and 447 characters.\n\nShort names (e.g., \"vault-plugin\" or \"hashicorp/vault-plugin\") are not allowed. The registry hostname must be included and must contain at least one dot. Image tags (e.g., \":latest\", \":v1.0.0\") are not allowed.", + "args": "args are the command-line arguments passed to the KMS plugin container. The platform prepends -listen-address= before these arguments. Arguments may reference credential files mounted by the platform at well-known injection points under /var/run/kms/ from Secrets and ConfigMaps in the operator namespace.", + "secrets": "secrets lists Secrets in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/secrets/. Plugin arguments may reference files from these mounted Secrets. When omitted, no Secrets are mounted.", + "configMaps": "configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/config/. Plugin arguments may reference files from these mounted ConfigMaps. When omitted, no ConfigMaps are mounted.", +} + +func (KMSPluginRuntime) SwaggerDoc() map[string]string { + return map_KMSPluginRuntime +} + +var map_KMSPluginSecretReference = map[string]string{ + "": "KMSPluginSecretReference references a Secret in the same namespace as the KMSPlugin.", + "name": "name is the metadata.name of the referenced Secret. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", +} + +func (KMSPluginSecretReference) SwaggerDoc() map[string]string { + return map_KMSPluginSecretReference +} + +var map_KMSPluginSpec = map[string]string{ + "": "KMSPluginSpec is reserved for future use.", +} + +func (KMSPluginSpec) SwaggerDoc() map[string]string { + return map_KMSPluginSpec +} + +var map_KMSPluginStatus = map[string]string{ + "": "KMSPluginStatus defines the observed status of KMSPlugin.", + "runtime": "runtime describes how the platform should run the KMS plugin sidecar. The KMS provider operator must populate this before the platform can deploy the plugin. When omitted, the platform cannot proceed with KMS encryption.", +} + +func (KMSPluginStatus) SwaggerDoc() map[string]string { + return map_KMSPluginStatus +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index d884f92cfbd..38969212bab 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -25,6 +25,7 @@ import ( insightsv1 "github.com/openshift/api/insights/v1" insightsv1alpha1 "github.com/openshift/api/insights/v1alpha1" insightsv1alpha2 "github.com/openshift/api/insights/v1alpha2" + kmsv1alpha1 "github.com/openshift/api/kms/v1alpha1" kubecontrolplanev1 "github.com/openshift/api/kubecontrolplane/v1" legacyconfigv1 "github.com/openshift/api/legacyconfig/v1" machinev1 "github.com/openshift/api/machine/v1" @@ -323,6 +324,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA configv1.Gatherers{}.OpenAPIModelName(): schema_openshift_api_config_v1_Gatherers(ref), configv1.GenericAPIServerConfig{}.OpenAPIModelName(): schema_openshift_api_config_v1_GenericAPIServerConfig(ref), configv1.GenericControllerConfig{}.OpenAPIModelName(): schema_openshift_api_config_v1_GenericControllerConfig(ref), + configv1.GenericKMSv2PluginConfig{}.OpenAPIModelName(): schema_openshift_api_config_v1_GenericKMSv2PluginConfig(ref), configv1.GitHubIdentityProvider{}.OpenAPIModelName(): schema_openshift_api_config_v1_GitHubIdentityProvider(ref), configv1.GitLabIdentityProvider{}.OpenAPIModelName(): schema_openshift_api_config_v1_GitLabIdentityProvider(ref), configv1.GoogleIdentityProvider{}.OpenAPIModelName(): schema_openshift_api_config_v1_GoogleIdentityProvider(ref), @@ -778,6 +780,13 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA insightsv1alpha2.PersistentVolumeClaimReference{}.OpenAPIModelName(): schema_openshift_api_insights_v1alpha2_PersistentVolumeClaimReference(ref), insightsv1alpha2.PersistentVolumeConfig{}.OpenAPIModelName(): schema_openshift_api_insights_v1alpha2_PersistentVolumeConfig(ref), insightsv1alpha2.Storage{}.OpenAPIModelName(): schema_openshift_api_insights_v1alpha2_Storage(ref), + kmsv1alpha1.KMSPlugin{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPlugin(ref), + kmsv1alpha1.KMSPluginConfigMapReference{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginConfigMapReference(ref), + kmsv1alpha1.KMSPluginList{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginList(ref), + kmsv1alpha1.KMSPluginRuntime{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginRuntime(ref), + kmsv1alpha1.KMSPluginSecretReference{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginSecretReference(ref), + kmsv1alpha1.KMSPluginSpec{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginSpec(ref), + kmsv1alpha1.KMSPluginStatus{}.OpenAPIModelName(): schema_openshift_api_kms_v1alpha1_KMSPluginStatus(ref), kubecontrolplanev1.AggregatorConfig{}.OpenAPIModelName(): schema_openshift_api_kubecontrolplane_v1_AggregatorConfig(ref), kubecontrolplanev1.KubeAPIServerConfig{}.OpenAPIModelName(): schema_openshift_api_kubecontrolplane_v1_KubeAPIServerConfig(ref), kubecontrolplanev1.KubeAPIServerImagePolicyConfig{}.OpenAPIModelName(): schema_openshift_api_kubecontrolplane_v1_KubeAPIServerImagePolicyConfig(ref), @@ -14439,6 +14448,27 @@ func schema_openshift_api_config_v1_GenericControllerConfig(ref common.Reference } } +func schema_openshift_api_config_v1_GenericKMSv2PluginConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GenericKMSv2PluginConfig references a KMS provider operator installed via OLM.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "operatorNamespace": { + SchemaProps: spec.SchemaProps{ + Description: "operatorNamespace is the namespace where the KMS provider operator is installed. The platform reads the KMSPlugin resource named \"cluster\" from this namespace to determine the container image and arguments for the KMS plugin sidecar.\n\nSecrets and ConfigMaps referenced by the plugin arguments are expected to exist in this namespace. The platform mounts them at well-known injection points during sidecar lifecycle management.\n\nThe namespace must be a valid DNS-1123 label and must not be an openshift-* or kube-* system namespace.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"operatorNamespace"}, + }, + }, + } +} + func schema_openshift_api_config_v1_GitHubIdentityProvider(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -16817,7 +16847,7 @@ func schema_openshift_api_config_v1_KMSPluginConfig(ref common.ReferenceCallback Properties: map[string]spec.Schema{ "type": { SchemaProps: spec.SchemaProps{ - Description: "type defines the kind of platform for the KMS provider. Allowed values are Vault. When set to Vault, the plugin connects to a HashiCorp Vault server for key management.", + Description: "type defines the kind of platform for the KMS provider. Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider operator installed in the referenced namespace.", Default: "", Type: []string{"string"}, Format: "", @@ -16830,6 +16860,13 @@ func schema_openshift_api_config_v1_KMSPluginConfig(ref common.ReferenceCallback Ref: ref(configv1.VaultKMSPluginConfig{}.OpenAPIModelName()), }, }, + "genericKMSv2": { + SchemaProps: spec.SchemaProps{ + Description: "genericKMSv2 references an OLM-managed KMS provider operator. The operator publishes how to run the KMS plugin sidecar (container image and arguments). The platform handles deployment, lifecycle, and mounting credentials from Secrets and ConfigMaps in the operator namespace at well-known injection points referenced by the plugin arguments. This field must be set when type is GenericKMSv2, and must be unset otherwise.", + Default: map[string]interface{}{}, + Ref: ref(configv1.GenericKMSv2PluginConfig{}.OpenAPIModelName()), + }, + }, }, Required: []string{"type"}, }, @@ -16839,7 +16876,8 @@ func schema_openshift_api_config_v1_KMSPluginConfig(ref common.ReferenceCallback map[string]interface{}{ "discriminator": "type", "fields-to-discriminateBy": map[string]interface{}{ - "vault": "Vault", + "genericKMSv2": "GenericKMSv2", + "vault": "Vault", }, }, }, @@ -16847,7 +16885,7 @@ func schema_openshift_api_config_v1_KMSPluginConfig(ref common.ReferenceCallback }, }, Dependencies: []string{ - configv1.VaultKMSPluginConfig{}.OpenAPIModelName()}, + configv1.GenericKMSv2PluginConfig{}.OpenAPIModelName(), configv1.VaultKMSPluginConfig{}.OpenAPIModelName()}, } } @@ -35792,6 +35830,262 @@ func schema_openshift_api_insights_v1alpha2_Storage(ref common.ReferenceCallback } } +func schema_openshift_api_kms_v1alpha1_KMSPlugin(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. A KMS provider operator installed via OLM reconciles provider-specific configuration and publishes the container runtime configuration in status.runtime.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Default: map[string]interface{}{}, + Ref: ref(metav1.ObjectMeta{}.OpenAPIModelName()), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec is reserved for future use. Operators publish runtime configuration in status.runtime.", + Ref: ref(kmsv1alpha1.KMSPluginSpec{}.OpenAPIModelName()), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status is the most recently observed status of the KMSPlugin.", + Ref: ref(kmsv1alpha1.KMSPluginStatus{}.OpenAPIModelName()), + }, + }, + }, + Required: []string{"metadata"}, + }, + }, + Dependencies: []string{ + kmsv1alpha1.KMSPluginSpec{}.OpenAPIModelName(), kmsv1alpha1.KMSPluginStatus{}.OpenAPIModelName(), metav1.ObjectMeta{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginConfigMapReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginConfigMapReference references a ConfigMap in the same namespace as the KMSPlugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the metadata.name of the referenced ConfigMap. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginList contains a list of KMSPlugins.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Default: map[string]interface{}{}, + Ref: ref(metav1.ListMeta{}.OpenAPIModelName()), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items is the list of KMSPlugins.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(kmsv1alpha1.KMSPlugin{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + kmsv1alpha1.KMSPlugin{}.OpenAPIModelName(), metav1.ListMeta{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginRuntime(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginRuntime describes the container configuration for a KMS plugin sidecar. The platform injects -listen-address and manages lifecycle, resources, security context, and mounting Secrets and ConfigMaps from the operator namespace at well-known injection points. Operators must not set -listen-address in args, either as -listen-address= or as a separate -listen-address flag.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "image": { + SchemaProps: spec.SchemaProps{ + Description: "image is the digest-pinned OCI image for the KMS plugin.\n\nThe image must be a fully qualified OCI image pull spec with a SHA256 digest. The format is: host[:port][/namespace]/name@sha256: where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. The total length must be between 75 and 447 characters.\n\nShort names (e.g., \"vault-plugin\" or \"hashicorp/vault-plugin\") are not allowed. The registry hostname must be included and must contain at least one dot. Image tags (e.g., \":latest\", \":v1.0.0\") are not allowed.", + Type: []string{"string"}, + Format: "", + }, + }, + "args": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "args are the command-line arguments passed to the KMS plugin container. The platform prepends -listen-address= before these arguments. Arguments may reference credential files mounted by the platform at well-known injection points under /var/run/kms/ from Secrets and ConfigMaps in the operator namespace.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "secrets": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "secrets lists Secrets in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/secrets/. Plugin arguments may reference files from these mounted Secrets. When omitted, no Secrets are mounted.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(kmsv1alpha1.KMSPluginSecretReference{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + "configMaps": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/config/. Plugin arguments may reference files from these mounted ConfigMaps. When omitted, no ConfigMaps are mounted.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref(kmsv1alpha1.KMSPluginConfigMapReference{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + }, + Required: []string{"image", "args"}, + }, + }, + Dependencies: []string{ + kmsv1alpha1.KMSPluginConfigMapReference{}.OpenAPIModelName(), kmsv1alpha1.KMSPluginSecretReference{}.OpenAPIModelName()}, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginSecretReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginSecretReference references a Secret in the same namespace as the KMSPlugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the metadata.name of the referenced Secret. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginSpec is reserved for future use.", + Type: []string{"object"}, + }, + }, + } +} + +func schema_openshift_api_kms_v1alpha1_KMSPluginStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KMSPluginStatus defines the observed status of KMSPlugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "runtime": { + SchemaProps: spec.SchemaProps{ + Description: "runtime describes how the platform should run the KMS plugin sidecar. The KMS provider operator must populate this before the platform can deploy the plugin. When omitted, the platform cannot proceed with KMS encryption.", + Default: map[string]interface{}{}, + Ref: ref(kmsv1alpha1.KMSPluginRuntime{}.OpenAPIModelName()), + }, + }, + }, + }, + }, + Dependencies: []string{ + kmsv1alpha1.KMSPluginRuntime{}.OpenAPIModelName()}, + } +} + func schema_openshift_api_kubecontrolplane_v1_AggregatorConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index ac9d7114218..8122cbc63d7 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -7427,6 +7427,19 @@ } } }, + "com.github.openshift.api.config.v1.GenericKMSv2PluginConfig": { + "description": "GenericKMSv2PluginConfig references a KMS provider operator installed via OLM.", + "type": "object", + "required": [ + "operatorNamespace" + ], + "properties": { + "operatorNamespace": { + "description": "operatorNamespace is the namespace where the KMS provider operator is installed. The platform reads the KMSPlugin resource named \"cluster\" from this namespace to determine the container image and arguments for the KMS plugin sidecar.\n\nSecrets and ConfigMaps referenced by the plugin arguments are expected to exist in this namespace. The platform mounts them at well-known injection points during sidecar lifecycle management.\n\nThe namespace must be a valid DNS-1123 label and must not be an openshift-* or kube-* system namespace.", + "type": "string" + } + } + }, "com.github.openshift.api.config.v1.GitHubIdentityProvider": { "description": "GitHubIdentityProvider provides identities for users authenticating using GitHub credentials", "type": "object", @@ -8842,8 +8855,13 @@ "type" ], "properties": { + "genericKMSv2": { + "description": "genericKMSv2 references an OLM-managed KMS provider operator. The operator publishes how to run the KMS plugin sidecar (container image and arguments). The platform handles deployment, lifecycle, and mounting credentials from Secrets and ConfigMaps in the operator namespace at well-known injection points referenced by the plugin arguments. This field must be set when type is GenericKMSv2, and must be unset otherwise.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1.GenericKMSv2PluginConfig" + }, "type": { - "description": "type defines the kind of platform for the KMS provider. Allowed values are Vault. When set to Vault, the plugin connects to a HashiCorp Vault server for key management.", + "description": "type defines the kind of platform for the KMS provider. Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider operator installed in the referenced namespace.", "type": "string", "default": "" }, @@ -8857,6 +8875,7 @@ { "discriminator": "type", "fields-to-discriminateBy": { + "genericKMSv2": "GenericKMSv2", "vault": "Vault" } } @@ -20158,6 +20177,148 @@ } ] }, + "com.github.openshift.api.kms.v1alpha1.KMSPlugin": { + "description": "KMSPlugin defines how the platform runs a KMS encryption provider plugin sidecar. A KMS provider operator installed via OLM reconciles provider-specific configuration and publishes the container runtime configuration in status.runtime.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + "type": "object", + "required": [ + "metadata" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "description": "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta" + }, + "spec": { + "description": "spec is reserved for future use. Operators publish runtime configuration in status.runtime.", + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPluginSpec" + }, + "status": { + "description": "status is the most recently observed status of the KMSPlugin.", + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPluginStatus" + } + } + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginConfigMapReference": { + "description": "KMSPluginConfigMapReference references a ConfigMap in the same namespace as the KMSPlugin.", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "name is the metadata.name of the referenced ConfigMap. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", + "type": "string" + } + } + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginList": { + "description": "KMSPluginList contains a list of KMSPlugins.\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + "type": "object", + "required": [ + "items" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "items": { + "description": "items is the list of KMSPlugins.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPlugin" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "description": "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "default": {}, + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" + } + } + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginRuntime": { + "description": "KMSPluginRuntime describes the container configuration for a KMS plugin sidecar. The platform injects -listen-address and manages lifecycle, resources, security context, and mounting Secrets and ConfigMaps from the operator namespace at well-known injection points. Operators must not set -listen-address in args, either as -listen-address= or as a separate -listen-address flag.", + "type": "object", + "required": [ + "image", + "args" + ], + "properties": { + "args": { + "description": "args are the command-line arguments passed to the KMS plugin container. The platform prepends -listen-address= before these arguments. Arguments may reference credential files mounted by the platform at well-known injection points under /var/run/kms/ from Secrets and ConfigMaps in the operator namespace.", + "type": "array", + "items": { + "type": "string", + "default": "" + }, + "x-kubernetes-list-type": "atomic" + }, + "configMaps": { + "description": "configMaps lists ConfigMaps in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/config/. Plugin arguments may reference files from these mounted ConfigMaps. When omitted, no ConfigMaps are mounted.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPluginConfigMapReference" + }, + "x-kubernetes-list-type": "atomic" + }, + "image": { + "description": "image is the digest-pinned OCI image for the KMS plugin.\n\nThe image must be a fully qualified OCI image pull spec with a SHA256 digest. The format is: host[:port][/namespace]/name@sha256: where the digest must be 64 characters long and consist only of lowercase hexadecimal characters, a-f and 0-9. The total length must be between 75 and 447 characters.\n\nShort names (e.g., \"vault-plugin\" or \"hashicorp/vault-plugin\") are not allowed. The registry hostname must be included and must contain at least one dot. Image tags (e.g., \":latest\", \":v1.0.0\") are not allowed.", + "type": "string" + }, + "secrets": { + "description": "secrets lists Secrets in the same namespace as the KMSPlugin that the platform mounts at well-known injection points under /var/run/kms/secrets/. Plugin arguments may reference files from these mounted Secrets. When omitted, no Secrets are mounted.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPluginSecretReference" + }, + "x-kubernetes-list-type": "atomic" + } + } + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginSecretReference": { + "description": "KMSPluginSecretReference references a Secret in the same namespace as the KMSPlugin.", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "name is the metadata.name of the referenced Secret. The name must be a valid DNS subdomain name: it must contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character.", + "type": "string" + } + } + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginSpec": { + "description": "KMSPluginSpec is reserved for future use.", + "type": "object" + }, + "com.github.openshift.api.kms.v1alpha1.KMSPluginStatus": { + "description": "KMSPluginStatus defines the observed status of KMSPlugin.", + "type": "object", + "properties": { + "runtime": { + "description": "runtime describes how the platform should run the KMS plugin sidecar. The KMS provider operator must populate this before the platform can deploy the plugin. When omitted, the platform cannot proceed with KMS encryption.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.kms.v1alpha1.KMSPluginRuntime" + } + } + }, "com.github.openshift.api.kubecontrolplane.v1.AggregatorConfig": { "description": "AggregatorConfig holds information required to make the aggregator function.", "type": "object", diff --git a/payload-manifests/crds/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml index f3793fac61d..568d0603dce 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_apiservers-CustomNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/payload-manifests/crds/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml index d06cd26ca79..831dc110fcb 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_apiservers-DevPreviewNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer. diff --git a/payload-manifests/crds/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml index cce33594546..9b1a25b8236 100644 --- a/payload-manifests/crds/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml +++ b/payload-manifests/crds/0000_10_config-operator_01_apiservers-TechPreviewNoUpgrade.crd.yaml @@ -168,13 +168,50 @@ spec: managing the lifecyle of the encryption keys outside of the control plane. This allows integration with an external provider to manage the data encryption keys securely. properties: + genericKMSv2: + description: |- + genericKMSv2 references an OLM-managed KMS provider operator. + The operator publishes how to run the KMS plugin sidecar (container image and arguments). + The platform handles deployment, lifecycle, and mounting credentials from Secrets and + ConfigMaps in the operator namespace at well-known injection points referenced by the + plugin arguments. + This field must be set when type is GenericKMSv2, and must be unset otherwise. + properties: + operatorNamespace: + description: |- + operatorNamespace is the namespace where the KMS provider operator is installed. + The platform reads the KMSPlugin resource named "cluster" from this namespace + to determine the container image and arguments for the KMS plugin sidecar. + + Secrets and ConfigMaps referenced by the plugin arguments are expected to exist + in this namespace. The platform mounts them at well-known injection points + during sidecar lifecycle management. + + The namespace must be a valid DNS-1123 label and must not be an openshift-* or + kube-* system namespace. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: operatorNamespace must be a valid DNS-1123 + label + rule: '!format.dns1123Label().validate(self).hasValue()' + - message: operatorNamespace must not be an openshift-* + or kube-* system namespace + rule: '!self.startsWith(''openshift-'') && !self.startsWith(''kube-'')' + required: + - operatorNamespace + type: object type: description: |- type defines the kind of platform for the KMS provider. - Allowed values are Vault. + Allowed values are Vault and GenericKMSv2. When set to Vault, the plugin connects to a HashiCorp Vault server for key management. + When set to GenericKMSv2, the platform reads runtime configuration from a KMS provider + operator installed in the referenced namespace. enum: - Vault + - GenericKMSv2 type: string vault: description: |- @@ -448,6 +485,10 @@ spec: - message: vault config is required when kms provider type is Vault, and forbidden otherwise rule: 'self.type == ''Vault'' ? has(self.vault) : !has(self.vault)' + - message: genericKMSv2 config is required when kms provider type + is GenericKMSv2, and forbidden otherwise + rule: 'self.type == ''GenericKMSv2'' ? has(self.genericKMSv2) + : !has(self.genericKMSv2)' type: description: |- type defines what encryption type should be used to encrypt resources at the datastore layer.