diff --git a/api/v1alpha1/kbsconfig_types.go b/api/v1alpha1/kbsconfig_types.go index 5ccc4b9..a6fc6d0 100644 --- a/api/v1alpha1/kbsconfig_types.go +++ b/api/v1alpha1/kbsconfig_types.go @@ -67,6 +67,9 @@ type KbsConfigSpec struct { // KbsHttpsCertSecretName is the name of the secret that contains the KBS https certificate KbsHttpsCertSecretName string `json:"kbsHttpsCertSecretName,omitempty"` + + // KbsSecretResources is an array of secret names that contain the keys required by clients + KbsSecretResources []string `json:"kbsSecretResources,omitempty"` } // KbsConfigStatus defines the observed state of KbsConfig diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 407fa4e..309e257 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -30,7 +30,7 @@ func (in *KbsConfig) DeepCopyInto(out *KbsConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status } @@ -87,6 +87,11 @@ func (in *KbsConfigList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KbsConfigSpec) DeepCopyInto(out *KbsConfigSpec) { *out = *in + if in.KbsSecretResources != nil { + in, out := &in.KbsSecretResources, &out.KbsSecretResources + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KbsConfigSpec. diff --git a/config/crd/bases/confidentialcontainers.org_kbsconfigs.yaml b/config/crd/bases/confidentialcontainers.org_kbsconfigs.yaml index 30cdfce..1d921e6 100644 --- a/config/crd/bases/confidentialcontainers.org_kbsconfigs.yaml +++ b/config/crd/bases/confidentialcontainers.org_kbsconfigs.yaml @@ -65,6 +65,12 @@ spec: description: KbsRvpsConfigMapName is the name of the configmap that contains the KBS RVPS configuration type: string + kbsSecretResources: + description: KbsSecretResources is an array of secret names that contain + the keys required by clients + items: + type: string + type: array kbsServiceType: description: KbsServiceType is the type of service to create for KBS type: string diff --git a/config/manifests/bases/kbs-operator.clusterserviceversion.yaml b/config/manifests/bases/kbs-operator.clusterserviceversion.yaml new file mode 100644 index 0000000..7827e11 --- /dev/null +++ b/config/manifests/bases/kbs-operator.clusterserviceversion.yaml @@ -0,0 +1,53 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: '[]' + capabilities: Basic Install + name: kbs-operator.v0.0.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: KbsConfig is the Schema for the kbsconfigs API + displayName: Kbs Config + kind: KbsConfig + name: kbsconfigs.confidentialcontainers.org + version: v1alpha1 + description: Operator to manage the lifecycle of Key Broker Service (KBS) + displayName: KBS Operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + deployments: null + strategy: "" + installModes: + - supported: false + type: OwnNamespace + - supported: false + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - kbs + - kbs-operator + - attestation-service + - rvps + links: + - name: Kbs Operator + url: https://kbs-operator.domain + maintainers: + - email: cncf-ccontainers-maintainers@lists.cncf.io + name: Pradipta Banerjee + - email: ' cncf-ccontainers-maintainers@lists.cncf.io' + name: Jens Freimann + maturity: alpha + provider: + name: Confidential Containers Community + url: https://github.com/confidential-containers + version: 0.0.0 diff --git a/config/samples/all-in-one/kbsconfig_sample.yaml b/config/samples/all-in-one/kbsconfig_sample.yaml index c7e0583..bf5be1f 100644 --- a/config/samples/all-in-one/kbsconfig_sample.yaml +++ b/config/samples/all-in-one/kbsconfig_sample.yaml @@ -13,7 +13,4 @@ spec: kbsConfigMapName: kbs-config kbsAuthSecretName: kbs-auth-public-key kbsDeploymentType: AllInOneDeployment - - - - + kbsSecretResources: [] diff --git a/config/samples/microservices/kbsconfig_sample.yaml b/config/samples/microservices/kbsconfig_sample.yaml index 70290c9..f587b08 100644 --- a/config/samples/microservices/kbsconfig_sample.yaml +++ b/config/samples/microservices/kbsconfig_sample.yaml @@ -20,3 +20,4 @@ spec: kbsDeploymentType: MicroservicesDeployment #kbsHttpsKeySecretName: kbs-https-key #kbsHttpsCertSecretName: kbs-https-certificate + kbsSecretResources: [] diff --git a/controllers/common.go b/controllers/common.go index ddd21a9..21ab17e 100644 --- a/controllers/common.go +++ b/controllers/common.go @@ -38,6 +38,9 @@ const ( // KBS service name KbsServiceName = "kbs-service" + + // Default KBS Resources Path + kbsResourcesPath = "/opt/confidential-containers/kbs/repository/default" ) func contains(list []string, s string) bool { diff --git a/controllers/kbsconfig_controller.go b/controllers/kbsconfig_controller.go index b9bebae..286ee35 100644 --- a/controllers/kbsconfig_controller.go +++ b/controllers/kbsconfig_controller.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "os" + "path/filepath" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -206,7 +207,7 @@ func (r *KbsConfigReconciler) deployOrUpdateKbsService(ctx context.Context) erro } // newKbsService returns a new service for the KBS instance -func (r *KbsConfigReconciler) newKbsService(ctx context.Context) *corev1.Service { +func (r *KbsConfigReconciler) newKbsService(_ context.Context) *corev1.Service { // Get the service type from the KbsConfig instance serviceType := r.kbsConfig.Spec.KbsServiceType // if the service type is not provided, default to ClusterIP @@ -308,21 +309,31 @@ func (r *KbsConfigReconciler) deployOrUpdateKbsDeployment(ctx context.Context) e } func (r *KbsConfigReconciler) buildKbsVolumeMounts(ctx context.Context, volumes []corev1.Volume) ([]corev1.Volume, []corev1.VolumeMount, error) { - var kbsVolumes []corev1.Volume - kbsVolumes, err := r.processKbsConfigMap(ctx, kbsVolumes) + var kbsEtcVolumes, kbsSecretResourceVolumes []corev1.Volume + kbsEtcVolumes, err := r.processKbsConfigMap(ctx, kbsEtcVolumes) if err != nil { return nil, nil, err } - kbsVolumes, err = r.processAuthSecret(ctx, kbsVolumes) + kbsEtcVolumes, err = r.processAuthSecret(ctx, kbsEtcVolumes) if err != nil { return nil, nil, err } - kbsVolumes, err = r.processHttpsSecret(ctx, kbsVolumes) + kbsEtcVolumes, err = r.processHttpsSecret(ctx, kbsEtcVolumes) if err != nil { return nil, nil, err } - volumeMounts := volumesToVolumeMounts(kbsVolumes) - volumes = append(volumes, kbsVolumes...) + // All the above kbsVolumes gets mounted under "/etc" directory + volumeMounts := volumesToVolumeMounts(kbsEtcVolumes) + volumes = append(volumes, kbsEtcVolumes...) + + kbsSecretResourceVolumes, err = r.processKbsSecretResources(ctx, kbsSecretResourceVolumes) + if err != nil { + return nil, nil, err + } + // Add the kbsSecretResourceVolumes to the volumesMounts + volumeMounts = append(volumeMounts, volumesToVolumeMountsCustom(kbsSecretResourceVolumes, kbsResourcesPath)...) + volumes = append(volumes, kbsSecretResourceVolumes...) + return volumes, volumeMounts, nil } @@ -348,6 +359,7 @@ func (r *KbsConfigReconciler) buildRvpsVolumesMounts(ctx context.Context, volume return volumes, volumeMounts, nil } +// Method to add volumeMounts for KBS under "/etc" directory func volumesToVolumeMounts(volumes []corev1.Volume) []corev1.VolumeMount { volumeMounts := []corev1.VolumeMount{} for _, volume := range volumes { @@ -359,6 +371,20 @@ func volumesToVolumeMounts(volumes []corev1.Volume) []corev1.VolumeMount { return volumeMounts } +// Method to add volumeMounts for KBS under custom directory +func volumesToVolumeMountsCustom(volumes []corev1.Volume, mountPath string) []corev1.VolumeMount { + volumeMounts := []corev1.VolumeMount{} + for _, volume := range volumes { + // Create MountPath ensuring file path separators are handled correctly + mountPath := filepath.Join(mountPath, volume.Name) + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: volume.Name, + MountPath: mountPath, + }) + } + return volumeMounts +} + // newKbsDeployment returns a new deployment for the KBS instance func (r *KbsConfigReconciler) newKbsDeployment(ctx context.Context) *appsv1.Deployment { // Set replica count @@ -721,6 +747,38 @@ func (r *KbsConfigReconciler) processKbsConfigMap(ctx context.Context, volumes [ return volumes, nil } +// Method to add KbsSecretResources to the KBS volumes + +func (r *KbsConfigReconciler) processKbsSecretResources(ctx context.Context, volumes []corev1.Volume) ([]corev1.Volume, error) { + if r.kbsConfig.Spec.KbsSecretResources != nil { + for _, secretResource := range r.kbsConfig.Spec.KbsSecretResources { + foundSecret := &corev1.Secret{} + err := r.Client.Get(ctx, client.ObjectKey{ + Namespace: r.namespace, + Name: secretResource, + }, foundSecret) + if err != nil && k8serrors.IsNotFound(err) { + r.log.Error(err, "KbsSecretResource does not exist", "Secret.Namespace", r.namespace, "Secret.Name", secretResource) + return nil, err + } else if err != nil { + r.log.Error(err, "Failed to get KBS Secret Resource") + return nil, err + } + + volumes = append(volumes, corev1.Volume{ + Name: secretResource, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretResource, + }, + }, + }) + } + } + return volumes, nil + +} + // updateKbsDeployment updates an existing deployment for the KBS instance func (r *KbsConfigReconciler) updateKbsDeployment(ctx context.Context, deployment *appsv1.Deployment) error { err := r.Client.Update(ctx, deployment)