diff --git a/api/bases/barbican.openstack.org_barbicanapis.yaml b/api/bases/barbican.openstack.org_barbicanapis.yaml index 4069a53..0a75ff8 100644 --- a/api/bases/barbican.openstack.org_barbicanapis.yaml +++ b/api/bases/barbican.openstack.org_barbicanapis.yaml @@ -385,6 +385,36 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + api: + description: API tls type which encapsulates for API services + properties: + internal: + description: Internal GenericService - holds the secret for + the internal endpoint + properties: + secretName: + description: SecretName - holding the cert, key for the + service + type: string + type: object + public: + description: Public GenericService - holds the secret for + the public endpoint + properties: + secretName: + description: SecretName - holding the cert, key for the + service + type: string + type: object + type: object + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml b/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml index 1802a14..0bc5887 100644 --- a/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml +++ b/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml @@ -207,6 +207,14 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: type: string required: diff --git a/api/bases/barbican.openstack.org_barbicans.yaml b/api/bases/barbican.openstack.org_barbicans.yaml index 4d105ee..9877816 100644 --- a/api/bases/barbican.openstack.org_barbicans.yaml +++ b/api/bases/barbican.openstack.org_barbicans.yaml @@ -323,6 +323,36 @@ spec: to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object + tls: + description: TLS - Parameters related to the TLS + properties: + api: + description: API tls type which encapsulates for API services + properties: + internal: + description: Internal GenericService - holds the secret + for the internal endpoint + properties: + secretName: + description: SecretName - holding the cert, key for + the service + type: string + type: object + public: + description: Public GenericService - holds the secret + for the public endpoint + properties: + secretName: + description: SecretName - holding the cert, key for + the service + type: string + type: object + type: object + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in + a pre-created bundle file + type: string + type: object required: - containerImage type: object diff --git a/api/bases/barbican.openstack.org_barbicanworkers.yaml b/api/bases/barbican.openstack.org_barbicanworkers.yaml index c16ebf4..3a794c1 100644 --- a/api/bases/barbican.openstack.org_barbicanworkers.yaml +++ b/api/bases/barbican.openstack.org_barbicanworkers.yaml @@ -205,6 +205,14 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: type: string required: diff --git a/api/go.mod b/api/go.mod index 0ab6613..f78da6d 100644 --- a/api/go.mod +++ b/api/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 - github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f + github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14 k8s.io/api v0.26.12 k8s.io/apimachinery v0.27.1 k8s.io/client-go v0.26.12 diff --git a/api/go.sum b/api/go.sum index a544ab6..0f39474 100644 --- a/api/go.sum +++ b/api/go.sum @@ -228,8 +228,8 @@ github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f h1:ifW2n0TkrS1Wa58DK/N+zAKdGH5XQh4Llk/hefsXzN8= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f/go.mod h1:ov4lAbniNUsLqZCBp1RTixpqXc8JlzA5B+yTcCkJXQg= +github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14 h1:8batipIElAHscbsVUJz8w/2NOvu+pRi8ixF1XUP6WiQ= +github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14/go.mod h1:ov4lAbniNUsLqZCBp1RTixpqXc8JlzA5B+yTcCkJXQg= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/api/v1beta1/barbicanapi_types.go b/api/v1beta1/barbicanapi_types.go index 545f331..d8187bd 100644 --- a/api/v1beta1/barbicanapi_types.go +++ b/api/v1beta1/barbicanapi_types.go @@ -19,6 +19,7 @@ package v1beta1 import ( "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/service" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -34,6 +35,11 @@ type BarbicanAPITemplate struct { // Override, provides the ability to override the generated manifest of several child resources. Override APIOverrideSpec `json:"override,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // TLS - Parameters related to the TLS + TLS tls.API `json:"tls,omitempty"` } // APIOverrideSpec to override the generated manifest of several child resources. diff --git a/api/v1beta1/barbicankeystonelistener_types.go b/api/v1beta1/barbicankeystonelistener_types.go index 28e69df..99e4b58 100644 --- a/api/v1beta1/barbicankeystonelistener_types.go +++ b/api/v1beta1/barbicankeystonelistener_types.go @@ -18,6 +18,7 @@ package v1beta1 import ( "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -37,6 +38,11 @@ type BarbicanKeystoneListenerSpec struct { DatabaseHostname string `json:"databaseHostname"` TransportURLSecret string `json:"transportURLSecret,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // TLS - Parameters related to the TLS + TLS tls.Ca `json:"tls,omitempty"` } // BarbicanKeystoneListenerStatus defines the observed state of BarbicanKeystoneListener diff --git a/api/v1beta1/barbicanworker_types.go b/api/v1beta1/barbicanworker_types.go index aa88eae..d31d8a3 100644 --- a/api/v1beta1/barbicanworker_types.go +++ b/api/v1beta1/barbicanworker_types.go @@ -18,6 +18,7 @@ package v1beta1 import ( "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -37,6 +38,11 @@ type BarbicanWorkerSpec struct { DatabaseHostname string `json:"databaseHostname"` TransportURLSecret string `json:"transportURLSecret,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // TLS - Parameters related to the TLS + TLS tls.Ca `json:"tls,omitempty"` } // BarbicanWorkerStatus defines the observed state of BarbicanWorker diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 59fc786..eade7e5 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -208,6 +208,7 @@ func (in *BarbicanAPITemplate) DeepCopyInto(out *BarbicanAPITemplate) { *out = *in in.BarbicanComponentTemplate.DeepCopyInto(&out.BarbicanComponentTemplate) in.Override.DeepCopyInto(&out.Override) + in.TLS.DeepCopyInto(&out.TLS) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanAPITemplate. @@ -359,6 +360,7 @@ func (in *BarbicanKeystoneListenerSpec) DeepCopyInto(out *BarbicanKeystoneListen *out = *in out.BarbicanTemplate = in.BarbicanTemplate in.BarbicanKeystoneListenerTemplate.DeepCopyInto(&out.BarbicanKeystoneListenerTemplate) + out.TLS = in.TLS } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanKeystoneListenerSpec. @@ -606,6 +608,7 @@ func (in *BarbicanWorkerSpec) DeepCopyInto(out *BarbicanWorkerSpec) { *out = *in out.BarbicanTemplate = in.BarbicanTemplate in.BarbicanWorkerTemplate.DeepCopyInto(&out.BarbicanWorkerTemplate) + out.TLS = in.TLS } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanWorkerSpec. diff --git a/config/certmanager/kustomizeconfig.yaml b/config/certmanager/kustomizeconfig.yaml index 90d7c31..e631f77 100644 --- a/config/certmanager/kustomizeconfig.yaml +++ b/config/certmanager/kustomizeconfig.yaml @@ -1,4 +1,4 @@ -# This configuration is for teaching kustomize how to update name ref and var substitution +# This configuration is for teaching kustomize how to update name ref and var substitution nameReference: - kind: Issuer group: cert-manager.io diff --git a/config/crd/bases/barbican.openstack.org_barbicanapis.yaml b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml index 4069a53..0a75ff8 100644 --- a/config/crd/bases/barbican.openstack.org_barbicanapis.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml @@ -385,6 +385,36 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + api: + description: API tls type which encapsulates for API services + properties: + internal: + description: Internal GenericService - holds the secret for + the internal endpoint + properties: + secretName: + description: SecretName - holding the cert, key for the + service + type: string + type: object + public: + description: Public GenericService - holds the secret for + the public endpoint + properties: + secretName: + description: SecretName - holding the cert, key for the + service + type: string + type: object + type: object + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml b/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml index 1802a14..0bc5887 100644 --- a/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml @@ -207,6 +207,14 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: type: string required: diff --git a/config/crd/bases/barbican.openstack.org_barbicans.yaml b/config/crd/bases/barbican.openstack.org_barbicans.yaml index 4d105ee..9877816 100644 --- a/config/crd/bases/barbican.openstack.org_barbicans.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicans.yaml @@ -323,6 +323,36 @@ spec: to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' type: object type: object + tls: + description: TLS - Parameters related to the TLS + properties: + api: + description: API tls type which encapsulates for API services + properties: + internal: + description: Internal GenericService - holds the secret + for the internal endpoint + properties: + secretName: + description: SecretName - holding the cert, key for + the service + type: string + type: object + public: + description: Public GenericService - holds the secret + for the public endpoint + properties: + secretName: + description: SecretName - holding the cert, key for + the service + type: string + type: object + type: object + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in + a pre-created bundle file + type: string + type: object required: - containerImage type: object diff --git a/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml b/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml index c16ebf4..3a794c1 100644 --- a/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml @@ -205,6 +205,14 @@ spec: simpleCryptoBackendKEKSecret: description: Secret containing SimpleCrypto KEK type: string + tls: + description: TLS - Parameters related to the TLS + properties: + caBundleSecretName: + description: CaBundleSecretName - holding the CA certs in a pre-created + bundle file + type: string + type: object transportURLSecret: type: string required: diff --git a/config/default/manager_default_images.yaml b/config/default/manager_default_images.yaml index 2e0bba9..9f0eda4 100644 --- a/config/default/manager_default_images.yaml +++ b/config/default/manager_default_images.yaml @@ -17,4 +17,3 @@ spec: value: quay.io/podified-antelope-centos9/openstack-barbican-worker:current-podified - name: RELATED_IMAGE_BARBICAN_KEYSTONE_LISTENER_IMAGE_URL_DEFAULT value: quay.io/podified-antelope-centos9/openstack-barbican-keystone-listener:current-podified - diff --git a/config/manifests/bases/barbican-operator.clusterserviceversion.yaml b/config/manifests/bases/barbican-operator.clusterserviceversion.yaml index 4dc8551..d827ff1 100644 --- a/config/manifests/bases/barbican-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/barbican-operator.clusterserviceversion.yaml @@ -17,16 +17,28 @@ spec: displayName: Barbican API kind: BarbicanAPI name: barbicanapis.barbican.openstack.org + specDescriptors: + - description: TLS - Parameters related to the TLS + displayName: TLS + path: tls version: v1beta1 - description: Barbican is the Schema for the barbicans API displayName: Barbican kind: Barbican name: barbicans.barbican.openstack.org + specDescriptors: + - description: TLS - Parameters related to the TLS + displayName: TLS + path: barbicanAPI.tls version: v1beta1 - description: BarbicanWorker is the Schema for the barbicanworkers API displayName: Barbican Worker kind: BarbicanWorker name: barbicanworkers.barbican.openstack.org + specDescriptors: + - description: TLS - Parameters related to the TLS + displayName: TLS + path: tls version: v1beta1 description: Barbican Operator displayName: Barbican Operator diff --git a/controllers/barbican_controller.go b/controllers/barbican_controller.go index 5b04d6c..c0ede49 100644 --- a/controllers/barbican_controller.go +++ b/controllers/barbican_controller.go @@ -478,6 +478,27 @@ func (r *BarbicanReconciler) reconcileDelete(ctx context.Context, instance *barb return ctrl.Result{}, nil } +// fields to index to reconcile when change +const ( + passwordSecretField = ".spec.secret" + caBundleSecretNameField = ".spec.tls.caBundleSecretName" + tlsAPIInternalField = ".spec.tls.api.internal.secretName" + tlsAPIPublicField = ".spec.tls.api.public.secretName" +) + +var ( + commonWatchFields = []string{ + passwordSecretField, + caBundleSecretNameField, + } + apinWatchFields = []string{ + passwordSecretField, + caBundleSecretNameField, + tlsAPIInternalField, + tlsAPIPublicField, + } +) + // SetupWithManager sets up the controller with the Manager. func (r *BarbicanReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). @@ -623,6 +644,7 @@ func (r *BarbicanReconciler) workerDeploymentCreateOrUpdate(ctx context.Context, BarbicanWorkerTemplate: instance.Spec.BarbicanWorker, DatabaseHostname: instance.Status.DatabaseHostname, TransportURLSecret: instance.Status.TransportURLSecret, + TLS: instance.Spec.BarbicanAPI.TLS.Ca, } deployment := &barbicanv1beta1.BarbicanWorker{ @@ -660,6 +682,7 @@ func (r *BarbicanReconciler) keystoneListenerDeploymentCreateOrUpdate(ctx contex BarbicanKeystoneListenerTemplate: instance.Spec.BarbicanKeystoneListener, DatabaseHostname: instance.Status.DatabaseHostname, TransportURLSecret: instance.Status.TransportURLSecret, + TLS: instance.Spec.BarbicanAPI.TLS.Ca, } deployment := &barbicanv1beta1.BarbicanKeystoneListener{ diff --git a/controllers/barbicanapi_controller.go b/controllers/barbicanapi_controller.go index 467ee2a..91886f3 100644 --- a/controllers/barbicanapi_controller.go +++ b/controllers/barbicanapi_controller.go @@ -36,13 +36,22 @@ import ( nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/service" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -142,6 +151,7 @@ func (r *BarbicanAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage condition.UnknownCondition(condition.KeystoneEndpointReadyCondition, condition.InitReason, ""), condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage), + condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), ) Log.Info(fmt.Sprintf("calling init %s", instance.Name)) instance.Status.Conditions.Init(&cl) @@ -288,6 +298,21 @@ func (r *BarbicanAPIReconciler) generateServiceConfigs( "EnableSecureRBAC": instance.Spec.EnableSecureRBAC, } + // create httpd vhost template parameters + httpdVhostConfig := map[string]interface{}{} + for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} { + endptConfig := map[string]interface{}{} + endptConfig["ServerName"] = fmt.Sprintf("barbican-%s.%s.svc", endpt.String(), instance.Namespace) + endptConfig["TLS"] = false // default TLS to false, and set it bellow to true if enabled + if instance.Spec.TLS.API.Enabled(endpt) { + endptConfig["TLS"] = true + endptConfig["SSLCertificateFile"] = fmt.Sprintf("/etc/pki/tls/certs/%s.crt", endpt.String()) + endptConfig["SSLCertificateKeyFile"] = fmt.Sprintf("/etc/pki/tls/private/%s.key", endpt.String()) + } + httpdVhostConfig[endpt.String()] = endptConfig + } + templateParameters["VHosts"] = httpdVhostConfig + return GenerateConfigsGeneric(ctx, h, instance, envVars, templateParameters, customData, labels, false) } @@ -399,7 +424,12 @@ func (r *BarbicanAPIReconciler) reconcileInit( } // create service - end - // TODO: TLS, pass in https as protocol, create TLS cert + // if TLS is enabled + if instance.Spec.TLS.API.Enabled(endpointType) { + // set endpoint protocol to https + data.Protocol = ptr.To(service.ProtocolHTTPS) + } + apiEndpoints[string(endpointType)], err = svc.GetAPIEndpoint( svcOverride.EndpointURL, data.Protocol, data.Path) if err != nil { @@ -537,26 +567,60 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b // This seems like a great place to store things like HSM passwords Log.Info(fmt.Sprintf("[API] Got secrets '%s'", instance.Name)) + // - // create custom config for this barbican service + // TLS input validation // - err = r.generateServiceConfigs(ctx, helper, instance, &configVars) + // Validate the CA cert secret if provided + if instance.Spec.TLS.CaBundleSecretName != "" { + hash, ctrlResult, err := tls.ValidateCACertSecret( + ctx, + helper.GetClient(), + types.NamespacedName{ + Name: instance.Spec.TLS.CaBundleSecretName, + Namespace: instance.Namespace, + }, + ) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.TLSInputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.TLSInputErrorMessage, + err.Error())) + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + if hash != "" { + configVars[tls.CABundleKey] = env.SetValue(hash) + } + } + + // TODO(alee) should this validation occur in an if statement? what happens when tls is not enabled? + // Validate API service certs secrets + certsHash, ctrlResult, err := instance.Spec.TLS.API.ValidateCertSecrets(ctx, helper, instance.Namespace) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( - condition.ServiceConfigReadyCondition, + condition.TLSInputReadyCondition, condition.ErrorReason, condition.SeverityWarning, - condition.ServiceConfigReadyErrorMessage, + condition.TLSInputErrorMessage, err.Error())) - return ctrl.Result{}, err + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil } + configVars[tls.TLSHashName] = env.SetValue(certsHash) + + // all cert input checks out so report InputReady + instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) - Log.Info(fmt.Sprintf("[API] Getting input hash '%s'", instance.Name)) // - // create hash over all the different input resources to identify if any those changed - // and a restart/recreate is required. + // create custom config for this barbican service // - inputHash, hashChanged, err := r.createHashOfInputHashes(ctx, instance, configVars) + err = r.generateServiceConfigs(ctx, helper, instance, &configVars) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.ServiceConfigReadyCondition, @@ -565,13 +629,11 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b condition.ServiceConfigReadyErrorMessage, err.Error())) return ctrl.Result{}, err - } else if hashChanged { - // Hash changed and instance status should be updated (which will be done by main defer func), - // so we need to return and reconcile again - return ctrl.Result{}, nil } + instance.Status.Conditions.MarkTrue(condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage) + // TODO(alee) Figure out how serviceLabels are used and what must be in them Log.Info(fmt.Sprintf("[API] Getting service labels '%s'", instance.Name)) serviceLabels := map[string]string{ common.AppSelector: fmt.Sprintf(barbican.ServiceName), @@ -632,9 +694,38 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b return ctrlResult, nil } + Log.Info(fmt.Sprintf("[API] Getting input hash '%s'", instance.Name)) + // + // create hash over all the different input resources to identify if any those changed + // and a restart/recreate is required. + // + inputHash, hashChanged, err := r.createHashOfInputHashes(ctx, instance, configVars) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.ServiceConfigReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.ServiceConfigReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } else if hashChanged { + // Hash changed and instance status should be updated (which will be done by main defer func), + // so we need to return and reconcile again + return ctrl.Result{}, nil + } + Log.Info(fmt.Sprintf("[API] Defining deployment '%s'", instance.Name)) // Define a new Deployment object - deplDef := barbicanapi.Deployment(instance, inputHash, serviceLabels, serviceAnnotations) + deplDef, err := barbicanapi.Deployment(instance, inputHash, serviceLabels, serviceAnnotations) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.DeploymentReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } Log.Info(fmt.Sprintf("[API] Getting deployment '%s'", instance.Name)) depl := deployment.NewDeployment( deplDef, @@ -692,11 +783,97 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b // SetupWithManager sets up the controller with the Manager. func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error { + + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanAPI{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanAPI) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanAPI{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanAPI) + if cr.Spec.TLS.CaBundleSecretName == "" { + return nil + } + return []string{cr.Spec.TLS.CaBundleSecretName} + }); err != nil { + return err + } + + // index tlsAPIInternalField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanAPI{}, tlsAPIInternalField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanAPI) + if cr.Spec.TLS.API.Internal.SecretName == nil { + return nil + } + return []string{*cr.Spec.TLS.API.Internal.SecretName} + }); err != nil { + return err + } + + // index tlsAPIPublicField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanAPI{}, tlsAPIPublicField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanAPI) + if cr.Spec.TLS.API.Public.SecretName == nil { + return nil + } + return []string{*cr.Spec.TLS.API.Public.SecretName} + }); err != nil { + return err + } return ctrl.NewControllerManagedBy(mgr). For(&barbicanv1beta1.BarbicanAPI{}). Owns(&corev1.Service{}). Owns(&corev1.Secret{}). Owns(&keystonev1.KeystoneEndpoint{}). Owns(&appsv1.Deployment{}). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } + +func (r *BarbicanAPIReconciler) findObjectsForSrc(src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("BarbicanAPI") + + for _, field := range apinWatchFields { + crList := &barbicanv1beta1.BarbicanAPIList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.List(context.TODO(), crList, listOps) + if err != nil { + return []reconcile.Request{} + } + + for _, item := range crList.Items { + l.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace())) + + requests = append(requests, + reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: item.GetName(), + Namespace: item.GetNamespace(), + }, + }, + ) + } + } + + return requests +} diff --git a/controllers/barbicankeystonelistener_controller.go b/controllers/barbicankeystonelistener_controller.go index dea1f51..e895022 100644 --- a/controllers/barbicankeystonelistener_controller.go +++ b/controllers/barbicankeystonelistener_controller.go @@ -31,6 +31,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/deployment" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" //"github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/env" @@ -39,12 +40,19 @@ import ( nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -123,21 +131,14 @@ func (r *BarbicanKeystoneListenerReconciler) Reconcile(ctx context.Context, req if instance.Status.Conditions == nil { instance.Status.Conditions = condition.Conditions{} cl := condition.CreateList( - //condition.UnknownCondition(condition.ExposeServiceReadyCondition, condition.InitReason, condition.ExposeServiceReadyInitMessage), condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage), condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage), - // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage - //condition.UnknownCondition(condition.KeystoneServiceReadyCondition, condition.InitReason, ""), - //condition.UnknownCondition(condition.KeystoneEndpointReadyCondition, condition.InitReason, ""), condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage), + condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), ) - Log.Info(fmt.Sprintf("calling init %s", instance.Name)) instance.Status.Conditions.Init(&cl) - Log.Info(fmt.Sprintf("post init %s", instance.Name)) - // TODO: (alee) this is ssupposed to exit here - but then it never comes back! - // Register overall status immediately to have an early feedback e.g. in the cli return ctrl.Result{}, nil } Log.Info(fmt.Sprintf("post initiialize %s", instance.Name)) @@ -471,6 +472,40 @@ func (r *BarbicanKeystoneListenerReconciler) reconcileNormal(ctx context.Context // This seems like a great place to store things like HSM passwords Log.Info(fmt.Sprintf("[KeystoneListener] Got secrets '%s'", instance.Name)) + + // + // TLS input validation + // + // Validate the CA cert secret if provided + if instance.Spec.TLS.CaBundleSecretName != "" { + hash, ctrlResult, err := tls.ValidateCACertSecret( + ctx, + helper.GetClient(), + types.NamespacedName{ + Name: instance.Spec.TLS.CaBundleSecretName, + Namespace: instance.Namespace, + }, + ) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.TLSInputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.TLSInputErrorMessage, + err.Error())) + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + if hash != "" { + configVars[tls.CABundleKey] = env.SetValue(hash) + } + } + + // all cert input checks out so report InputReady + instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) + // // create custom config for this barbican service // @@ -630,11 +665,73 @@ func (r *BarbicanKeystoneListenerReconciler) reconcileNormal(ctx context.Context // SetupWithManager sets up the controller with the Manager. func (r *BarbicanKeystoneListenerReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanKeystoneListener{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanKeystoneListener) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanKeystoneListener{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanKeystoneListener) + if cr.Spec.TLS.CaBundleSecretName == "" { + return nil + } + return []string{cr.Spec.TLS.CaBundleSecretName} + }); err != nil { + return err + } + return ctrl.NewControllerManagedBy(mgr). For(&barbicanv1beta1.BarbicanKeystoneListener{}). //Owns(&corev1.Service{}). //Owns(&corev1.Secret{}). Owns(&appsv1.Deployment{}). //Owns(&routev1.Route{}). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } + +func (r *BarbicanKeystoneListenerReconciler) findObjectsForSrc(src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("BarbicanKeystoneListener") + + for _, field := range commonWatchFields { + crList := &barbicanv1beta1.BarbicanKeystoneListenerList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.List(context.TODO(), crList, listOps) + if err != nil { + return []reconcile.Request{} + } + + for _, item := range crList.Items { + l.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace())) + + requests = append(requests, + reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: item.GetName(), + Namespace: item.GetNamespace(), + }, + }, + ) + } + } + + return requests +} diff --git a/controllers/barbicanworker_controller.go b/controllers/barbicanworker_controller.go index 2069718..a312cd8 100644 --- a/controllers/barbicanworker_controller.go +++ b/controllers/barbicanworker_controller.go @@ -29,6 +29,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/deployment" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" "github.com/openstack-k8s-operators/lib-common/modules/common/env" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" @@ -36,12 +37,19 @@ import ( nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -124,6 +132,7 @@ func (r *BarbicanWorkerReconciler) Reconcile(ctx context.Context, req ctrl.Reque condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage), condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage), condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage), + condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), ) Log.Info(fmt.Sprintf("calling init %s", instance.Name)) instance.Status.Conditions.Init(&cl) @@ -330,6 +339,40 @@ func (r *BarbicanWorkerReconciler) reconcileNormal(ctx context.Context, instance // This seems like a great place to store things like HSM passwords Log.Info(fmt.Sprintf("[Worker] Got secrets '%s'", instance.Name)) + + // + // TLS input validation + // + // Validate the CA cert secret if provided + if instance.Spec.TLS.CaBundleSecretName != "" { + hash, ctrlResult, err := tls.ValidateCACertSecret( + ctx, + helper.GetClient(), + types.NamespacedName{ + Name: instance.Spec.TLS.CaBundleSecretName, + Namespace: instance.Namespace, + }, + ) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.TLSInputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.TLSInputErrorMessage, + err.Error())) + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + if hash != "" { + configVars[tls.CABundleKey] = env.SetValue(hash) + } + } + + // all cert input checks out so report InputReady + instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) + // // create custom config for this barbican service // @@ -489,11 +532,72 @@ func (r *BarbicanWorkerReconciler) reconcileNormal(ctx context.Context, instance // SetupWithManager sets up the controller with the Manager. func (r *BarbicanWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanWorker{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanWorker) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &barbicanv1beta1.BarbicanWorker{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*barbicanv1beta1.BarbicanWorker) + if cr.Spec.TLS.CaBundleSecretName == "" { + return nil + } + return []string{cr.Spec.TLS.CaBundleSecretName} + }); err != nil { + return err + } return ctrl.NewControllerManagedBy(mgr). For(&barbicanv1beta1.BarbicanWorker{}). //Owns(&corev1.Service{}). //Owns(&corev1.Secret{}). Owns(&appsv1.Deployment{}). //Owns(&routev1.Route{}). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } + +func (r *BarbicanWorkerReconciler) findObjectsForSrc(src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("BarbicanWorker") + + for _, field := range commonWatchFields { + crList := &barbicanv1beta1.BarbicanWorkerList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.List(context.TODO(), crList, listOps) + if err != nil { + return []reconcile.Request{} + } + + for _, item := range crList.Items { + l.Info(fmt.Sprintf("input source %s changed, reconcile: %s - %s", src.GetName(), item.GetName(), item.GetNamespace())) + + requests = append(requests, + reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: item.GetName(), + Namespace: item.GetNamespace(), + }, + }, + ) + } + } + + return requests +} diff --git a/go.mod b/go.mod index 3979d99..3761e36 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,13 @@ require ( github.com/openstack-k8s-operators/barbican-operator/api v0.0.0-00000000000000-000000000000 github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20240104150635-c4ffc51e0752 github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20240104144437-5355d932c316 - github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f + github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14 github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20240106101723-5f7aa263457f github.com/openstack-k8s-operators/mariadb-operator/api v0.3.0 k8s.io/api v0.26.12 k8s.io/apimachinery v0.27.1 k8s.io/client-go v0.26.12 + k8s.io/utils v0.0.0-20240102154912-e7106e64919e sigs.k8s.io/controller-runtime v0.14.7 ) @@ -75,7 +76,6 @@ require ( k8s.io/component-base v0.26.12 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect - k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 463b880..1b08457 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,8 @@ github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20240104150635-c github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20240104150635-c4ffc51e0752/go.mod h1:y4qeIT1ubUm9SKrvhVTuEYWSm0so38P5Hu3ZpdMJMek= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20240104144437-5355d932c316 h1:IwTuIoC78bbp3awd8P0tWeknCe2jNLB1FCJDIwI/2Pg= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20240104144437-5355d932c316/go.mod h1:qx+z+k0RMK8Vcl5Nug6bOScEg7ROSxEV4FFy0gjcQDQ= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f h1:ifW2n0TkrS1Wa58DK/N+zAKdGH5XQh4Llk/hefsXzN8= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240106101723-5f7aa263457f/go.mod h1:ov4lAbniNUsLqZCBp1RTixpqXc8JlzA5B+yTcCkJXQg= +github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14 h1:8batipIElAHscbsVUJz8w/2NOvu+pRi8ixF1XUP6WiQ= +github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240110131857-e70e1dec4d14/go.mod h1:ov4lAbniNUsLqZCBp1RTixpqXc8JlzA5B+yTcCkJXQg= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20240106101723-5f7aa263457f h1:bXaUzrP+JiBHSCQwmndGjD5nafFAK+t8X2oXVP8hj3c= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20240106101723-5f7aa263457f/go.mod h1:Lb1xXXJpbWxU619nemBD4XQy+rqRhzyNcGji9zZbG20= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20240106101723-5f7aa263457f h1:b9fpRkubG+tk6uKGCNz/kuTWYtpUFsm3d/jECF1AmAs= diff --git a/kuttl-test.yaml b/kuttl-test.yaml index 7f97fbd..7ac8e59 100644 --- a/kuttl-test.yaml +++ b/kuttl-test.yaml @@ -18,7 +18,7 @@ apiVersion: kuttl.dev/v1beta1 kind: TestSuite reportFormat: JSON reportName: kuttl-test-barbican -namespace: barbican-kuttl-tests +namespace: barbican-kuttl-tests timeout: 180 parallel: 1 suppress: diff --git a/pkg/barbican/dbsync.go b/pkg/barbican/dbsync.go index 0ecf75c..e310a8e 100644 --- a/pkg/barbican/dbsync.go +++ b/pkg/barbican/dbsync.go @@ -26,20 +26,22 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann // service, The two snippet files that it does need (DefaultsConfigFileName // and CustomConfigFileName) can be extracted from the top-level barbican // config-data secret. - dbSyncVolume := corev1.Volume{ - Name: "db-sync-config-data", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - DefaultMode: &config0644AccessMode, - SecretName: instance.Name + "-config-data", - Items: []corev1.KeyToPath{ - { - Key: DefaultsConfigFileName, - Path: DefaultsConfigFileName, - }, - { - Key: CustomConfigFileName, - Path: CustomConfigFileName, + dbSyncVolume := []corev1.Volume{ + { + Name: "db-sync-config-data", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: &config0644AccessMode, + SecretName: instance.Name + "-config-data", + Items: []corev1.KeyToPath{ + { + Key: DefaultsConfigFileName, + Path: DefaultsConfigFileName, + }, + { + Key: CustomConfigFileName, + Path: CustomConfigFileName, + }, }, }, }, @@ -59,6 +61,12 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann ReadOnly: true, }, } + + // add CA cert if defined + if instance.Spec.BarbicanAPI.TLS.CaBundleSecretName != "" { + dbSyncVolume = append(dbSyncVolume, instance.Spec.BarbicanAPI.TLS.CreateVolume()) + dbSyncMounts = append(dbSyncMounts, instance.Spec.BarbicanAPI.TLS.CreateVolumeMounts(nil)...) + } args := []string{"-c"} if instance.Spec.Debug.DBSync { args = append(args, common.DebugCommand) @@ -111,7 +119,7 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann ServiceName, secretNames, DbsyncPropagation), - dbSyncVolume, + dbSyncVolume..., ) return job diff --git a/pkg/barbicanapi/deployment.go b/pkg/barbicanapi/deployment.go index cde17f6..bebef5c 100644 --- a/pkg/barbicanapi/deployment.go +++ b/pkg/barbicanapi/deployment.go @@ -5,6 +5,8 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/env" + "github.com/openstack-k8s-operators/lib-common/modules/common/service" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,7 +27,7 @@ func Deployment( configHash string, labels map[string]string, annotations map[string]string, -) *appsv1.Deployment { +) (*appsv1.Deployment, error) { runAsUser := int64(0) var config0644AccessMode int32 = 0644 envVars := map[string]env.Setter{} @@ -62,6 +64,11 @@ func Deployment( Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(barbican.BarbicanPublicPort)}, } readinessProbe.HTTPGet = livenessProbe.HTTPGet + + if instance.Spec.TLS.API.Enabled(service.EndpointPublic) { + livenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + readinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + } } apiVolumes := []corev1.Volume{ @@ -89,6 +96,31 @@ func Deployment( // logging apiVolumeMounts = append(apiVolumeMounts, barbican.GetLogVolumeMount()...) + // add CA cert if defined + if instance.Spec.TLS.CaBundleSecretName != "" { + apiVolumes = append(apiVolumes, instance.Spec.TLS.CreateVolume()) + apiVolumeMounts = append(apiVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + + for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} { + if instance.Spec.TLS.API.Enabled(endpt) { + var tlsEndptCfg tls.GenericService + switch endpt { + case service.EndpointPublic: + tlsEndptCfg = instance.Spec.TLS.API.Public + case service.EndpointInternal: + tlsEndptCfg = instance.Spec.TLS.API.Internal + } + + svc, err := tlsEndptCfg.ToService() + if err != nil { + return nil, err + } + apiVolumes = append(apiVolumes, svc.CreateVolume(endpt.String())) + apiVolumeMounts = append(apiVolumeMounts, svc.CreateVolumeMounts(endpt.String())...) + } + } + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-api", instance.Name), @@ -156,5 +188,5 @@ func Deployment( barbican.BarbicanAPIPropagation), apiVolumes...) - return deployment + return deployment, nil } diff --git a/pkg/barbicankeystonelistener/deployment.go b/pkg/barbicankeystonelistener/deployment.go index 5c771d1..571222f 100644 --- a/pkg/barbicankeystonelistener/deployment.go +++ b/pkg/barbicankeystonelistener/deployment.go @@ -62,6 +62,12 @@ func Deployment( // logging keystoneListenerVolumeMounts = append(keystoneListenerVolumeMounts, barbican.GetLogVolumeMount()...) + // Add the CA bundle + if instance.Spec.TLS.CaBundleSecretName != "" { + keystoneListenerVolumes = append(keystoneListenerVolumes, instance.Spec.TLS.CreateVolume()) + keystoneListenerVolumeMounts = append(keystoneListenerVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-keystone-listener", instance.Name), diff --git a/pkg/barbicanworker/deployment.go b/pkg/barbicanworker/deployment.go index fb3633b..2d7dec8 100644 --- a/pkg/barbicanworker/deployment.go +++ b/pkg/barbicanworker/deployment.go @@ -8,6 +8,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + //"k8s.io/apimachinery/pkg/util/intstr" barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1" @@ -91,6 +92,12 @@ func Deployment( // logging workerVolumeMounts = append(workerVolumeMounts, barbican.GetLogVolumeMount()...) + // Add the CA bundle + if instance.Spec.TLS.CaBundleSecretName != "" { + workerVolumes = append(workerVolumes, instance.Spec.TLS.CreateVolume()) + workerVolumeMounts = append(workerVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-worker", instance.Name), diff --git a/templates/barbican/config/10-barbican_wsgi_main.conf b/templates/barbican/config/10-barbican_wsgi_main.conf index adff73d..cfdc646 100644 --- a/templates/barbican/config/10-barbican_wsgi_main.conf +++ b/templates/barbican/config/10-barbican_wsgi_main.conf @@ -1,5 +1,8 @@ +{{ if (index . "VHosts") }} +{{ range $endpt, $vhost := .VHosts }} +# {{ $endpt }} vhost {{ $vhost.ServerName }} configuration - ServerName barbicanapi.openstack.svc + ServerName {{ $vhost.ServerName }} ## Vhost docroot DocumentRoot "/var/www/cgi-bin/barbican" @@ -16,11 +19,21 @@ ErrorLog "/var/log/barbican/error.log" ServerSignature Off CustomLog "/var/log/barbican/access.log" combined env=!forwarded + +{{- if $vhost.TLS }} SetEnvIf X-Forwarded-Proto https HTTPS=1 + ## SSL directives + SSLEngine on + SSLCertificateFile "{{ $vhost.SSLCertificateFile }}" + SSLCertificateKeyFile "{{ $vhost.SSLCertificateKeyFile }}" +{{- end }} + ## WSGI configuration WSGIApplicationGroup %{GLOBAL} - WSGIDaemonProcess barbican-api display-name=barbican_wsgi_main group=barbican processes=8 threads=1 user=barbican - WSGIProcessGroup barbican-api + WSGIDaemonProcess {{ $endpt }} display-name={{ $endpt }} group=barbican processes=8 threads=1 user=barbican + WSGIProcessGroup {{ $endpt }} WSGIScriptAlias / "/var/www/cgi-bin/barbican/main" +{{ end }} +{{ end }} diff --git a/templates/barbican/config/barbican-api-config.json b/templates/barbican/config/barbican-api-config.json index 415bf86..13b6fc1 100644 --- a/templates/barbican/config/barbican-api-config.json +++ b/templates/barbican/config/barbican-api-config.json @@ -55,6 +55,12 @@ "owner": "root", "perm": "0755", "optional": true + }, + { + "source": "/var/lib/config-data/default/ssl.conf", + "dest": "/etc/httpd/conf.d/ssl.conf", + "owner": "root", + "perm": "0644" } ], "permissions": [ diff --git a/templates/barbican/config/barbican-keystone-listener b/templates/barbican/config/barbican-keystone-listener index 73b3f1b..4fc7c73 100644 --- a/templates/barbican/config/barbican-keystone-listener +++ b/templates/barbican/config/barbican-keystone-listener @@ -4,4 +4,3 @@ import sys from barbican.cmd.keystone_listener import main if __name__ == "__main__": sys.exit(main()) - diff --git a/templates/barbican/config/barbican-worker b/templates/barbican/config/barbican-worker index 82ff05b..e18e517 100644 --- a/templates/barbican/config/barbican-worker +++ b/templates/barbican/config/barbican-worker @@ -4,4 +4,3 @@ import sys from barbican.cmd.worker import main if __name__ == "__main__": sys.exit(main()) - diff --git a/templates/barbican/config/main b/templates/barbican/config/main index e3b15dc..04f35ec 100644 --- a/templates/barbican/config/main +++ b/templates/barbican/config/main @@ -50,4 +50,3 @@ else: with app_lock: if application is None: application = get_api_wsgi_script() - diff --git a/templates/barbican/config/ssl.conf b/templates/barbican/config/ssl.conf new file mode 100644 index 0000000..e3da4ec --- /dev/null +++ b/templates/barbican/config/ssl.conf @@ -0,0 +1,21 @@ + + SSLRandomSeed startup builtin + SSLRandomSeed startup file:/dev/urandom 512 + SSLRandomSeed connect builtin + SSLRandomSeed connect file:/dev/urandom 512 + + AddType application/x-x509-ca-cert .crt + AddType application/x-pkcs7-crl .crl + + SSLPassPhraseDialog builtin + SSLSessionCache "shmcb:/var/cache/mod_ssl/scache(512000)" + SSLSessionCacheTimeout 300 + Mutex default + SSLCryptoDevice builtin + SSLHonorCipherOrder On + SSLUseStapling Off + SSLStaplingCache "shmcb:/run/httpd/ssl_stapling(32768)" + SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!RC4:!3DES + SSLProtocol all -SSLv2 -SSLv3 -TLSv1 + SSLOptions StdEnvVars +