diff --git a/api/bases/barbican.openstack.org_barbicanapis.yaml b/api/bases/barbican.openstack.org_barbicanapis.yaml
index f52bb38..58018c2 100644
--- a/api/bases/barbican.openstack.org_barbicanapis.yaml
+++ b/api/bases/barbican.openstack.org_barbicanapis.yaml
@@ -361,6 +361,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 ddb1d63..2fa8aaa 100644
--- a/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml
+++ b/api/bases/barbican.openstack.org_barbicankeystonelisteners.yaml
@@ -183,6 +183,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 d9e0ee9..e52b1b4 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 aab3e31..21d6b57 100644
--- a/api/bases/barbican.openstack.org_barbicanworkers.yaml
+++ b/api/bases/barbican.openstack.org_barbicanworkers.yaml
@@ -181,6 +181,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/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 a633e6f..4d6f2de 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.
@@ -344,6 +345,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.
@@ -590,6 +592,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/crd/bases/barbican.openstack.org_barbicanapis.yaml b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml
index f52bb38..58018c2 100644
--- a/config/crd/bases/barbican.openstack.org_barbicanapis.yaml
+++ b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml
@@ -361,6 +361,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 ddb1d63..2fa8aaa 100644
--- a/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml
+++ b/config/crd/bases/barbican.openstack.org_barbicankeystonelisteners.yaml
@@ -183,6 +183,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 d9e0ee9..e52b1b4 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 aab3e31..21d6b57 100644
--- a/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml
+++ b/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml
@@ -181,6 +181,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/manifests/bases/barbican-operator.clusterserviceversion.yaml b/config/manifests/bases/barbican-operator.clusterserviceversion.yaml
index 0abc65f..27d60b6 100644
--- a/config/manifests/bases/barbican-operator.clusterserviceversion.yaml
+++ b/config/manifests/bases/barbican-operator.clusterserviceversion.yaml
@@ -18,16 +18,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 a51a9ca..8bdeca8 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).
@@ -624,6 +645,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{
@@ -652,7 +674,6 @@ func (r *BarbicanReconciler) workerDeploymentCreateOrUpdate(ctx context.Context,
}
func (r *BarbicanReconciler) keystoneListenerDeploymentCreateOrUpdate(ctx context.Context, instance *barbicanv1beta1.Barbican, helper *helper.Helper) (*barbicanv1beta1.BarbicanKeystoneListener, controllerutil.OperationResult, error) {
-
Log := r.GetLogger(ctx)
Log.Info(fmt.Sprintf("Creating barbican KeystoneListener spec. transporturlsecret: '%s'", instance.Status.TransportURLSecret))
Log.Info(fmt.Sprintf("database hostname: '%s'", instance.Status.DatabaseHostname))
@@ -661,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 37f27f2..e0889ba 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)
@@ -289,6 +299,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("%s-%s.%s.svc", barbican.ServiceName, 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)
}
@@ -400,7 +425,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 {
@@ -538,26 +568,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,
@@ -566,13 +630,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),
@@ -634,9 +696,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,
@@ -694,11 +785,96 @@ 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 12d9a31..400dd51 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
//
@@ -631,11 +666,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 b857d30..3683f7c 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)
@@ -331,6 +340,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
//
@@ -491,11 +534,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 08d0a96..be1a969 100644
--- a/go.mod
+++ b/go.mod
@@ -16,9 +16,11 @@ require (
github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20240117103205-2bd91a3da216
github.com/openstack-k8s-operators/mariadb-operator/api v0.3.1-0.20240124160436-36095347284f
go.uber.org/zap v1.26.0
+ golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
k8s.io/api v0.26.13
k8s.io/apimachinery v0.27.1
k8s.io/client-go v0.26.13
+ k8s.io/utils v0.0.0-20240102154912-e7106e64919e
sigs.k8s.io/controller-runtime v0.14.7
)
@@ -59,7 +61,6 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/multierr v1.10.0 // indirect
- golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
@@ -78,7 +79,6 @@ require (
k8s.io/component-base v0.26.13 // 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/pkg/barbican/dbsync.go b/pkg/barbican/dbsync.go
index c22c1c1..c8e5692 100644
--- a/pkg/barbican/dbsync.go
+++ b/pkg/barbican/dbsync.go
@@ -16,7 +16,6 @@ const (
// DbSyncJob func
func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, annotations map[string]string) *batchv1.Job {
-
secretNames := []string{}
var config0644AccessMode int32 = 0644
@@ -25,20 +24,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,
+ },
},
},
},
@@ -58,6 +59,13 @@ 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", DBSyncCommand}
runAsUser := int64(0)
@@ -105,7 +113,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 f1d942e..828a8e6 100644
--- a/pkg/barbicanapi/deployment.go
+++ b/pkg/barbicanapi/deployment.go
@@ -4,6 +4,8 @@ import (
"fmt"
"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"
@@ -24,7 +26,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{}
@@ -52,6 +54,12 @@ func Deployment(
}
readinessProbe.HTTPGet = livenessProbe.HTTPGet
+ if instance.Spec.TLS.API.Enabled(service.EndpointPublic) {
+ livenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
+ readinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS
+ }
+ readinessProbe.HTTPGet = livenessProbe.HTTPGet
+
apiVolumes := []corev1.Volume{
{
Name: "config-data-custom",
@@ -77,6 +85,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),
@@ -151,5 +184,5 @@ func Deployment(
barbican.BarbicanAPIPropagation),
apiVolumes...)
- return deployment
+ return deployment, nil
}
diff --git a/pkg/barbicankeystonelistener/deployment.go b/pkg/barbicankeystonelistener/deployment.go
index 8d96c78..ecdb8c8 100644
--- a/pkg/barbicankeystonelistener/deployment.go
+++ b/pkg/barbicankeystonelistener/deployment.go
@@ -56,6 +56,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 995b546..0f1e4a6 100644
--- a/pkg/barbicanworker/deployment.go
+++ b/pkg/barbicanworker/deployment.go
@@ -80,6 +80,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..f545011 100644
--- a/templates/barbican/config/barbican-api-config.json
+++ b/templates/barbican/config/barbican-api-config.json
@@ -1,67 +1,89 @@
{
- "command": "/usr/sbin/httpd -DFOREGROUND",
- "config_files": [
- {
- "source": "/var/lib/config-data/default/00-default.conf",
- "dest": "/etc/barbican/barbican.conf.d/00-default.conf",
- "owner": "barbican",
- "perm": "0600"
- },
- {
- "source": "/var/lib/config-data/default/02-service.conf",
- "dest": "/etc/barbican/barbican.conf.d/02-service.conf",
- "owner": "barbican",
- "perm": "0600",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/03-secrets.conf",
- "dest": "/etc/barbican/barbican.conf.d/03-secrets.conf",
- "owner": "barbican",
- "perm": "0640",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/10-barbican_wsgi_main.conf",
- "dest": "/etc/httpd/conf.d/10-barbican_wsgi_main.conf",
- "owner": "root",
- "perm": "0640",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/httpd.conf",
- "dest": "/etc/httpd/conf/httpd.conf",
- "owner": "root",
- "perm": "0640",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/main",
- "dest": "/var/www/cgi-bin/barbican/main",
- "owner": "barbican",
- "perm": "0640",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/mime.conf",
- "dest": "/etc/httpd/conf.modules.d/mime.conf",
- "owner": "root",
- "perm": "0640",
- "optional": true
- },
- {
- "source": "/var/lib/config-data/default/kolla_extend_start",
- "dest": "/usr/local/bin/kolla_extend_start",
- "owner": "root",
- "perm": "0755",
- "optional": true
- }
- ],
- "permissions": [
- {
- "path": "/var/log/barbican",
- "owner": "barbican:barbican",
- "recurse": true
- }
- ]
+ "command": "/usr/sbin/httpd -DFOREGROUND",
+ "config_files": [
+ {
+ "source": "/var/lib/config-data/default/00-default.conf",
+ "dest": "/etc/barbican/barbican.conf.d/00-default.conf",
+ "owner": "barbican",
+ "perm": "0600"
+ },
+ {
+ "source": "/var/lib/config-data/default/02-service.conf",
+ "dest": "/etc/barbican/barbican.conf.d/02-service.conf",
+ "owner": "barbican",
+ "perm": "0600",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/03-secrets.conf",
+ "dest": "/etc/barbican/barbican.conf.d/03-secrets.conf",
+ "owner": "barbican",
+ "perm": "0640",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/10-barbican_wsgi_main.conf",
+ "dest": "/etc/httpd/conf.d/10-barbican_wsgi_main.conf",
+ "owner": "root",
+ "perm": "0640",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/httpd.conf",
+ "dest": "/etc/httpd/conf/httpd.conf",
+ "owner": "root",
+ "perm": "0640",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/main",
+ "dest": "/var/www/cgi-bin/barbican/main",
+ "owner": "barbican",
+ "perm": "0640",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/mime.conf",
+ "dest": "/etc/httpd/conf.modules.d/mime.conf",
+ "owner": "root",
+ "perm": "0640",
+ "optional": true
+ },
+ {
+ "source": "/var/lib/config-data/default/kolla_extend_start",
+ "dest": "/usr/local/bin/kolla_extend_start",
+ "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"
+ },
+ {
+ "source": "/var/lib/config-data/tls/certs/*",
+ "dest": "/etc/pki/tls/certs/",
+ "owner": "root",
+ "perm": "0640",
+ "optional": true,
+ "merge": true
+ },
+ {
+ "source": "/var/lib/config-data/tls/private/*",
+ "dest": "/etc/pki/tls/private/",
+ "owner": "root",
+ "perm": "0600",
+ "optional": true,
+ "merge": true
+ }
+ ],
+ "permissions": [
+ {
+ "path": "/var/log/barbican",
+ "owner": "barbican:barbican",
+ "recurse": true
+ }
+ ]
}
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
+
diff --git a/tests/functional/barbican_controller_test.go b/tests/functional/barbican_controller_test.go
index 62518a3..cb7aec1 100644
--- a/tests/functional/barbican_controller_test.go
+++ b/tests/functional/barbican_controller_test.go
@@ -1,62 +1,30 @@
-package functional_test
+package functional
import (
- "os"
-
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
+ . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
+
barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
- . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
)
var _ = Describe("Barbican controller", func() {
-
- var barbicanName types.NamespacedName
- var barbicanTransportURL types.NamespacedName
- var dbSyncJobName types.NamespacedName
- var barbicanConfigMapData types.NamespacedName
-
- BeforeEach(func() {
-
- barbicanName = types.NamespacedName{
- Name: "barbican",
- Namespace: namespace,
- }
- barbicanTransportURL = types.NamespacedName{
- Name: "barbican-barbican-transport",
- Namespace: namespace,
- }
- dbSyncJobName = types.NamespacedName{
- Name: "barbican-db-sync",
- Namespace: namespace,
- }
- barbicanConfigMapData = types.NamespacedName{
- Name: "barbican-config-data",
- Namespace: namespace,
- }
-
- err := os.Setenv("OPERATOR_TEMPLATES", "../../templates")
- Expect(err).NotTo(HaveOccurred())
-
- })
-
When("A Barbican instance is created", func() {
BeforeEach(func() {
- DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanName, GetDefaultBarbicanSpec()))
+ DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, GetDefaultBarbicanSpec()))
})
It("should have the Spec fields defaulted", func() {
- Barbican := GetBarbican(barbicanName)
+ Barbican := GetBarbican(barbicanTest.Instance)
Expect(Barbican.Spec.ServiceUser).Should(Equal("barbican"))
Expect(Barbican.Spec.DatabaseInstance).Should(Equal("openstack"))
Expect(Barbican.Spec.DatabaseUser).Should(Equal("barbican"))
})
It("should have the Status fields initialized", func() {
- Barbican := GetBarbican(barbicanName)
+ Barbican := GetBarbican(barbicanTest.Instance)
Expect(Barbican.Status.Hash).To(BeEmpty())
Expect(Barbican.Status.BarbicanAPIReadyCount).To(Equal(int32(0)))
Expect(Barbican.Status.BarbicanWorkerReadyCount).To(Equal(int32(0)))
@@ -67,14 +35,14 @@ var _ = Describe("Barbican controller", func() {
It("should have input not ready and unknown Conditions initialized", func() {
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.ReadyCondition,
corev1.ConditionFalse,
)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.InputReadyCondition,
corev1.ConditionUnknown,
@@ -87,7 +55,7 @@ var _ = Describe("Barbican controller", func() {
condition.NetworkAttachmentsReadyCondition,
} {
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
cond,
corev1.ConditionUnknown,
@@ -98,126 +66,179 @@ var _ = Describe("Barbican controller", func() {
// the reconciler loop adds the finalizer so we have to wait for
// it to run
Eventually(func() []string {
- return GetBarbican(barbicanName).Finalizers
+ return GetBarbican(barbicanTest.Instance).Finalizers
}, timeout, interval).Should(ContainElement("Barbican"))
})
It("should not create a config map", func() {
Eventually(func() []corev1.ConfigMap {
- return th.ListConfigMaps(barbicanConfigMapData.Name).Items
+ return th.ListConfigMaps(barbicanTest.BarbicanConfigMapData.Name).Items
}, timeout, interval).Should(BeEmpty())
})
})
When("Barbican DB is created", func() {
BeforeEach(func() {
- DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanName.Namespace, "rabbitmq-secret"))
- DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanName, GetDefaultBarbicanSpec()))
- DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(namespace, SecretName))
+ DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanTest.Instance.Namespace, "rabbitmq-secret"))
+ DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, GetDefaultBarbicanSpec()))
+ DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(barbicanTest.Instance.Namespace, SecretName))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
- namespace,
- GetBarbican(barbicanName).Spec.DatabaseInstance,
+ barbicanTest.Instance.Namespace,
+ GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
- infra.SimulateTransportURLReady(barbicanTransportURL)
- DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanName.Namespace))
- //DeferCleanup(infra.DeleteMemcached, infra.CreateMemcached(namespace, "memcached", memcachedSpec))
+ infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL)
+ DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace))
})
It("Should set DBReady Condition and set DatabaseHostname Status when DB is Created", func() {
- mariadb.SimulateMariaDBDatabaseCompleted(barbicanName)
- th.SimulateJobSuccess(dbSyncJobName)
- Barbican := GetBarbican(barbicanName)
+ mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.Instance)
+ th.SimulateJobSuccess(barbicanTest.BarbicanDBSync)
+ Barbican := GetBarbican(barbicanTest.Instance)
Expect(Barbican.Status.DatabaseHostname).To(Equal("hostname-for-openstack"))
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
- condition.InputReadyCondition,
+ condition.DBReadyCondition,
corev1.ConditionTrue,
)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.DBSyncReadyCondition,
corev1.ConditionFalse,
)
})
It("Should fail if db-sync job fails when DB is Created", func() {
- mariadb.SimulateMariaDBDatabaseCompleted(barbicanName)
- th.SimulateJobFailure(dbSyncJobName)
+ mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.Instance)
+ th.SimulateJobFailure(barbicanTest.BarbicanDBSync)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.DBReadyCondition,
corev1.ConditionTrue,
)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.DBSyncReadyCondition,
corev1.ConditionFalse,
)
})
It("Does not create BarbicanAPI", func() {
- BarbicanAPINotExists(barbicanName)
+ BarbicanAPINotExists(barbicanTest.Instance)
})
It("Does not create BarbicanWorker", func() {
- BarbicanWorkerNotExists(barbicanName)
+ BarbicanWorkerNotExists(barbicanTest.Instance)
})
It("Does not create BarbicanKeystoneListener", func() {
- BarbicanKeystoneListenerNotExists(barbicanName)
+ BarbicanKeystoneListenerNotExists(barbicanTest.Instance)
})
})
When("DB sync is completed", func() {
BeforeEach(func() {
- DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanName.Namespace, "rabbitmq-secret"))
- DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanName, GetDefaultBarbicanSpec()))
- DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(namespace, SecretName))
+ DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanTest.Instance.Namespace, "rabbitmq-secret"))
+ DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, GetDefaultBarbicanSpec()))
+ DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(barbicanTest.Instance.Namespace, SecretName))
DeferCleanup(
- k8sClient.Delete, ctx, CreateBarbicanSecret(barbicanName.Namespace, "test-osp-secret-berbican"))
+ k8sClient.Delete, ctx, CreateBarbicanSecret(barbicanTest.Instance.Namespace, "test-osp-secret-barbican"))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
- namespace,
- GetBarbican(barbicanName).Spec.DatabaseInstance,
+ barbicanTest.Instance.Namespace,
+ GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
- infra.SimulateTransportURLReady(barbicanTransportURL)
- DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanName.Namespace))
- mariadb.SimulateMariaDBDatabaseCompleted(barbicanName)
- th.SimulateJobSuccess(dbSyncJobName)
+ infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL)
+ DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace))
+ mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.Instance)
+ th.SimulateJobSuccess(barbicanTest.BarbicanDBSync)
})
It("should have db sync ready condition", func() {
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.ReadyCondition,
corev1.ConditionFalse,
)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
barbicanv1beta1.BarbicanRabbitMQTransportURLReadyCondition,
corev1.ConditionTrue,
)
th.ExpectCondition(
- barbicanName,
+ barbicanTest.Instance,
ConditionGetterFunc(BarbicanConditionGetter),
condition.DBSyncReadyCondition,
corev1.ConditionTrue,
)
})
})
+ When("A Barbican with TLS is created", func() {
+ BeforeEach(func() {
+ DeferCleanup(th.DeleteInstance, CreateBarbican(barbicanTest.Instance, GetTLSBarbicanSpec()))
+ DeferCleanup(k8sClient.Delete, ctx, CreateBarbicanMessageBusSecret(barbicanTest.Instance.Namespace, barbicanTest.RabbitmqSecretName))
+ DeferCleanup(th.DeleteInstance, CreateBarbicanAPI(barbicanTest.Instance, GetTLSBarbicanAPISpec()))
+ DeferCleanup(k8sClient.Delete, ctx, CreateKeystoneAPISecret(barbicanTest.Instance.Namespace, SecretName))
+ DeferCleanup(
+ mariadb.DeleteDBService,
+ mariadb.CreateDBService(
+ barbicanTest.Instance.Namespace,
+ GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance,
+ corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{{Port: 3306}},
+ },
+ ),
+ )
+ infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL)
+ DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace))
+ mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.Instance)
+ th.SimulateJobSuccess(barbicanTest.BarbicanDBSync)
+ })
+
+ It("Creates BarbicanAPI", func() {
+ DeferCleanup(k8sClient.Delete, ctx, th.CreateCABundleSecret(barbicanTest.CABundleSecret))
+ DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(barbicanTest.InternalCertSecret))
+ DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(barbicanTest.PublicCertSecret))
+ keystone.SimulateKeystoneEndpointReady(barbicanTest.BarbicanKeystoneEndpoint)
+
+ BarbicanAPIExists(barbicanTest.Instance)
+
+ d := th.GetDeployment(barbicanTest.BarbicanAPI)
+ // Check the resulting deployment fields
+ Expect(int(*d.Spec.Replicas)).To(Equal(1))
+
+ Expect(d.Spec.Template.Spec.Volumes).To(HaveLen(6))
+ Expect(d.Spec.Template.Spec.Containers).To(HaveLen(2))
+
+ // cert deployment volumes
+ th.AssertVolumeExists(barbicanTest.CABundleSecret.Name, d.Spec.Template.Spec.Volumes)
+ th.AssertVolumeExists(barbicanTest.InternalCertSecret.Name, d.Spec.Template.Spec.Volumes)
+ th.AssertVolumeExists(barbicanTest.PublicCertSecret.Name, d.Spec.Template.Spec.Volumes)
+
+ // cert volumeMounts
+ container := d.Spec.Template.Spec.Containers[1]
+ th.AssertVolumeMountExists(barbicanTest.InternalCertSecret.Name, "tls.key", container.VolumeMounts)
+ th.AssertVolumeMountExists(barbicanTest.InternalCertSecret.Name, "tls.crt", container.VolumeMounts)
+ th.AssertVolumeMountExists(barbicanTest.PublicCertSecret.Name, "tls.key", container.VolumeMounts)
+ th.AssertVolumeMountExists(barbicanTest.PublicCertSecret.Name, "tls.crt", container.VolumeMounts)
+ th.AssertVolumeMountExists(barbicanTest.CABundleSecret.Name, "tls-ca-bundle.pem", container.VolumeMounts)
+
+ Expect(container.ReadinessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS))
+ Expect(container.LivenessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS))
+ })
+ })
})
diff --git a/tests/functional/barbican_test_data.go b/tests/functional/barbican_test_data.go
new file mode 100644
index 0000000..6ec70b4
--- /dev/null
+++ b/tests/functional/barbican_test_data.go
@@ -0,0 +1,167 @@
+/*
+Copyright 2023.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package functional implements the envTest coverage for barbican-operator
+package functional
+
+import (
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/types"
+)
+
+type APIType string
+
+const (
+ // BarbicanAPIInternal -
+ BarbicanAPITypeInternal APIType = "internal"
+ // BarbicanAPITypeExternal
+ BarbicanAPITypePublic APIType = "public"
+ // PublicCertSecretName -
+ PublicCertSecretName = "public-tls-certs"
+ // InternalCertSecretName -
+ InternalCertSecretName = "internal-tls-certs"
+ // CABundleSecretName -
+ CABundleSecretName = "combined-ca-bundle"
+)
+
+// BarbicanTestData is the data structure used to provide input data to envTest
+type BarbicanTestData struct {
+ BarbicanDatabaseUser string
+ BarbicanPassword string
+ BarbicanServiceUser string
+ ContainerImage string
+ DatabaseHostname string
+ DatabaseInstance string
+ RabbitmqClusterName string
+ RabbitmqSecretName string
+ Instance types.NamespacedName
+ Barbican types.NamespacedName
+ BarbicanDBSync types.NamespacedName
+ BarbicanAPI types.NamespacedName
+ BarbicanRole types.NamespacedName
+ BarbicanRoleBinding types.NamespacedName
+ BarbicanTransportURL types.NamespacedName
+ BarbicanSA types.NamespacedName
+ BarbicanKeystoneService types.NamespacedName
+ BarbicanKeystoneEndpoint types.NamespacedName
+ BarbicanServicePublic types.NamespacedName
+ BarbicanServiceInternal types.NamespacedName
+ BarbicanConfigSecret types.NamespacedName
+ BarbicanConfigScripts types.NamespacedName
+ BarbicanConfigMapData types.NamespacedName
+ BarbicanScheduler types.NamespacedName
+ InternalAPINAD types.NamespacedName
+ CABundleSecret types.NamespacedName
+ InternalCertSecret types.NamespacedName
+ PublicCertSecret types.NamespacedName
+}
+
+// GetBarbicanTestData is a function that initialize the BarbicanTestData
+// used in the test
+func GetBarbicanTestData(barbicanName types.NamespacedName) BarbicanTestData {
+ m := barbicanName
+ return BarbicanTestData{
+ Instance: m,
+
+ Barbican: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: barbicanName.Name,
+ },
+ BarbicanDBSync: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-db-sync", barbicanName.Name),
+ },
+ BarbicanAPI: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-api-api", barbicanName.Name),
+ },
+ BarbicanRole: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("barbican-%s-role", barbicanName.Name),
+ },
+ BarbicanRoleBinding: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("barbican-%s-rolebinding", barbicanName.Name),
+ },
+ BarbicanTransportURL: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("barbican-%s-transport", barbicanName.Name),
+ },
+ BarbicanSA: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("barbican-%s", barbicanName.Name),
+ },
+ BarbicanKeystoneService: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: barbicanName.Name,
+ },
+ BarbicanKeystoneEndpoint: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-api", barbicanName.Name),
+ },
+ // Also used to identify BarbicanRoutePublic
+ BarbicanServicePublic: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-public", barbicanName.Name),
+ },
+ BarbicanServiceInternal: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-internal", barbicanName.Name),
+ },
+ BarbicanConfigSecret: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-%s", barbicanName.Name, "config-data"),
+ },
+ BarbicanConfigScripts: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-%s", barbicanName.Name, "scripts"),
+ },
+ BarbicanConfigMapData: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-%s", barbicanName.Name, "config-data"),
+ },
+ BarbicanScheduler: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: fmt.Sprintf("%s-scheduler", barbicanName.Name),
+ },
+ InternalAPINAD: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: "internalapi",
+ },
+ CABundleSecret: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: CABundleSecretName,
+ },
+ InternalCertSecret: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: InternalCertSecretName,
+ },
+ PublicCertSecret: types.NamespacedName{
+ Namespace: barbicanName.Namespace,
+ Name: PublicCertSecretName,
+ },
+ RabbitmqClusterName: "rabbitmq",
+ RabbitmqSecretName: "rabbitmq-secret",
+ BarbicanDatabaseUser: "barbican",
+ DatabaseInstance: "openstack",
+ // Password used for both db and service
+ BarbicanPassword: "12345678",
+ BarbicanServiceUser: "barbican",
+ ContainerImage: "test://barbican",
+ DatabaseHostname: "database-hostname",
+ }
+}
diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go
index b9309fe..d6d4afc 100644
--- a/tests/functional/base_test.go
+++ b/tests/functional/base_test.go
@@ -14,10 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package functional_test
+package functional
import (
"fmt"
+
+ maps "golang.org/x/exp/maps"
+
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
@@ -47,7 +50,6 @@ func GetDefaultBarbicanSpec() map[string]interface{} {
}
func CreateBarbican(name types.NamespacedName, spec map[string]interface{}) client.Object {
-
raw := map[string]interface{}{
"apiVersion": "barbican.openstack.org/v1beta1",
"kind": "Barbican",
@@ -117,3 +119,81 @@ func BarbicanKeystoneListenerNotExists(name types.NamespacedName) {
g.Expect(k8s_errors.IsNotFound(err)).To(BeTrue())
}, timeout, interval).Should(Succeed())
}
+
+// ========== TLS Stuff ==============
+func BarbicanAPIConditionGetter(name types.NamespacedName) condition.Conditions {
+ instance := GetBarbicanAPI(name)
+ return instance.Status.Conditions
+}
+
+func BarbicanAPIExists(name types.NamespacedName) {
+ Consistently(func(g Gomega) {
+ instance := &barbicanv1.BarbicanAPI{}
+ err := k8sClient.Get(ctx, name, instance)
+ g.Expect(k8s_errors.IsNotFound(err)).To(BeFalse())
+ }, timeout, interval).Should(Succeed())
+}
+
+func GetBarbicanAPI(name types.NamespacedName) *barbicanv1.BarbicanAPI {
+ instance := &barbicanv1.BarbicanAPI{}
+ Eventually(func(g Gomega) {
+ g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed())
+ }, timeout, interval).Should(Succeed())
+ return instance
+}
+
+func GetTLSBarbicanSpec() map[string]interface{} {
+ return map[string]interface{}{
+ "databaseInstance": "openstack",
+ "secret": SecretName,
+ "barbicanAPI": GetTLSBarbicanAPISpec(),
+ }
+}
+
+func GetTLSBarbicanAPISpec() map[string]interface{} {
+ spec := GetDefaultBarbicanAPISpec()
+ maps.Copy(spec, map[string]interface{}{
+ "tls": map[string]interface{}{
+ "api": map[string]interface{}{
+ "internal": map[string]interface{}{
+ "secretName": InternalCertSecretName,
+ },
+ "public": map[string]interface{}{
+ "secretName": PublicCertSecretName,
+ },
+ },
+ "caBundleSecretName": CABundleSecretName,
+ },
+ })
+ return spec
+}
+
+func GetDefaultBarbicanAPISpec() map[string]interface{} {
+ return map[string]interface{}{
+ "secret": SecretName,
+ "replicas": 1,
+ "databaseHostname": barbicanTest.DatabaseHostname,
+ "databaseInstance": barbicanTest.DatabaseInstance,
+ "containerImage": barbicanTest.ContainerImage,
+ "serviceAccount": barbicanTest.BarbicanSA.Name,
+ "transportURLSecret": barbicanTest.RabbitmqSecretName,
+ }
+}
+
+func CreateBarbicanAPI(name types.NamespacedName, spec map[string]interface{}) client.Object {
+ // we get the parent CR and set ownership to the barbicanAPI CR
+ raw := map[string]interface{}{
+ "apiVersion": "barbican.openstack.org/v1beta1",
+ "kind": "BarbicanAPI",
+ "metadata": map[string]interface{}{
+ "annotations": map[string]interface{}{
+ "keystoneEndpoint": "true",
+ },
+ "name": name.Name,
+ "namespace": name.Namespace,
+ },
+ "spec": spec,
+ }
+
+ return th.CreateUnstructured(raw)
+}
diff --git a/tests/functional/suite_test.go b/tests/functional/suite_test.go
index a65d955..5638b5a 100644
--- a/tests/functional/suite_test.go
+++ b/tests/functional/suite_test.go
@@ -1,4 +1,4 @@
-package functional_test
+package functional
import (
"context"
@@ -15,6 +15,7 @@ import (
. "github.com/onsi/gomega"
"go.uber.org/zap/zapcore"
+ "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
@@ -44,17 +45,19 @@ import (
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var (
- cfg *rest.Config
- k8sClient client.Client
- testEnv *envtest.Environment
- ctx context.Context
- cancel context.CancelFunc
- logger logr.Logger
- th *common_test.TestHelper
- keystone *keystone_test.TestHelper
- mariadb *mariadb_test.TestHelper
- infra *infra_test.TestHelper
- namespace string
+ cfg *rest.Config
+ k8sClient client.Client
+ testEnv *envtest.Environment
+ ctx context.Context
+ cancel context.CancelFunc
+ logger logr.Logger
+ th *common_test.TestHelper
+ keystone *keystone_test.TestHelper
+ mariadb *mariadb_test.TestHelper
+ infra *infra_test.TestHelper
+ namespace string
+ barbicanName types.NamespacedName
+ barbicanTest BarbicanTestData
)
const (
@@ -138,6 +141,7 @@ var _ = BeforeSuite(func() {
err = appsv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
+ logger = ctrl.Log.WithName("---Test---")
//+kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
@@ -170,11 +174,6 @@ var _ = BeforeSuite(func() {
kclient, err := kubernetes.NewForConfig(cfg)
Expect(err).ToNot(HaveOccurred(), "failed to create kclient")
- err = (&barbicanv1.Barbican{}).SetupWebhookWithManager(k8sManager)
- Expect(err).NotTo(HaveOccurred())
-
- barbicanv1.SetupDefaults()
-
err = (&controllers.BarbicanReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
@@ -182,6 +181,18 @@ var _ = BeforeSuite(func() {
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())
+ err = (&controllers.BarbicanAPIReconciler{
+ Client: k8sManager.GetClient(),
+ Scheme: k8sManager.GetScheme(),
+ Kclient: kclient,
+ }).SetupWithManager(k8sManager)
+ Expect(err).ToNot(HaveOccurred())
+
+ barbicanv1.SetupDefaults()
+
+ err = (&barbicanv1.Barbican{}).SetupWebhookWithManager(k8sManager)
+ Expect(err).NotTo(HaveOccurred())
+
go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctx)
@@ -216,5 +227,12 @@ var _ = BeforeEach(func() {
th.CreateNamespace(namespace)
// We still request the delete of the Namespace to properly cleanup if
// we run the test in an existing cluster.
+ barbicanName = types.NamespacedName{
+ Namespace: namespace,
+ Name: "barbican",
+ }
+
+ barbicanTest = GetBarbicanTestData(barbicanName)
+
DeferCleanup(th.DeleteNamespace, namespace)
})