diff --git a/api/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml b/api/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml index e0b1b544..a99243a2 100644 --- a/api/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml +++ b/api/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml @@ -232,6 +232,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/api/bases/octavia.openstack.org_octaviaapis.yaml b/api/bases/octavia.openstack.org_octaviaapis.yaml index 2f8147ad..fb147c4e 100644 --- a/api/bases/octavia.openstack.org_octaviaapis.yaml +++ b/api/bases/octavia.openstack.org_octaviaapis.yaml @@ -362,6 +362,36 @@ spec: default: octavia description: ServiceUser - service user name 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/octavia.openstack.org_octavias.yaml b/api/bases/octavia.openstack.org_octavias.yaml index 21f73c93..e98351d2 100644 --- a/api/bases/octavia.openstack.org_octavias.yaml +++ b/api/bases/octavia.openstack.org_octavias.yaml @@ -442,6 +442,36 @@ spec: default: octavia description: ServiceUser - service user name 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 @@ -640,6 +670,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string @@ -838,6 +876,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string @@ -1036,6 +1082,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/api/go.sum b/api/go.sum index 02cf93aa..168ff23a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -11,6 +11,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -58,7 +59,9 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -87,16 +90,19 @@ github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1B github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -167,6 +173,7 @@ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7 google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/api/v1beta1/amphoracontroller_types.go b/api/v1beta1/amphoracontroller_types.go index d47147fb..f41a2814 100644 --- a/api/v1beta1/amphoracontroller_types.go +++ b/api/v1beta1/amphoracontroller_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" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -135,6 +136,9 @@ type OctaviaAmphoraControllerSpecCore struct { // +kubebuilder:default={} // List of Redis Host IP addresses RedisHostIPs []string `json:"redisHostIPs,omitempty"` + // +operator-sdk:csv:customresourcedefinitions:type=spec + // TLS - Parameters related to the TLS + TLS tls.Ca `json:"tls,omitempty"` } // OctaviaAmphoraControllerStatus defines the observed state of the Octavia Amphora Controller diff --git a/api/v1beta1/octaviaapi_types.go b/api/v1beta1/octaviaapi_types.go index 90c1a5e0..35e7c91f 100644 --- a/api/v1beta1/octaviaapi_types.go +++ b/api/v1beta1/octaviaapi_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" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -132,6 +133,11 @@ type OctaviaAPISpecCore struct { // +kubebuilder:validation:Optional // NetworkAttachments is a list of NetworkAttachment resource names to expose the services to the given network NetworkAttachments []string `json:"networkAttachments,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 eea6dd0e..f17e141c 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -181,6 +181,7 @@ func (in *OctaviaAPISpecCore) DeepCopyInto(out *OctaviaAPISpecCore) { *out = make([]string, len(*in)) copy(*out, *in) } + in.TLS.DeepCopyInto(&out.TLS) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OctaviaAPISpecCore. @@ -347,6 +348,7 @@ func (in *OctaviaAmphoraControllerSpecCore) DeepCopyInto(out *OctaviaAmphoraCont *out = make([]string, len(*in)) copy(*out, *in) } + out.TLS = in.TLS } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OctaviaAmphoraControllerSpecCore. diff --git a/config/crd/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml b/config/crd/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml index e0b1b544..a99243a2 100644 --- a/config/crd/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml +++ b/config/crd/bases/octavia.openstack.org_octaviaamphoracontrollers.yaml @@ -232,6 +232,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/config/crd/bases/octavia.openstack.org_octaviaapis.yaml b/config/crd/bases/octavia.openstack.org_octaviaapis.yaml index 2f8147ad..fb147c4e 100644 --- a/config/crd/bases/octavia.openstack.org_octaviaapis.yaml +++ b/config/crd/bases/octavia.openstack.org_octaviaapis.yaml @@ -362,6 +362,36 @@ spec: default: octavia description: ServiceUser - service user name 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/octavia.openstack.org_octavias.yaml b/config/crd/bases/octavia.openstack.org_octavias.yaml index 21f73c93..e98351d2 100644 --- a/config/crd/bases/octavia.openstack.org_octavias.yaml +++ b/config/crd/bases/octavia.openstack.org_octavias.yaml @@ -442,6 +442,36 @@ spec: default: octavia description: ServiceUser - service user name 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 @@ -640,6 +670,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string @@ -838,6 +876,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string @@ -1036,6 +1082,14 @@ spec: description: TenantName - the name of the OpenStack tenant that controls the Octavia resources TODO(gthiemonge) same as ServiceAccount? 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: description: TransportURLSecret - Secret containing RabbitMQ transportURL type: string diff --git a/config/samples/octavia_v1beta1_octavia_tls.yaml b/config/samples/octavia_v1beta1_octavia_tls.yaml new file mode 100644 index 00000000..b8d65442 --- /dev/null +++ b/config/samples/octavia_v1beta1_octavia_tls.yaml @@ -0,0 +1,70 @@ +apiVersion: octavia.openstack.org/v1beta1 +kind: Octavia +metadata: + name: octavia +spec: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + rabbitMqClusterName: rabbitmq + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaHousekeeping: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: housekeeping + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaHealthManager: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: healthmanager + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaWorker: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: worker + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaAPI: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + tls: + api: + internal: + secretName: cert-octavia-internal-svc + public: + secretName: cert-octavia-public-svc + caBundleSecretName: combined-ca-bundle diff --git a/controllers/amphoracontroller_controller.go b/controllers/amphoracontroller_controller.go index 521bc6fa..c6efd97e 100644 --- a/controllers/amphoracontroller_controller.go +++ b/controllers/amphoracontroller_controller.go @@ -32,6 +32,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/labels" 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/tls" "github.com/openstack-k8s-operators/lib-common/modules/common/util" mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" @@ -43,12 +44,18 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" + "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" ) // OctaviaAmphoraControllerReconciler reconciles an OctaviaAmmphoraController object @@ -109,6 +116,7 @@ func (r *OctaviaAmphoraControllerReconciler) Reconcile(ctx context.Context, req condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage), condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage), + condition.UnknownCondition(condition.TLSInputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), ) // TODO(beagles): what other conditions? instance.Status.Conditions.Init(&cl) @@ -284,6 +292,38 @@ func (r *OctaviaAmphoraControllerReconciler) reconcileNormal(ctx context.Context instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) + // + // 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 != "" { + configMapVars[tls.CABundleKey] = env.SetValue(hash) + } + } + // all cert input checks out so report InputReady + instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) + // // create hash over all the different input resources to identify if any those changed // and a restart/recreate is required. @@ -425,7 +465,19 @@ func (r *OctaviaAmphoraControllerReconciler) generateServiceConfigMaps( ) error { r.Log.Info(fmt.Sprintf("generating service config map for %s (%s)", instance.Name, instance.Kind)) cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(instance.ObjectMeta.Name), map[string]string{}) - customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + db, err := mariadbv1.GetDatabaseByName(ctx, helper, octavia.DatabaseName) + if err != nil { + return err + } + var tlsCfg *tls.Service + if instance.Spec.TLS.CaBundleSecretName != "" { + tlsCfg = &tls.Service{} + } + + customData := map[string]string{ + common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig, + "my.cnf": db.GetDatabaseClientConfig(tlsCfg), //(mschuppert) for now just get the default my.cnf + } for key, data := range instance.Spec.DefaultConfigOverwrite { customData[key] = data } @@ -589,11 +641,72 @@ func (r *OctaviaAmphoraControllerReconciler) createHashOfInputHashes( // SetupWithManager sets up the controller with the Manager. func (r *OctaviaAmphoraControllerReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &octaviav1.OctaviaAmphoraController{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAmphoraController) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &octaviav1.OctaviaAmphoraController{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAmphoraController) + if cr.Spec.TLS.CaBundleSecretName == "" { + return nil + } + return []string{cr.Spec.TLS.CaBundleSecretName} + }); err != nil { + return err + } return ctrl.NewControllerManagedBy(mgr). For(&octaviav1.OctaviaAmphoraController{}). Owns(&corev1.Service{}). Owns(&corev1.Secret{}). Owns(&corev1.ConfigMap{}). Owns(&appsv1.DaemonSet{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } + +func (r *OctaviaAmphoraControllerReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("Amphora") + + for _, field := range allWatchFields { + crList := &octaviav1.OctaviaAmphoraControllerList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.Client.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/octavia_controller.go b/controllers/octavia_controller.go index 4cf265d5..c04981aa 100644 --- a/controllers/octavia_controller.go +++ b/controllers/octavia_controller.go @@ -34,6 +34,8 @@ import ( common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" 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" "github.com/openstack-k8s-operators/lib-common/modules/common/util" mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" @@ -193,6 +195,23 @@ func (r *OctaviaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re 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 *OctaviaReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). @@ -520,6 +539,7 @@ func (r *OctaviaReconciler) reconcileNormal(ctx context.Context, instance *octav return ctrl.Result{}, fmt.Errorf("failed create network annotation from %s: %w", instance.Spec.OctaviaAPI.NetworkAttachments, err) } + instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage) // Handle service init ctrlResult, err := r.reconcileInit(ctx, instance, helper, serviceLabels, serviceAnnotations) @@ -802,11 +822,19 @@ func (r *OctaviaReconciler) generateServiceConfigMaps( cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(octavia.ServiceName), map[string]string{}) + var tlsCfg *tls.Service + if instance.Spec.OctaviaAPI.TLS.Ca.CaBundleSecretName != "" { + tlsCfg = &tls.Service{} + } + // customData hold any customization for the service. // custom.conf is going to /etc//.conf.d // all other files get placed into /etc/ to allow overwrite of e.g. logging.conf or policy.json // TODO: make sure custom.conf can not be overwritten - customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + customData := map[string]string{ + common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig, + "my.cnf": octaviaDb.GetDatabaseClientConfig(tlsCfg), //(mschuppert) for now just get the default my.cnf + } for key, data := range instance.Spec.DefaultConfigOverwrite { customData[key] = data } @@ -835,6 +863,21 @@ func (r *OctaviaReconciler) generateServiceConfigMaps( } templateParameters["ServiceUser"] = instance.Spec.ServiceUser + // 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", octavia.ServiceName, endpt.String(), instance.Namespace) + endptConfig["TLS"] = false // default TLS to false, and set it bellow to true if enabled + if instance.Spec.OctaviaAPI.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 { @@ -906,6 +949,7 @@ func (r *OctaviaReconciler) apiDeploymentCreateOrUpdate(instance *octaviav1.Octa deployment.Spec.TransportURLSecret = instance.Status.TransportURLSecret deployment.Spec.Secret = instance.Spec.Secret deployment.Spec.ServiceAccount = instance.RbacResourceName() + deployment.Spec.TLS = instance.Spec.OctaviaAPI.TLS if len(deployment.Spec.NodeSelector) == 0 { deployment.Spec.NodeSelector = instance.Spec.NodeSelector } @@ -1015,6 +1059,7 @@ func (r *OctaviaReconciler) amphoraControllerDaemonSetCreateOrUpdate( daemonset.Spec.LbMgmtNetworks.SubnetIPVersion = instance.Spec.LbMgmtNetworks.SubnetIPVersion daemonset.Spec.AmphoraCustomFlavors = instance.Spec.AmphoraCustomFlavors daemonset.Spec.RedisHostIPs = instance.Status.RedisHostIPs + daemonset.Spec.TLS = instance.Spec.OctaviaAPI.TLS.Ca if len(daemonset.Spec.NodeSelector) == 0 { daemonset.Spec.NodeSelector = instance.Spec.NodeSelector } diff --git a/controllers/octaviaapi_controller.go b/controllers/octaviaapi_controller.go index d9c037dd..9ded2378 100644 --- a/controllers/octaviaapi_controller.go +++ b/controllers/octaviaapi_controller.go @@ -35,6 +35,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/secret" 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" "github.com/openstack-k8s-operators/lib-common/modules/common/util" mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" @@ -46,13 +47,19 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" + "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" ) // OctaviaAPIReconciler reconciles a OctaviaAPI object @@ -156,6 +163,7 @@ func (r *OctaviaAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) 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), ) instance.Status.Conditions.Init(&cl) @@ -179,6 +187,55 @@ func (r *OctaviaAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) // SetupWithManager sets up the controller with the Manager. func (r *OctaviaAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { crs := &octaviav1.OctaviaAPIList{} + + // index passwordSecretField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &octaviav1.OctaviaAPI{}, passwordSecretField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAPI) + if cr.Spec.Secret == "" { + return nil + } + return []string{cr.Spec.Secret} + }); err != nil { + return err + } + + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &octaviav1.OctaviaAPI{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAPI) + 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(), &octaviav1.OctaviaAPI{}, tlsAPIInternalField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAPI) + 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(), &octaviav1.OctaviaAPI{}, tlsAPIPublicField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*octaviav1.OctaviaAPI) + 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(&octaviav1.OctaviaAPI{}). Owns(&keystonev1.KeystoneService{}). @@ -189,9 +246,47 @@ func (r *OctaviaAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma Owns(&corev1.ConfigMap{}). Owns(&appsv1.Deployment{}). Watches(&ovnclient.OVNDBCluster{}, handler.EnqueueRequestsFromMapFunc(ovnclient.OVNDBClusterNamespaceMapFunc(crs, mgr.GetClient(), r.GetLogger(ctx)))). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } +func (r *OctaviaAPIReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + l := log.FromContext(context.Background()).WithName("Controllers").WithName("OctaviaAPI") + + for _, field := range allWatchFields { + crList := &octaviav1.OctaviaAPIList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.Client.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 *OctaviaAPIReconciler) reconcileDelete(ctx context.Context, instance *octaviav1.OctaviaAPI, helper *helper.Helper) (ctrl.Result, error) { Log := r.GetLogger(ctx) util.LogForObject(helper, "Reconciling Service delete", instance) @@ -342,7 +437,11 @@ func (r *OctaviaAPIReconciler) 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 { @@ -486,6 +585,55 @@ func (r *OctaviaAPIReconciler) reconcileNormal(ctx context.Context, instance *oc // run check OpenStack secret - end + // + // 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 != "" { + 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 { + 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 + } + + configMapVars[tls.TLSHashName] = env.SetValue(certsHash) + } + + // all cert input checks out so report InputReady + instance.Status.Conditions.MarkTrue(condition.TLSInputReadyCondition, condition.InputReadyMessage) + // // Create ConfigMaps and Secrets required as input for the Service and calculate an overall hash of hashes // @@ -588,10 +736,19 @@ func (r *OctaviaAPIReconciler) reconcileNormal(ctx context.Context, instance *oc // // Define a new Deployment object - depl := deployment.NewDeployment( - octaviaapi.Deployment(instance, inputHash, serviceLabels, serviceAnnotations), - time.Duration(5)*time.Second, - ) + + deplDef, err := octaviaapi.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 + } + + depl := deployment.NewDeployment(deplDef, time.Duration(5)*time.Second) ctrlResult, err = depl.CreateOrPatch(ctx, helper) if err != nil { @@ -672,11 +829,23 @@ func (r *OctaviaAPIReconciler) generateServiceConfigMaps( cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(octavia.ServiceName), map[string]string{}) + db, err := mariadbv1.GetDatabaseByName(ctx, h, octavia.DatabaseName) + if err != nil { + return err + } + var tlsCfg *tls.Service + if instance.Spec.TLS.CaBundleSecretName != "" { + tlsCfg = &tls.Service{} + } + // customData hold any customization for the service. // custom.conf is going to /etc//.conf.d // all other files get placed into /etc/ to allow overwrite of e.g. logging.conf or policy.json // TODO: make sure custom.conf can not be overwritten - customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + customData := map[string]string{ + common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig, + "my.cnf": db.GetDatabaseClientConfig(tlsCfg), //(mschuppert) for now just get the default my.cnf + } for key, data := range instance.Spec.DefaultConfigOverwrite { customData[key] = data } diff --git a/go.mod b/go.mod index fed0868e..da258abe 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,10 @@ require ( sigs.k8s.io/controller-runtime v0.16.5 ) -require golang.org/x/crypto v0.19.0 +require ( + golang.org/x/crypto v0.19.0 + k8s.io/utils v0.0.0-20240102154912-e7106e64919e +) require ( github.com/beorn7/perks v1.0.1 // indirect @@ -77,7 +80,6 @@ require ( k8s.io/component-base v0.28.7 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240126223410-2919ad4fcfec // 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.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 0150f73b..64fc00c2 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -62,7 +63,9 @@ github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.m github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -103,16 +106,19 @@ github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1B github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -189,6 +195,7 @@ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7 google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/amphoracontrollers/daemonset.go b/pkg/amphoracontrollers/daemonset.go index 107eff17..d14b0403 100644 --- a/pkg/amphoracontrollers/daemonset.go +++ b/pkg/amphoracontrollers/daemonset.go @@ -84,6 +84,12 @@ func DaemonSet( envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["CONFIG_HASH"] = env.SetValue(configHash) + // Add the CA bundle + if instance.Spec.TLS.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.TLS.CreateVolume()) + volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) + } + daemonset := &appsv1.DaemonSet{ ObjectMeta: metav1.ObjectMeta{ Name: serviceName, diff --git a/pkg/octavia/dbsync.go b/pkg/octavia/dbsync.go index 5da05d89..c67992bb 100644 --- a/pkg/octavia/dbsync.go +++ b/pkg/octavia/dbsync.go @@ -45,6 +45,12 @@ func DbSyncJob( envVars := map[string]env.Setter{} envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") + // add CA cert if defined + if instance.Spec.OctaviaAPI.TLS.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.OctaviaAPI.TLS.CreateVolume()) + volumeMounts = append(volumeMounts, instance.Spec.OctaviaAPI.TLS.CreateVolumeMounts(nil)...) + } + job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: instance.Name + "-db-sync", diff --git a/pkg/octavia/volumes.go b/pkg/octavia/volumes.go index f4a1a769..5683e4fa 100644 --- a/pkg/octavia/volumes.go +++ b/pkg/octavia/volumes.go @@ -70,6 +70,12 @@ func GetInitVolumeMounts() []corev1.VolumeMount { MountPath: "/var/lib/config-data/merged", ReadOnly: false, }, + { + Name: "config-data", + MountPath: "/etc/my.cnf", + SubPath: "my.cnf", + ReadOnly: true, + }, } } diff --git a/pkg/octaviaapi/deployment.go b/pkg/octaviaapi/deployment.go index ded9dd22..529508ec 100644 --- a/pkg/octaviaapi/deployment.go +++ b/pkg/octaviaapi/deployment.go @@ -21,6 +21,8 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" "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" octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" "github.com/openstack-k8s-operators/octavia-operator/pkg/octavia" @@ -41,7 +43,7 @@ func Deployment( configHash string, labels map[string]string, annotations map[string]string, -) *appsv1.Deployment { +) (*appsv1.Deployment, error) { runAsUser := int64(0) initVolumeMounts := octavia.GetInitVolumeMounts() @@ -71,6 +73,40 @@ func Deployment( Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(octavia.OctaviaPublicPort)}, } + if instance.Spec.TLS.API.Enabled(service.EndpointPublic) { + livenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + readinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS + } + + // create Volume and VolumeMounts + volumes := getVolumes(instance.Name) + volumeMounts := getVolumeMounts("octavia-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())...) + } + } + envVars := map[string]env.Setter{} envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["CONFIG_HASH"] = env.SetValue(configHash) @@ -111,7 +147,7 @@ func Deployment( RunAsUser: &runAsUser, }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: getVolumeMounts("octavia-api"), + VolumeMounts: volumeMounts, Resources: instance.Spec.Resources, ReadinessProbe: readinessProbe, LivenessProbe: livenessProbe, @@ -126,7 +162,7 @@ func Deployment( LivenessProbe: livenessProbe, }, }, - Volumes: getVolumes(instance.Name), + Volumes: volumes, }, }, }, @@ -156,5 +192,5 @@ func Deployment( } deployment.Spec.Template.Spec.InitContainers = octavia.InitContainer(initContainerDetails) - return deployment + return deployment, nil } diff --git a/templates/octaviaapi/config/octavia-api-config.json b/templates/octaviaapi/config/octavia-api-config.json index 05592062..a3f03867 100644 --- a/templates/octaviaapi/config/octavia-api-config.json +++ b/templates/octaviaapi/config/octavia-api-config.json @@ -18,7 +18,29 @@ "dest": "/etc/httpd/conf/httpd.conf", "owner": "root", "perm": "0644" - } + }, + { + "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": "octavia", + "perm": "0440", + "optional": true, + "merge": true + }, + { + "source": "/var/lib/config-data/tls/private/*", + "dest": "/etc/pki/tls/private/", + "owner": "octavia", + "perm": "0400", + "optional": true, + "merge": true + } ], "permissions": [ { diff --git a/templates/octaviaapi/ssl.conf b/templates/octaviaapi/ssl.conf new file mode 100644 index 00000000..e3da4ecb --- /dev/null +++ b/templates/octaviaapi/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/kuttl/tests/octavia_tls/01-assert.yaml b/tests/kuttl/tests/octavia_tls/01-assert.yaml new file mode 100644 index 00000000..aafb73fd --- /dev/null +++ b/tests/kuttl/tests/octavia_tls/01-assert.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Secret +metadata: + name: cert-octavia-internal-svc +--- +apiVersion: v1 +kind: Secret +metadata: + name: cert-octavia-public-svc +--- +apiVersion: v1 +kind: Secret +metadata: + name: combined-ca-bundle diff --git a/tests/kuttl/tests/octavia_tls/01-tls-certs.yaml b/tests/kuttl/tests/octavia_tls/01-tls-certs.yaml new file mode 100644 index 00000000..610a926e --- /dev/null +++ b/tests/kuttl/tests/octavia_tls/01-tls-certs.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Secret +metadata: + name: combined-ca-bundle + labels: + service: octavia +data: + tls-ca-bundle.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNLZ0F3SUJBZ0lRUHhtRFFscmxjNTNhb215RVU5MU9pakFLQmdncWhrak9QUVFEQWpBZU1Sd3cKR2dZRFZRUURFeE5yZFhSMGJDMXpaV3htYzJsbmJtVmtMV05oTUI0WERUSXpNVEF4T0RFeU1EazFNMW9YRFRJMApNREV4TmpFeU1EazFNMW93SGpFY01Cb0dBMVVFQXhNVGEzVjBkR3d0YzJWc1puTnBaMjVsWkMxallUQlpNQk1HCkJ5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCSVdJY0JiR0cveEg4Lzlkc2lMbkJCdnRqcEZoQ2JRM3U4R0EKZXBVcnhTY25XM0hrZ2hrc1BCVE12M3NCeGdnVFQwL0Eva0dtazRYTkJ0dElnbUZJaFBpalFqQkFNQTRHQTFVZApEd0VCL3dRRUF3SUNwREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlFKaDd3VklFYjgxcFlsCkl3RDAraTBwSnlCTjNqQUtCZ2dxaGtqT1BRUURBZ05KQURCR0FpRUF2a3h5RzZjNzltSDlRWHRIVWFSM014REkKUUVRRGVtL1hZR3VGY1ZCUDJpQUNJUUNFeEZqeStQUTBkNFU5dEJacTVOd1gzdmxibnQxVlNCYWE5VFIrNkNkbAozdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tIyByb290Y2EtaW50ZXJuYWwKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmekNDQVNhZ0F3SUJBZ0lRUWxlcTNZcDBtU2kwVDNiTm03Q29UVEFLQmdncWhrak9QUVFEQWpBZ01SNHcKSEFZRFZRUURFeFZ5YjI5MFkyRXRhM1YwZEd3dGFXNTBaWEp1WVd3d0hoY05NalF3TVRFMU1URTBOelUwV2hjTgpNelF3TVRFeU1URTBOelUwV2pBZ01SNHdIQVlEVlFRREV4VnliMjkwWTJFdGEzVjBkR3d0YVc1MFpYSnVZV3d3CldUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTRk9rNHJPUldVUGhoTjUrK09EN1I2MW5Gb1lBY0QKenpvUS91SW93NktjeGhwRWNQTDFxb3ZZUGxUYUJabEh3c2FpNE50VHA4aDA1RHVRSGZKOE9JNXFvMEl3UURBTwpCZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXE3TGtFSk1TCm1MOVpKWjBSOUluKzZkclhycEl3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVlN1K00ydnZ3QlF3eTJHMVlhdkkKQld2RGtSNlRla0I5U0VqdzJIblRSMWtDSUZSNFNkWGFPQkFGWjVHa2RLWCtSY2IzaDFIZm52eFJEVW96bTl2agphenp3Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KIyByb290Y2EtcHVibGljCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZXpDQ0FTS2dBd0lCQWdJUU5IREdZc0JzNzk4aWJERDdxL28ybGpBS0JnZ3Foa2pPUFFRREFqQWVNUnd3CkdnWURWUVFERXhOeWIyOTBZMkV0YTNWMGRHd3RjSFZpYkdsak1CNFhEVEkwTURFeE5URXdNVFV6TmxvWERUTTAKTURFeE1qRXdNVFV6Tmxvd0hqRWNNQm9HQTFVRUF4TVRjbTl2ZEdOaExXdDFkSFJzTFhCMVlteHBZekJaTUJNRwpCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkQ3OGF2WHFocmhDNXc4czlXa2Q0SXBiZUV1MDNDUitYWFVkCmtEek9SeXhhOXdjY0lkRGl2YkdKakpGWlRUY1ZtYmpxMUJNWXNqcjEyVUlFNUVUM1ZscWpRakJBTUE0R0ExVWQKRHdFQi93UUVBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUS0ppeldVSjllVUtpMQpkczBscjZjNnNEN0VCREFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUJJWndZcTYxQnFNSmFCNlVjRm9Sc3hlY3dICjV6L3pNT2RyT3llMG1OaThKZ0lnUUxCNHdES3JwZjl0WDJsb00rMHVUb3BBRFNZSW5yY2ZWdTRGQnVZVTNJZz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= +--- +apiVersion: v1 +kind: Secret +metadata: + name: cert-octavia-internal-svc + labels: + service: octavia +data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkVENDQVJxZ0F3SUJBZ0lRTkZUVDE2eTc0RGJaOGJTL25ESDBkakFLQmdncWhrak9QUVFEQWpBYU1SZ3cKRmdZRFZRUURFdzl5YjI5MFkyRXRhVzUwWlhKdVlXd3dIaGNOTWpRd01URXdNVFV5T0RBMFdoY05NalF3TkRBNQpNVFV5T0RBMFdqQWFNUmd3RmdZRFZRUURFdzl5YjI5MFkyRXRhVzUwWlhKdVlXd3dXVEFUQmdjcWhrak9QUUlCCkJnZ3Foa2pPUFFNQkJ3TkNBQVFjK2d5OVFCNmw1NFNBQlkxUTJKZWx5MEhSTGEvMzlkRUxzU2RhNnJDRENKQWwKWjJ2bGlGbUo5WVlJNCtSbGRIejJWNXYvYjBpK2x0RjcxMGZ1OHJTbW8wSXdRREFPQmdOVkhROEJBZjhFQkFNQwpBcVF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVeUsyc0hXaUxHNnR6bWlVbENkUmhsRTJLCnNHSXdDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBSzVtTi9zQlBVcXAwckd1QjhnMVRxY21KR3ZMVUpyNjlnaEEKaEozMldCT1BBaUVBbEtwU0dVTzhac25UcVQrQ1hWbXNuWkxBcVJMV1NhbUI5U2NyczNDZ05zWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNhekNDQWhHZ0F3SUJBZ0lSQU1GRmpzWkpHY3BuaVBFNXNmQytrOEV3Q2dZSUtvWkl6ajBFQXdJd0dqRVkKTUJZR0ExVUVBeE1QY205dmRHTmhMV2x1ZEdWeWJtRnNNQjRYRFRJME1ERXhOVEV4TkRnMU1sb1hEVE0wTURFeApNakV4TkRnMU1sb3dBRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRzhQSWwzCnc4RXdXMHdUUG5qRURpU2dTdVI4WHJaajcrSjYyUkJMTHJ3ZUxKdWd1Wm1MaUh3M09uSldWa0hEOVpaZzlYSGUKbGZ6UDY3Wi8rYXBNMzJ5VWJTVUcrRjlBdXlGMHRTK2lPODFkUFRSY1luNzVBK0xWdnk1UkVpOGIvTFkzNTNPbgpxUEhuK2kyeTNLUC9HZkhjSi9lVlVXNFJkV2wyTHEyejRtRDRUK2twS0VwSnRGSTJQa2lrSVNOV2RRdmtEeW1WClF3a1B3U01FVy9yaEdGL2s3b0gvVWtwdy9wU1N1R0M2a1lpSnlwOTFHT0xCMlVoc254Z3dLelh5VS9MdGFrZXoKS2RHSFUvNUNLTTRKczg0ZnlNTDBBNXMxalpZQXZEWkVLNEgvYVpCb3EzV0NoQ1R4WWhIOVVuczhIQy9KbHJCMApHaitwVHNuaEc2cUlFQ2tDQXdFQUFhT0JoakNCZ3pBT0JnTlZIUThCQWY4RUJBTUNCYUF3RXdZRFZSMGxCQXd3CkNnWUlLd1lCQlFVSEF3RXdEQVlEVlIwVEFRSC9CQUl3QURBZkJnTlZIU01FR0RBV2dCVElyYXdkYUlzYnEzT2EKSlNVSjFHR1VUWXF3WWpBdEJnTlZIUkVCQWY4RUl6QWhnaDlyWlhsemRHOXVaUzFwYm5SbGNtNWhiQzV2Y0dWdQpjM1JoWTJzdWMzWmpNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJRTFJYXcxcnRnU0ROZmxBSjJRek9VQjJxU1llCk03ZWdsaXZLVW01cmVOZThBaUVBMU93SGcwQ1YxOUNhYUpSSi9SS25UcXNJTGhNdjBEUVNPdnFwbWc0MWZDTT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBd2J3OGlYZkR3VEJiVEJNK2VNUU9KS0JLNUh4ZXRtUHY0bnJaRUVzdXZCNHNtNkM1Cm1ZdUlmRGM2Y2xaV1FjUDFsbUQxY2Q2Vi9NL3J0bi81cWt6ZmJKUnRKUWI0WDBDN0lYUzFMNkk3elYwOU5GeGkKZnZrRDR0Vy9MbEVTTHh2OHRqZm5jNmVvOGVmNkxiTGNvLzhaOGR3bjk1VlJiaEYxYVhZdXJiUGlZUGhQNlNrbwpTa20wVWpZK1NLUWhJMVoxQytRUEtaVkRDUS9CSXdSYit1RVlYK1R1Z2Y5U1NuRCtsSks0WUxxUmlJbktuM1VZCjRzSFpTR3lmR0RBck5mSlQ4dTFxUjdNcDBZZFQva0lvemdtenpoL0l3dlFEbXpXTmxnQzhOa1FyZ2Y5cGtHaXIKZFlLRUpQRmlFZjFTZXp3Y0w4bVdzSFFhUDZsT3llRWJxb2dRS1FJREFRQUJBb0lCQVFDQ0hweUdNK05OY040UQo1V2Z6RXJMeEZKdlloRlBVcXFDbWU1NG9uR1ppUU4zekZPc3pYbzBuNkt3ZnVTOHI4cUtUQXNJM1hhbGRhSVRIClNZTDFSN1pVSmdoOGN3Y0VhdVNFbnU5R2MrODRpbVFlTStLUHAwNWQzdlFOOXJPQTRvcEVGSjRtaHJnbzZZYVYKaE9rK1dJc2piNXVFWlV5UTRiYjdRejRzdW9IVVlDYXFkVGlqU1lYQzNOd092YUlwa3pTNEo0cU5CUlhyYnNWSwowaGt4ZFNIY1hKNEREN0hybktpcEsxT2xUbUVObVZYbmlaNnRPcWc2eUNFeXFteWN0UnlUVTZRRzVPbVM2clJVCm82Z25EclA1TlgwRUhuakY3b1lka0JVbGJxWk96UHVGbG5CdUVKOFpTUEtOZHA5ejhuS3lqbGJiL0YxWGRDdEkKZERhVUhmREZBb0dCQVBFZkZZbDhPb2VhU21oSElKcGpxd3RCanYrRjFuOXNJbHNuZWNyQ1JmN243RW53d1hXaQpReStXQ3l6aDJGRVVad1dod2RQeXFJT3NVaG1vaXBIQmN3NlVUaW9xalM4SlpvSDlURFBQUEd5OXIwMHZwRkNuCnFkdjNXMkhWVytRckMrWk1nc2ZKdUlTTnFtbFdFeHpCNFBJQWRHQTdKVzFMY0ZCcG1Zd25DdXZyQW9HQkFNMncKbS94cVRhMmgySjFnNUI0elE5UnBhM280SEoyL2pTaHEzNW9heVNGNWJDYWtnWGRxek0yU0FwQ0x4dzlvY3doRAp3WWRaMWliaHl6b1dDQVZZZ0RlaXViUi96ZTN3Nzk4NktScUNmNnptMk5HOEoxODVDZDdKSjBiaTZBTTgvalpTCnFqWkJIK0FqanF2aFFJM0FMMEdzNlFvc2Z3L3hOL2k1cG00UWM5TTdBb0dBZjZCbFpQVmxnWnN3WVV1c3ZTdWUKUUlIOTc5Qm12ZUY5dWVRR09rVmtpVTAzSzlnTWZuaFp1WmxnNXV2UDlQS29xVGw2Zi9aRUxoWUxDdHZFSk94UgpPMWxTbWswVmw5MFE3aU1scjVLMHVCWWE4TzhUdVVGVnprRjZsQ2s3ejJUZGtwUFM4VzhiaE1YN2VtLytBODIzCmhFQ3JXTGhWMGlrSkZQY2dPQ2YrUnVzQ2dZQTYvcld1cnhxNmUxb3l3WENNVE8zZWhhSUMrd2NTSTdlcjZRTmIKSXVXZlNVRkEwQndtRVNiT3ExczY5Q3hTK2dWTVVJcTRkSWJjdmhSWkE2cW5SZHY0bVI2a2E2ZTM0RXdjZllUKwppb0Z1S1FQMUcvODY2NVF1SndteDVqRGZoT1h3MU1MbkxzU2l0L0FhMGs5K21LbTFMNC9qa0NHZGcvVW16TEMwCmp0bDVzd0tCZ0VPTVI3ODVLT2hyNXFoWmE2b0MvU25JeEptS1FxTWdXU0NGV1pGMDZrVlRnSmthb1hwUEl0bUIKOUZGbE1nTTJSeC91S2V3YTNDSTdQK240ek1uYSswTmhDL0RwNkMxVFVsVWlrcnJYQ3I5a1NPR2dXaEFISDljTwozRENvdkhOcE1PaG51dnhoMlpDeTdYbjFJeGgxWXdlYnVobFZzeTFvR0tDQ0lJb00rOVg1Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== +--- +apiVersion: v1 +kind: Secret +metadata: + name: cert-octavia-public-svc + labels: + service: octavia +data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlekNDQVNLZ0F3SUJBZ0lRTkhER1lzQnM3OThpYkREN3EvbzJsakFLQmdncWhrak9QUVFEQWpBZU1Sd3cKR2dZRFZRUURFeE55YjI5MFkyRXRhM1YwZEd3dGNIVmliR2xqTUI0WERUSTBNREV4TlRFd01UVXpObG9YRFRNMApNREV4TWpFd01UVXpObG93SGpFY01Cb0dBMVVFQXhNVGNtOXZkR05oTFd0MWRIUnNMWEIxWW14cFl6QlpNQk1HCkJ5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRDc4YXZYcWhyaEM1dzhzOVdrZDRJcGJlRXUwM0NSK1hYVWQKa0R6T1J5eGE5d2NjSWREaXZiR0pqSkZaVFRjVm1ianExQk1Zc2pyMTJVSUU1RVQzVmxxalFqQkFNQTRHQTFVZApEd0VCL3dRRUF3SUNwREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlRLSml6V1VKOWVVS2kxCmRzMGxyNmM2c0Q3RUJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQklad1lxNjFCcU1KYUI2VWNGb1JzeGVjd0gKNXovek1PZHJPeWUwbU5pOEpnSWdRTEI0d0RLcnBmOXRYMmxvTSswdVRvcEFEU1lJbnJjZlZ1NEZCdVlVM0lnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNiVENDQWhPZ0F3SUJBZ0lSQUtacXlMbUhLNC9VRTZmMi9LNWxiQnN3Q2dZSUtvWkl6ajBFQXdJd0hqRWMKTUJvR0ExVUVBeE1UY205dmRHTmhMV3QxZEhSc0xYQjFZbXhwWXpBZUZ3MHlOREF4TVRVeE1ESXdOVFJhRncwegpOREF4TVRJeE1ESXdOVFJhTUFBd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUMxCjhDcFJRVG1abHNzSUlmZ2hIK2ltUUtFMFdZVlJOeS8vMVM0aDVtV2tBcUZiVkhoUmptbFJ2cCtQUWpKOU16TDUKMXpXdmYxandEQ2pzYUxvL2FwSW9OSXJIcjN4TTRoYWl0emU0RjFwZzNoL3MvblExNWN5Q2U5dHdHR0RuWEllMwo2djBuNE9LNnAwSWJjcVk2Q1RBMTBwcGJZa3V6bzdVRkx6ZWxsc1ZhRlhzZ21JWDg4bTRXNmNBTi84cjJPWUI3Ck9HM0ZNOXAxSUFxT0hyT21EelFlTldqOUVjQy9TSCs5MGg4c1FyY1pvMWtWa1g1b2tpSUhDZjRlc2o3Q08rTGgKR3lsTmZyRzl6QTlPM0c3QVNDWVdPVWwyZTBhNHhZbE9QMmI4ejFEV3NIMTBVYXVsZHlRQXNtbkhtaW1VNzBmKwpEazZkQ1hXVHN4cGZ2cXphOVR4YkFnTUJBQUdqZ1lRd2dZRXdEZ1lEVlIwUEFRSC9CQVFEQWdXZ01CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01CTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwakJCZ3dGb0FVeWlZczFsQ2YKWGxDb3RYYk5KYStuT3JBK3hBUXdLd1lEVlIwUkFRSC9CQ0V3SDRJZGEyVjVjM1J2Ym1VdGNIVmliR2xqTG05dwpaVzV6ZEdGamF5NXpkbU13Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnTzAzT2JmNm9uV2RiZG4xa282OVpuTFhMCmtQSHFYU3VRNlcxTDFvY3NDR3NDSVFEakEyVm9pWVdYN0hzSjVGNkZYV3FsZnl0RmduVVgvTmhvT1lIVnB2TWQKSGc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdGZBcVVVRTVtWmJMQ0NINElSL29wa0NoTkZtRlVUY3YvOVV1SWVabHBBS2hXMVI0ClVZNXBVYjZmajBJeWZUTXkrZGMxcjM5WThBd283R2k2UDJxU0tEU0t4Njk4VE9JV29yYzN1QmRhWU40ZjdQNTAKTmVYTWdudmJjQmhnNTF5SHQrcjlKK0RpdXFkQ0czS21PZ2t3TmRLYVcySkxzNk8xQlM4M3BaYkZXaFY3SUppRgovUEp1RnVuQURmL0s5am1BZXpodHhUUGFkU0FLamg2enBnODBIalZvL1JIQXYwaC92ZElmTEVLM0dhTlpGWkYrCmFKSWlCd24rSHJJK3dqdmk0UnNwVFg2eHZjd1BUdHh1d0VnbUZqbEpkbnRHdU1XSlRqOW0vTTlRMXJCOWRGR3IKcFhja0FMSnB4NW9wbE85SC9nNU9uUWwxazdNYVg3NnMydlU4V3dJREFRQUJBb0lCQUd0eVdvdUNLYkk3Qzh6Ugp3dWhOSCtpUFlxUzMrYlB0RTd2UytsdXE1WHZtMGNST0xvQjd5bGNzYks3K09UTVhlWk56TlpGZmMvYlFONXJtCmZwZlZLRnYySzcraU01WjBMMG9KU2k2K0cvSDVQSUdLQkxlUDd5ZGdYa2ZsSGRXRkgrSE9OWlBIakI4UGlFc04KZW4zcnp6ejZFNDdFamxDWTdkOFI4NXNuWDRYREN2bG1CQnhvcnpqVERuK1dTWWpKS09SSk5zY3oxQXFYR1VjVwpQaHRNYkwybC8zN2hPbTA4SjRRWXowTWduOWE5VUFXLzFNS2lXbHVpc1NHNG9YaFNPS1hkdk1IS3VxS09sUDJzCk9xWjBlR3JBNmpKdWlmZVY2Q2NIU2p3VUgwdHpiMmdZQVM2cm5RQlREbFkxR1I4Skx0YWhWREtqdUwyV0hjclkKbHhCOGZBRUNnWUVBMWpxc01weFo5cG9LNkpmRDZzVTU0ZUU1UWlNYlB0MERRZjlYU1J6NW5zQXlraHdKWEZDVwpKWTNiU3BhcGREeEgzakpDQ0VzN3NSWUhUeDRzNVJQSldtWC9oZTFwVEs4TDVlaFV2TmVudG5nVTB3aE4rZVEzCjl4Sk1VbHVYdGkvU0FpNi9jQk5HY1ZjQjFGRStmVzY0VDhqYVVQakRrL0Z2dFRXOXkzZnNVZnNDZ1lFQTJXbXMKYStuZ2RaS24rVTlCMlFCTXB0K0RLL0txNVF6RW1qZDVMSjJMb3FLUjhGbjlpVVZoUVljUEpobDJVV3VjTTl0RQp0QUlYdEY0anVUejlqUUNMMGQ5a09DeCswdTBKUFZJejdlVmFFVGs1enF0azRsTnhVUkJhQ3pCUEJkdjZJd3BDCkR4UXJWRXBXYlMra1JvYTNKSElOdHdjUWt2Nk50N1JIajd1WEVTRUNnWUJsREozbTdZc2Q0QUZmUHg4Qm9YQXgKRkt5T2ZzSytQei9uSkl0R2lHMVNMWFJ0S041ZGRnR3N5eUh5SitqY1ZBYk9UMFNJWnZ4TUJva0NEOGk3Y1Q3Ygo3aHErVUlNSDBkVzU1NEg0NVh4TmZJek9FaSs5dktHTllFc3gyZFJROG5PTDVnTVUyWEt6eVllcVgzd3JiRXR5CkR0cXpzUE9IMkMySiswU0FNaHY5ZXdLQmdRQ2szeWs5TUwvaUNWUk9rTmNybTdtRk5xeS9rQ2dleU43eTRDeUoKTS9RbllrZHYwSjZmRWJrZU96QzJ3TXBrRmtuL1hVR3RqSVN6YUV5STlnS0ZnaXVGL1hWL3orWmhTQllncFl6eAoxR0xIK3ZDbWxIMU4wTjkzRFFKcng3ZTFoc3NhOVhXQS85ZVg5VU96UzFTMWt3V2hvc2haeXdhN29rU1FVaXVPCmlVQ1hZUUtCZ1FEUVZUVHc3WUY3QzNTVmg5OWRObUdTaHV2LzZ2aTJmNDlOMklGMURNQ1haaEpoOUVZck9TV2kKY05oakxGRFhmdzVlZlFURWU3Ykx5bTJGVDd0YnZFSm5USHFyakVuUDRUWExqZnczL3RiQ3RxWVNZRlRqdThFUApadHVwd21ZWjhFVU1pSnVHS2l2SExmSjk2dy8xR21BOHVCZUVtV05YRW9FUU1ySmxuM3g5d3c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= diff --git a/tests/kuttl/tests/octavia_tls/02-assert.yaml b/tests/kuttl/tests/octavia_tls/02-assert.yaml new file mode 100644 index 00000000..001064c1 --- /dev/null +++ b/tests/kuttl/tests/octavia_tls/02-assert.yaml @@ -0,0 +1,223 @@ +apiVersion: octavia.openstack.org/v1beta1 +kind: Octavia +metadata: + name: octavia +spec: + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: octavia + passwordSelectors: + service: OctaviaPassword + database: OctaviaDatabasePassword + preserveJobs: false + secret: osp-secret + serviceUser: octavia + octaviaAPI: + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: octavia + passwordSelectors: + service: OctaviaPassword + database: OctaviaDatabasePassword + preserveJobs: false + replicas: 1 + secret: osp-secret + serviceUser: octavia + tls: + api: + internal: + secretName: cert-octavia-internal-svc + public: + secretName: cert-octavia-public-svc + caBundleSecretName: combined-ca-bundle + octaviaHousekeeping: + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: octavia + passwordSelectors: + service: OctaviaPassword + database: OctaviaDatabasePassword + secret: osp-secret + serviceUser: octavia + octaviaHealthManager: + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: octavia + passwordSelectors: + service: OctaviaPassword + database: OctaviaDatabasePassword + secret: osp-secret + serviceUser: octavia + octaviaWorker: + customServiceConfig: | + [DEFAULT] + debug = true + databaseInstance: openstack + databaseUser: octavia + passwordSelectors: + service: OctaviaPassword + database: OctaviaDatabasePassword + secret: osp-secret + serviceUser: octavia +status: + databaseHostname: openstack.octavia-kuttl-tests.svc + apireadyCount: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: octavia-api +spec: + replicas: 1 + template: + metadata: + labels: + service: octavia + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: service + operator: In + values: + - octavia-api + topologyKey: kubernetes.io/hostname + weight: 1 + containers: + - args: + - -c + - /usr/local/bin/kolla_set_configs && /usr/local/bin/kolla_start + command: + - /bin/bash + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 9876 + scheme: HTTPS + initialDelaySeconds: 3 + periodSeconds: 13 + successThreshold: 1 + timeoutSeconds: 15 + name: octavia-api + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 9876 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 15 + - env: + - name: CONFIG_HASH + - name: KOLLA_CONFIG_STRATEGY + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 9876 + scheme: HTTPS + initialDelaySeconds: 3 + periodSeconds: 13 + successThreshold: 1 + timeoutSeconds: 15 + name: octavia-api-provider-agent + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 9876 + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 15 + initContainers: + - args: + - -c + - /usr/local/bin/container-scripts/init.sh + command: + - /bin/bash + env: + - name: DatabasePassword + valueFrom: + secretKeyRef: + key: OctaviaDatabasePassword + name: osp-secret + - name: AdminPassword + valueFrom: + secretKeyRef: + key: OctaviaPassword + name: osp-secret + - name: TransportURL + valueFrom: + secretKeyRef: + key: transport_url + name: rabbitmq-transport-url-octavia-octavia-transport + - name: DatabaseHost + value: openstack.octavia-kuttl-tests.svc + - name: DatabaseName + value: octavia + - name: DatabaseUser + value: octavia + imagePullPolicy: IfNotPresent + name: init + resources: {} + restartPolicy: Always + serviceAccount: octavia-octavia + serviceAccountName: octavia-octavia +status: + availableReplicas: 1 + replicas: 1 +--- +# the openshift annotations can't be checked through the deployment above +apiVersion: v1 +kind: Pod +metadata: + annotations: + openshift.io/scc: anyuid + labels: + service: octavia +--- +apiVersion: v1 +kind: Service +metadata: + labels: + endpoint: internal + service: octavia + name: octavia-internal +spec: + ports: + - name: octavia-internal + selector: + service: octavia + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + endpoint: public + service: octavia + name: octavia-public +spec: + ports: + - name: octavia-public + selector: + service: octavia + type: ClusterIP diff --git a/tests/kuttl/tests/octavia_tls/02-deploy.yaml b/tests/kuttl/tests/octavia_tls/02-deploy.yaml new file mode 100644 index 00000000..b8d65442 --- /dev/null +++ b/tests/kuttl/tests/octavia_tls/02-deploy.yaml @@ -0,0 +1,70 @@ +apiVersion: octavia.openstack.org/v1beta1 +kind: Octavia +metadata: + name: octavia +spec: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + rabbitMqClusterName: rabbitmq + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaHousekeeping: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: housekeeping + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaHealthManager: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: healthmanager + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaWorker: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + role: worker + certssecret: octavia-amp-cert-data + certspassphrasesecret: octavia-ca-passphrase + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + octaviaAPI: + databaseInstance: openstack + databaseUser: octavia + serviceUser: octavia + serviceAccount: octavia + secret: osp-secret + preserveJobs: false + customServiceConfig: | + [DEFAULT] + debug = true + tls: + api: + internal: + secretName: cert-octavia-internal-svc + public: + secretName: cert-octavia-public-svc + caBundleSecretName: combined-ca-bundle