From 533d0d0c080f3907d7e268af056648d1e38d005e Mon Sep 17 00:00:00 2001 From: Veronika Fisarova Date: Thu, 7 Dec 2023 12:51:01 +0100 Subject: [PATCH] [tlse] tls for PlacementAPI pod configuration Public/Internal service cert secrets and the CA bundle secret can be passed to configure httpd virtual hosts for tls termination. The certs get direct mounted to the appropriate place in etc/pki/tls/certs/%s.crt|key and a CA bundle to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem. Depends-On: openstack-k8s-operators/lib-common#384 Signed-off-by: Veronika Fisarova --- ...placement.openstack.org_placementapis.yaml | 30 +++ api/go.mod | 12 ++ api/go.sum | 19 +- api/v1beta1/placementapi_types.go | 6 + api/v1beta1/zz_generated.deepcopy.go | 1 + ...placement.openstack.org_placementapis.yaml | 30 +++ .../placement_v1beta1_placementtls.yaml | 25 +++ controllers/placementapi_controller.go | 179 +++++++++++++++++- go.mod | 2 + go.sum | 6 +- pkg/placement/dbsync.go | 16 +- pkg/placement/deployment.go | 56 +++++- templates/placementapi/config/httpd.conf | 24 +++ .../config/placement-api-config.json | 12 ++ templates/placementapi/config/ssl.conf | 21 ++ tests/functional/base_test.go | 57 ++++-- .../placementapi_controller_test.go | 60 +++++- tests/functional/suite_test.go | 6 + 18 files changed, 523 insertions(+), 39 deletions(-) create mode 100644 config/samples/placement_v1beta1_placementtls.yaml create mode 100644 templates/placementapi/config/ssl.conf diff --git a/api/bases/placement.openstack.org_placementapis.yaml b/api/bases/placement.openstack.org_placementapis.yaml index 40e1a833..fb688c69 100644 --- a/api/bases/placement.openstack.org_placementapis.yaml +++ b/api/bases/placement.openstack.org_placementapis.yaml @@ -365,6 +365,36 @@ spec: description: ServiceUser - optional username used for this service to register in keystone 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 required: - containerImage - databaseInstance diff --git a/api/go.mod b/api/go.mod index 1aea7671..ea419b48 100644 --- a/api/go.mod +++ b/api/go.mod @@ -41,6 +41,7 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.8.3 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sys v0.15.0 // indirect @@ -67,3 +68,14 @@ require ( // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +replace ( //allow-merging + github.com/google/gnostic => github.com/google/gnostic v0.6.9 + // pin to k8s 0.26.x for now + k8s.io/api => k8s.io/api v0.26.11 + k8s.io/apimachinery => k8s.io/apimachinery v0.26.11 + k8s.io/client-go => k8s.io/client-go v0.26.11 + sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.14.7 +) + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8 diff --git a/api/go.sum b/api/go.sum index a00268ae..1ad0af59 100644 --- a/api/go.sum +++ b/api/go.sum @@ -62,6 +62,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8 h1:B3jTaWtvyCT4O7uOvGwQN80mC18e4+IFNxNk4MZHkPE= +github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8/go.mod h1:IDd4i2ZXWELCF+Y8Zu9bQBobE6yy3HOEjUeLnSuSWaM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -220,8 +222,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231230095328-700482794743 h1:nElSEojlu7JxfpmF5c4zb2F3bjbQigpeiheV6Eus6RI= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231230095328-700482794743/go.mod h1:IDd4i2ZXWELCF+Y8Zu9bQBobE6yy3HOEjUeLnSuSWaM= 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= @@ -274,8 +274,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -609,14 +610,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.26.12 h1:jJm3s5ot05SUN3tPGg3b+XWuBE7rO/X0+dnVMhxyd5o= -k8s.io/api v0.26.12/go.mod h1:N+HUXukmtXNOKDngxXrEPbZWggWx01tH/N0nG4nV0oo= +k8s.io/api v0.26.11 h1:hLhTZRdYc3vBBOY4wbEyTLWgMyieOAk2Ws9NG57QqO4= +k8s.io/api v0.26.11/go.mod h1:bSr/A0TKRt5W2OMDdexkM/ER1NxOxiQqNNFXW2nMZrM= k8s.io/apiextensions-apiserver v0.26.12 h1:WHfFheB9AM0eHZsz6wu2h/KVmZ8PM7ZAmNDr3smkUzA= k8s.io/apiextensions-apiserver v0.26.12/go.mod h1:bvr3OVCML7icxP4rq/fJaNBPPiZ9KIi79n/icBbg5Rc= -k8s.io/apimachinery v0.26.12 h1:y+OgufxqLIZtyXIydRhjLBGzrYLF+qwiDdCFXYOjeN4= -k8s.io/apimachinery v0.26.12/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y= -k8s.io/client-go v0.26.12 h1:kPpTpIeFNqwo4UyvoqzNp3DNK2mbGcdGv23eS1U8VMo= -k8s.io/client-go v0.26.12/go.mod h1:V7thEnIFroyNZOU30dKLiiVeqQmJz45shJG1mu7nONQ= +k8s.io/apimachinery v0.26.11 h1:w//840HHdwSRKqD15j9YX9HLlU6RPlfrvW0xEhLk2+0= +k8s.io/apimachinery v0.26.11/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y= +k8s.io/client-go v0.26.11 h1:RjfZr5+vQjjTRmk4oCqHyC0cgrZXPjw+X+ge35sk4GI= +k8s.io/client-go v0.26.11/go.mod h1:+emNszw9va/uRJIM5ALTBtFnlZMTjwBrNjRfEh0iuw8= k8s.io/component-base v0.26.12 h1:OyYjCtruv4/Yau5Z1v6e59N+JRDTj8JnW95W9w9AMpg= k8s.io/component-base v0.26.12/go.mod h1:X98Et5BxJ8i4TcDusUcKS8EYxCujBU1lCL3pc/CUtHQ= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= diff --git a/api/v1beta1/placementapi_types.go b/api/v1beta1/placementapi_types.go index 40447c26..35a6b9fe 100644 --- a/api/v1beta1/placementapi_types.go +++ b/api/v1beta1/placementapi_types.go @@ -19,6 +19,7 @@ package v1beta1 import ( condition "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" "github.com/openstack-k8s-operators/lib-common/modules/common/util" corev1 "k8s.io/api/core/v1" @@ -115,6 +116,11 @@ type PlacementAPISpec struct { // +kubebuilder:validation:Optional // 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/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 5067acac..202b2c1d 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -184,6 +184,7 @@ func (in *PlacementAPISpec) DeepCopyInto(out *PlacementAPISpec) { copy(*out, *in) } in.Override.DeepCopyInto(&out.Override) + in.TLS.DeepCopyInto(&out.TLS) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementAPISpec. diff --git a/config/crd/bases/placement.openstack.org_placementapis.yaml b/config/crd/bases/placement.openstack.org_placementapis.yaml index 40e1a833..fb688c69 100644 --- a/config/crd/bases/placement.openstack.org_placementapis.yaml +++ b/config/crd/bases/placement.openstack.org_placementapis.yaml @@ -365,6 +365,36 @@ spec: description: ServiceUser - optional username used for this service to register in keystone 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 required: - containerImage - databaseInstance diff --git a/config/samples/placement_v1beta1_placementtls.yaml b/config/samples/placement_v1beta1_placementtls.yaml new file mode 100644 index 00000000..5dafec0b --- /dev/null +++ b/config/samples/placement_v1beta1_placementtls.yaml @@ -0,0 +1,25 @@ +apiVersion: placement.openstack.org/v1beta1 +kind: PlacementAPI +metadata: + name: placement-tls +spec: + serviceUser: placement + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: placement + debug: + dbSync: false + service: false + preserveJobs: false + replicas: 1 + secret: placement-secret + tls: + api: + disabled: false + internal: + secretName: cert-internal-svc + public: + secretName: cert-public-svc + caBundleSecretName: combined-ca-bundle diff --git a/controllers/placementapi_controller.go b/controllers/placementapi_controller.go index a7d5ffa2..a019428a 100644 --- a/controllers/placementapi_controller.go +++ b/controllers/placementapi_controller.go @@ -21,12 +21,20 @@ import ( "fmt" "time" + "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" "github.com/go-logr/logr" keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" @@ -44,6 +52,7 @@ import ( common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" oko_secret "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" util "github.com/openstack-k8s-operators/lib-common/modules/common/util" mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" @@ -192,8 +201,73 @@ func (r *PlacementAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request return r.reconcileNormal(ctx, instance, helper) } +// 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 ( + allWatchFields = []string{ + passwordSecretField, + caBundleSecretNameField, + tlsAPIInternalField, + tlsAPIPublicField, + } +) + // SetupWithManager sets up the controller with the Manager. func (r *PlacementAPIReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &placementv1.PlacementAPI{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*placementv1.PlacementAPI) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &placementv1.PlacementAPI{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*placementv1.PlacementAPI) + 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(), &placementv1.PlacementAPI{}, tlsAPIInternalField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*placementv1.PlacementAPI) + 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(), &placementv1.PlacementAPI{}, tlsAPIPublicField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*placementv1.PlacementAPI) + 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(&placementv1.PlacementAPI{}). Owns(&mariadbv1.MariaDBDatabase{}). @@ -207,9 +281,47 @@ func (r *PlacementAPIReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&corev1.ServiceAccount{}). Owns(&rbacv1.Role{}). Owns(&rbacv1.RoleBinding{}). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } +func (r *PlacementAPIReconciler) findObjectsForSrc(src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("PlacementAPI") + + for _, field := range allWatchFields { + crList := &placementv1.PlacementAPIList{} + 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 +} + func (r *PlacementAPIReconciler) reconcileDelete(ctx context.Context, instance *placementv1.PlacementAPI, helper *helper.Helper) (ctrl.Result, error) { Log := r.GetLogger(ctx) Log.Info("Reconciling Service delete") @@ -445,7 +557,12 @@ func (r *PlacementAPIReconciler) 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 { @@ -634,6 +751,38 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance * return ctrl.Result{}, err } + // 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 { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + if hash != "" { + configMapVars[tls.CABundleKey] = env.SetValue(hash) + } + } + + // Validate API service certs secrets + certsHash, ctrlResult, err := instance.Spec.TLS.API.ValidateCertSecrets(ctx, helper, instance.Namespace) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + configMapVars[tls.TLSHashName] = env.SetValue(certsHash) + // // create hash over all the different input resources to identify if any those changed // and a restart/recreate is required. @@ -654,7 +803,8 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance * // serviceLabels := map[string]string{ - common.AppSelector: placement.ServiceName, + common.AppSelector: placement.ServiceName, + common.OwnerSelector: instance.Name, } // networks to attach to @@ -687,7 +837,7 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance * } // Handle service init - ctrlResult, err := r.reconcileInit(ctx, instance, helper, serviceLabels, serviceAnnotations) + ctrlResult, err = r.reconcileInit(ctx, instance, helper, serviceLabels, serviceAnnotations) if err != nil { return ctrlResult, err } else if (ctrlResult != ctrl.Result{}) { @@ -715,8 +865,14 @@ func (r *PlacementAPIReconciler) reconcileNormal(ctx context.Context, instance * // // Define a new Deployment object - deplDef := placement.Deployment(instance, inputHash, serviceLabels, serviceAnnotations) + deplDef, err := placement.Deployment(ctx, helper, 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 } depl := deployment.NewDeployment( @@ -818,6 +974,21 @@ func (r *PlacementAPIReconciler) generateServiceConfigMaps( "log_file": "/var/log/placement/placement-api.log", } + // 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("placement-%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 + cms := []util.Template{ // ScriptsConfigMap { diff --git a/go.mod b/go.mod index 534701df..e112a806 100644 --- a/go.mod +++ b/go.mod @@ -90,3 +90,5 @@ replace github.com/openstack-k8s-operators/placement-operator/api => ./api // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8 diff --git a/go.sum b/go.sum index e798b6e8..9e52a948 100644 --- a/go.sum +++ b/go.sum @@ -63,6 +63,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8 h1:B3jTaWtvyCT4O7uOvGwQN80mC18e4+IFNxNk4MZHkPE= +github.com/deydra71/lib-common/modules/common v0.0.0-20240102085933-7629711060c8/go.mod h1:IDd4i2ZXWELCF+Y8Zu9bQBobE6yy3HOEjUeLnSuSWaM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -236,8 +238,6 @@ github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 h1:rncLxJBpFGqBztyxC github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231208104910-f8433c1c9399 h1:Te7JSPGGUhkzjig/1CjlPmQgMpHT0+yHWoTxbVJGJ74= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231208104910-f8433c1c9399/go.mod h1:kDtQ2LCkf28F7xgK8GBFAMPDhXnL6iRb8NztHhrYaO0= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231230095328-700482794743 h1:nElSEojlu7JxfpmF5c4zb2F3bjbQigpeiheV6Eus6RI= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231230095328-700482794743/go.mod h1:IDd4i2ZXWELCF+Y8Zu9bQBobE6yy3HOEjUeLnSuSWaM= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231230095328-700482794743 h1:Csah4t609IfGYZ5Ekfprjnmu3PrzaM/z4NXWx/JLKV4= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231230095328-700482794743/go.mod h1:4nmd2iUcjIAkF5Lw1ow+nsTeT3ifXbooGsjPSKG1+IA= github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20231230095328-700482794743 h1:XT/nipCZzwQJcdegypnxf7UiCeOtOtmT0WgwLpD6qOA= @@ -298,8 +298,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/pkg/placement/dbsync.go b/pkg/placement/dbsync.go index 87e28b59..58ed46bf 100644 --- a/pkg/placement/dbsync.go +++ b/pkg/placement/dbsync.go @@ -44,6 +44,16 @@ func DbSyncJob( envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") + // create Volume and VolumeMounts + volumes := getVolumes(instance.Name) + volumeMounts := getVolumeMounts("dbsync") + + // add CA cert if defined + if instance.Spec.TLS.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.TLS.CreateVolume()) + volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: ServiceName + "-db-sync", @@ -70,16 +80,15 @@ func DbSyncJob( RunAsUser: ptr.To(PlacementUserID), }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: getVolumeMounts("dbsync"), + VolumeMounts: volumeMounts, }, }, + Volumes: volumes, }, }, }, } - job.Spec.Template.Spec.Volumes = getVolumes(ServiceName) - initContainerDetails := APIDetails{ ContainerImage: instance.Spec.ContainerImage, DatabaseHost: instance.Status.DatabaseHostname, @@ -88,7 +97,6 @@ func DbSyncJob( OSPSecret: instance.Spec.Secret, DBPasswordSelector: instance.Spec.PasswordSelectors.Database, UserPasswordSelector: instance.Spec.PasswordSelectors.Service, - VolumeMounts: getInitVolumeMounts(), } job.Spec.Template.Spec.InitContainers = initContainer(initContainerDetails) diff --git a/pkg/placement/deployment.go b/pkg/placement/deployment.go index 1ea985df..ba3e5c6a 100644 --- a/pkg/placement/deployment.go +++ b/pkg/placement/deployment.go @@ -16,9 +16,14 @@ limitations under the License. package placement import ( + "context" + common "github.com/openstack-k8s-operators/lib-common/modules/common" affinity "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" env "github.com/openstack-k8s-operators/lib-common/modules/common/env" + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + "github.com/openstack-k8s-operators/lib-common/modules/common/service" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" placementv1 "github.com/openstack-k8s-operators/placement-operator/api/v1beta1" @@ -31,11 +36,13 @@ import ( // Deployment func func Deployment( + ctx context.Context, + helper *helper.Helper, instance *placementv1.PlacementAPI, configHash string, labels map[string]string, annotations map[string]string, -) *appsv1.Deployment { +) (*appsv1.Deployment, error) { livenessProbe := &corev1.Probe{ // TODO might need tuning TimeoutSeconds: 5, @@ -74,12 +81,46 @@ func Deployment( readinessProbe.HTTPGet = &corev1.HTTPGetAction{ Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(PlacementPublicPort)}, } + + if instance.Spec.TLS.API.Enabled(service.EndpointPublic) { + livenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + readinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + } } envVars := map[string]env.Setter{} envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["CONFIG_HASH"] = env.SetValue(configHash) + // create Volume and VolumeMounts + volumes := getVolumes(instance.Name) + volumeMounts := getVolumeMounts("api") + + // add CA cert if defined + if instance.Spec.TLS.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.TLS.CreateVolume()) + volumeMounts = append(volumeMounts, 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 + } + volumes = append(volumes, svc.CreateVolume(endpt.String())) + volumeMounts = append(volumeMounts, svc.CreateVolumeMounts(endpt.String())...) + } + } + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: ServiceName, @@ -97,6 +138,12 @@ func Deployment( }, Spec: corev1.PodSpec{ ServiceAccountName: instance.RbacResourceName(), + Volumes: volumes, + SecurityContext: &corev1.PodSecurityContext{ + // since we run as PlacementUserID, e.g. certs need to be + // readable by the placement user, instead of root + FSGroup: ptr.To(PlacementUserID), + }, Containers: []corev1.Container{ { Name: ServiceName + "-log", @@ -116,7 +163,7 @@ func Deployment( RunAsUser: ptr.To(PlacementUserID), }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: getVolumeMounts("api"), + VolumeMounts: volumeMounts, Resources: instance.Spec.Resources, ReadinessProbe: readinessProbe, LivenessProbe: livenessProbe, @@ -132,7 +179,7 @@ func Deployment( RunAsUser: ptr.To(PlacementUserID), }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: getVolumeMounts("api"), + VolumeMounts: volumeMounts, Resources: instance.Spec.Resources, ReadinessProbe: readinessProbe, LivenessProbe: livenessProbe, @@ -143,7 +190,6 @@ func Deployment( }, } - deployment.Spec.Template.Spec.Volumes = getVolumes(instance.Name) // If possible two pods of the same service should not // run on the same worker node. If this is not possible // the get still created on the same worker node. @@ -170,5 +216,5 @@ func Deployment( } deployment.Spec.Template.Spec.InitContainers = initContainer(initContainerDetails) - return deployment + return deployment, nil } diff --git a/templates/placementapi/config/httpd.conf b/templates/placementapi/config/httpd.conf index a42952e2..2e960f86 100644 --- a/templates/placementapi/config/httpd.conf +++ b/templates/placementapi/config/httpd.conf @@ -28,14 +28,37 @@ TransferLog /dev/stdout CustomLog /dev/stdout combined env=!forwarded CustomLog /dev/stdout proxy env=forwarded +{{ range $endpt, $vhost := .VHosts }} +# {{ $endpt }} vhost {{ $vhost.ServerName }} configuration = 2.4> ErrorLogFormat "%M" + ServerName {{ $vhost.ServerName }} + + ## Vhost docroot ErrorLog /dev/stdout SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded CustomLog /dev/stdout combined env=!forwarded CustomLog /dev/stdout proxy env=forwarded + ServerSignature Off + CustomLog /dev/stdout combined + +{{- if $vhost.TLS }} + SetEnvIf X-Forwarded-Proto https HTTPS=1 + + ## SSL directives + SSLEngine on + SSLCertificateFile "{{ $vhost.SSLCertificateFile }}" + SSLCertificateKeyFile "{{ $vhost.SSLCertificateKeyFile }}" +{{- end }} + + ## Directories, there should at least be a declaration for /var/www/cgi-bin/placement + + Options -Indexes +FollowSymLinks +MultiViews + AllowOverride None + Require all granted + ## WSGI configuration WSGIProcessGroup placement-api @@ -44,6 +67,7 @@ CustomLog /dev/stdout proxy env=forwarded WSGIDaemonProcess placement-api processes=3 threads=1 user=placement group=placement WSGIScriptAlias / /usr/bin/placement-api +{{ end }} Alias /placement-api /usr/bin/placement-api diff --git a/templates/placementapi/config/placement-api-config.json b/templates/placementapi/config/placement-api-config.json index 57e2d8ff..07ae4b72 100644 --- a/templates/placementapi/config/placement-api-config.json +++ b/templates/placementapi/config/placement-api-config.json @@ -18,6 +18,18 @@ "dest": "/etc/httpd/conf/httpd.conf", "owner": "apache", "perm": "0644" + }, + { + "source": "/var/lib/config-data/merged/ssl.conf", + "dest": "/etc/httpd/conf.d/ssl.conf", + "owner": "apache", + "perm": "0644" + }, + { + "source": "/var/lib/config-data/merged/logging.conf", + "dest": "/etc/placement/logging.conf", + "owner": "placement", + "perm": "0600" } ], "permissions": [ diff --git a/templates/placementapi/config/ssl.conf b/templates/placementapi/config/ssl.conf new file mode 100644 index 00000000..e3da4ecb --- /dev/null +++ b/templates/placementapi/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/base_test.go b/tests/functional/base_test.go index bc90e4ef..3b8f6809 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -28,19 +28,22 @@ import ( ) type Names struct { - Namespace string - PlacementAPIName types.NamespacedName - ConfigMapName types.NamespacedName - DBSyncJobName types.NamespacedName - MariaDBDatabaseName types.NamespacedName - DeploymentName types.NamespacedName - PublicServiceName types.NamespacedName - InternalServiceName types.NamespacedName - KeystoneServiceName types.NamespacedName - KeystoneEndpointName types.NamespacedName - ServiceAccountName types.NamespacedName - RoleName types.NamespacedName - RoleBindingName types.NamespacedName + Namespace string + PlacementAPIName types.NamespacedName + ConfigMapName types.NamespacedName + DBSyncJobName types.NamespacedName + MariaDBDatabaseName types.NamespacedName + DeploymentName types.NamespacedName + PublicServiceName types.NamespacedName + InternalServiceName types.NamespacedName + KeystoneServiceName types.NamespacedName + KeystoneEndpointName types.NamespacedName + ServiceAccountName types.NamespacedName + RoleName types.NamespacedName + RoleBindingName types.NamespacedName + CaBundleSecretName types.NamespacedName + InternalCertSecretName types.NamespacedName + PublicCertSecretName types.NamespacedName } func CreateNames(placementAPIName types.NamespacedName) Names { @@ -82,6 +85,15 @@ func CreateNames(placementAPIName types.NamespacedName) Names { RoleBindingName: types.NamespacedName{ Namespace: placementAPIName.Namespace, Name: "placement-" + placementAPIName.Name + "-rolebinding"}, + CaBundleSecretName: types.NamespacedName{ + Namespace: placementAPIName.Namespace, + Name: CABundleSecretName}, + InternalCertSecretName: types.NamespacedName{ + Namespace: placementAPIName.Namespace, + Name: InternalCertSecretName}, + PublicCertSecretName: types.NamespacedName{ + Namespace: placementAPIName.Namespace, + Name: PublicCertSecretName}, } } @@ -92,6 +104,25 @@ func GetDefaultPlacementAPISpec() map[string]interface{} { } } +func GetTLSPlacementAPISpec() map[string]interface{} { + return map[string]interface{}{ + "databaseInstance": "openstack", + "replicas": 1, + "secret": SecretName, + "tls": map[string]interface{}{ + "api": map[string]interface{}{ + "internal": map[string]interface{}{ + "secretName": InternalCertSecretName, + }, + "public": map[string]interface{}{ + "secretName": PublicCertSecretName, + }, + }, + "caBundleSecretName": CABundleSecretName, + }, + } +} + func CreatePlacementAPI(name types.NamespacedName, spec map[string]interface{}) client.Object { raw := map[string]interface{}{ diff --git a/tests/functional/placementapi_controller_test.go b/tests/functional/placementapi_controller_test.go index 40348131..7b1fb015 100644 --- a/tests/functional/placementapi_controller_test.go +++ b/tests/functional/placementapi_controller_test.go @@ -30,6 +30,7 @@ import ( ) var _ = Describe("PlacementAPI controller", func() { + BeforeEach(func() { // lib-common uses OPERATOR_TEMPLATES env var to locate the "templates" // directory of the operator. We need to set them othervise lib-common @@ -379,7 +380,7 @@ var _ = Describe("PlacementAPI controller", func() { deployment := th.GetDeployment(names.DeploymentName) Expect(int(*deployment.Spec.Replicas)).To(Equal(1)) - Expect(deployment.Spec.Selector.MatchLabels).To(Equal(map[string]string{"service": "placement"})) + Expect(deployment.Spec.Selector.MatchLabels).To(Equal(map[string]string{"service": "placement", "owner": names.PlacementAPIName.Name})) Expect(deployment.Spec.Template.Spec.ServiceAccountName).To(Equal(names.ServiceAccountName.Name)) Expect(len(deployment.Spec.Template.Spec.Containers)).To(Equal(2)) @@ -684,4 +685,61 @@ var _ = Describe("PlacementAPI controller", func() { }) }) + + When("A PlacementAPI is created with TLS", func() { + BeforeEach(func() { + DeferCleanup(k8sClient.Delete, ctx, th.CreateCABundleSecret(names.CaBundleSecretName)) + DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InternalCertSecretName)) + DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.PublicCertSecretName)) + DeferCleanup(th.DeleteInstance, CreatePlacementAPI(names.PlacementAPIName, GetTLSPlacementAPISpec())) + DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(namespace)) + DeferCleanup(k8sClient.Delete, ctx, CreatePlacementAPISecret(namespace, SecretName)) + + spec := GetTLSPlacementAPISpec() + placement := CreatePlacementAPI(names.PlacementAPIName, spec) + + serviceSpec := corev1.ServiceSpec{Ports: []corev1.ServicePort{{Port: 3306}}} + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService(namespace, "openstack", serviceSpec), + ) + mariadb.SimulateMariaDBDatabaseCompleted(names.MariaDBDatabaseName) + keystone.SimulateKeystoneServiceReady(names.KeystoneServiceName) + keystone.SimulateKeystoneEndpointReady(names.KeystoneEndpointName) + th.SimulateJobSuccess(names.DBSyncJobName) + DeferCleanup(th.DeleteInstance, placement) + }) + + It("it creates deployment with CA and service certs mounted", func() { + j := th.GetDeployment(names.DeploymentName) + + container := j.Spec.Template.Spec.Containers[0] + + // CA bundle + th.AssertVolumeExists(names.CaBundleSecretName.Name, j.Spec.Template.Spec.Volumes) + th.AssertVolumeMountExists(names.CaBundleSecretName.Name, "tls-ca-bundle.pem", j.Spec.Template.Spec.Containers[0].VolumeMounts) + + // service certs + th.AssertVolumeExists(names.InternalCertSecretName.Name, j.Spec.Template.Spec.Volumes) + th.AssertVolumeExists(names.PublicCertSecretName.Name, j.Spec.Template.Spec.Volumes) + th.AssertVolumeMountExists(names.PublicCertSecretName.Name, "tls.key", j.Spec.Template.Spec.Containers[0].VolumeMounts) + th.AssertVolumeMountExists(names.PublicCertSecretName.Name, "tls.crt", j.Spec.Template.Spec.Containers[0].VolumeMounts) + th.AssertVolumeMountExists(names.InternalCertSecretName.Name, "tls.key", j.Spec.Template.Spec.Containers[0].VolumeMounts) + th.AssertVolumeMountExists(names.InternalCertSecretName.Name, "tls.crt", j.Spec.Template.Spec.Containers[0].VolumeMounts) + + Expect(container.ReadinessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) + Expect(container.LivenessProbe.HTTPGet.Scheme).To(Equal(corev1.URISchemeHTTPS)) + + configDataMap := th.GetConfigMap(names.ConfigMapName) + Expect(configDataMap).ShouldNot(BeNil()) + Expect(configDataMap.Data).Should(HaveKey("httpd.conf")) + Expect(configDataMap.Data).Should(HaveKey("ssl.conf")) + configData := string(configDataMap.Data["httpd.conf"]) + Expect(configData).Should(ContainSubstring("SSLEngine on")) + Expect(configData).Should(ContainSubstring("SSLCertificateFile \"/etc/pki/tls/certs/internal.crt\"")) + Expect(configData).Should(ContainSubstring("SSLCertificateKeyFile \"/etc/pki/tls/private/internal.key\"")) + Expect(configData).Should(ContainSubstring("SSLCertificateFile \"/etc/pki/tls/certs/public.crt\"")) + Expect(configData).Should(ContainSubstring("SSLCertificateKeyFile \"/etc/pki/tls/private/public.key\"")) + }) + }) }) diff --git a/tests/functional/suite_test.go b/tests/functional/suite_test.go index d7f8508b..f57c9428 100644 --- a/tests/functional/suite_test.go +++ b/tests/functional/suite_test.go @@ -73,6 +73,12 @@ const ( SecretName = "test-osp-secret" + PublicCertSecretName = "public-tls-certs" + + InternalCertSecretName = "internal-tls-certs" + + CABundleSecretName = "combined-ca-bundle" + interval = time.Millisecond * 200 )