From 3e4e97fce2b99ffc6fcd94f11c4ea52af390fca6 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Fri, 3 Nov 2023 06:35:41 -0400 Subject: [PATCH] Refactor to allow services to specify the cacert and issuer Also specifies a cert for libvirt and nova that contains the ip and hostname of the control plane. Add top level flag for TLSEnabled Just like the control plane, we need a flag to indicate whether the dataplane has TLS enabled. This is because - per adoption requirements, internal TLS may not be enabled. The hasTLSCerts parameter at the service level is simply for developers to specify whether or not TLS certs are needed/supported with TLS is enabled at the top level. --- ...nstack.org_openstackdataplanenodesets.yaml | 2 + ...nstack.org_openstackdataplaneservices.yaml | 6 ++ .../openstackdataplanenodeset_types.go | 5 + .../openstackdataplaneservice_types.go | 8 ++ api/v1beta1/zz_generated.deepcopy.go | 12 +++ ...nstack.org_openstackdataplanenodesets.yaml | 2 + ...nstack.org_openstackdataplaneservices.yaml | 6 ++ ...ta1_openstackdataplaneservice_libvirt.yaml | 2 + ...1beta1_openstackdataplaneservice_nova.yaml | 2 + .../openstackdataplanenodeset_controller.go | 20 ++-- docs/openstack_dataplanenodeset.md | 1 + docs/openstack_dataplaneservice.md | 2 + go.mod | 5 +- go.sum | 4 +- pkg/deployment/cert.go | 102 ++++++++++++------ pkg/deployment/const.go | 3 + pkg/deployment/deployment.go | 79 +++++++++----- pkg/deployment/inventory.go | 6 ++ pkg/deployment/ipam.go | 18 ++-- 19 files changed, 210 insertions(+), 75 deletions(-) diff --git a/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml b/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml index 4e48feaf2..d8dc44d65 100644 --- a/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml +++ b/api/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml @@ -1876,6 +1876,8 @@ spec: items: type: string type: array + tlsEnabled: + type: boolean required: - nodeTemplate - nodes diff --git a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml index 87ba1b942..5d72ad2fc 100644 --- a/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml +++ b/api/bases/dataplane.openstack.org_openstackdataplaneservices.yaml @@ -30,12 +30,18 @@ spec: type: object spec: properties: + caCerts: + type: string configMaps: items: type: string type: array hasTLSCerts: type: boolean + issuers: + additionalProperties: + type: string + type: object label: maxLength: 53 pattern: '[a-z]([-a-z0-9]*[a-z0-9])' diff --git a/api/v1beta1/openstackdataplanenodeset_types.go b/api/v1beta1/openstackdataplanenodeset_types.go index 42f4fe46c..693886f20 100644 --- a/api/v1beta1/openstackdataplanenodeset_types.go +++ b/api/v1beta1/openstackdataplanenodeset_types.go @@ -59,6 +59,11 @@ type OpenStackDataPlaneNodeSetSpec struct { // +kubebuilder:default={download-cache,bootstrap,configure-network,validate-network,install-os,configure-os,run-os,ovn,neutron-metadata,libvirt,nova,telemetry} // Services list Services []string `json:"services"` + + // TLSEnabled - Whether the node set has TLS enabled. + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} + TLSEnabled *bool `json:"tlsEnabled,omitempty" yaml:"tlsEnabled,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/v1beta1/openstackdataplaneservice_types.go b/api/v1beta1/openstackdataplaneservice_types.go index f8c368f40..5867c6a26 100644 --- a/api/v1beta1/openstackdataplaneservice_types.go +++ b/api/v1beta1/openstackdataplaneservice_types.go @@ -81,6 +81,14 @@ type OpenStackDataPlaneServiceSpec struct { // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} HasTLSCerts *bool `json:"hasTLSCerts,omitempty" yaml:"hasTLSCerts,omitempty"` + + // Issuers - Issuers to issue TLS Certificates + // +kubebuilder:validation:Optional + Issuers map[string]string `json:"issuers,omitempty"` + + // CACerts - Secret containing the CA certificate chain + // +kubebuilder:validation:Optional + CACerts string `json:"caCerts,omitempty" yaml:"caCerts,omitempty"` } // OpenStackDataPlaneServiceStatus defines the observed state of OpenStackDataPlaneService diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 843f1eb73..812885656 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -403,6 +403,11 @@ func (in *OpenStackDataPlaneNodeSetSpec) DeepCopyInto(out *OpenStackDataPlaneNod *out = make([]string, len(*in)) copy(*out, *in) } + if in.TLSEnabled != nil { + in, out := &in.TLSEnabled, &out.TLSEnabled + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackDataPlaneNodeSetSpec. @@ -524,6 +529,13 @@ func (in *OpenStackDataPlaneServiceSpec) DeepCopyInto(out *OpenStackDataPlaneSer *out = new(bool) **out = **in } + if in.Issuers != nil { + in, out := &in.Issuers, &out.Issuers + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackDataPlaneServiceSpec. diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml index 4e48feaf2..d8dc44d65 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplanenodesets.yaml @@ -1876,6 +1876,8 @@ spec: items: type: string type: array + tlsEnabled: + type: boolean required: - nodeTemplate - nodes diff --git a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml index 87ba1b942..5d72ad2fc 100644 --- a/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml +++ b/config/crd/bases/dataplane.openstack.org_openstackdataplaneservices.yaml @@ -30,12 +30,18 @@ spec: type: object spec: properties: + caCerts: + type: string configMaps: items: type: string type: array hasTLSCerts: type: boolean + issuers: + additionalProperties: + type: string + type: object label: maxLength: 53 pattern: '[a-z]([-a-z0-9]*[a-z0-9])' diff --git a/config/services/dataplane_v1beta1_openstackdataplaneservice_libvirt.yaml b/config/services/dataplane_v1beta1_openstackdataplaneservice_libvirt.yaml index 75d48bfb4..4ce2f400f 100644 --- a/config/services/dataplane_v1beta1_openstackdataplaneservice_libvirt.yaml +++ b/config/services/dataplane_v1beta1_openstackdataplaneservice_libvirt.yaml @@ -6,3 +6,5 @@ spec: label: libvirt playbook: osp.edpm.libvirt hasTLSCerts: True + issuers: + default: osp-rootca-issuer-internal diff --git a/config/services/dataplane_v1beta1_openstackdataplaneservice_nova.yaml b/config/services/dataplane_v1beta1_openstackdataplaneservice_nova.yaml index 66182b50d..70c3e9fbd 100644 --- a/config/services/dataplane_v1beta1_openstackdataplaneservice_nova.yaml +++ b/config/services/dataplane_v1beta1_openstackdataplaneservice_nova.yaml @@ -12,3 +12,5 @@ spec: - nova-migration-ssh-key playbook: osp.edpm.nova hasTLSCerts: True + issuers: + default: osp-rootca-issuer-internal diff --git a/controllers/openstackdataplanenodeset_controller.go b/controllers/openstackdataplanenodeset_controller.go index 8c2b9c527..3a79256db 100644 --- a/controllers/openstackdataplanenodeset_controller.go +++ b/controllers/openstackdataplanenodeset_controller.go @@ -210,17 +210,19 @@ func (r *OpenStackDataPlaneNodeSetReconciler) Reconcile(ctx context.Context, req instance.Status.CtlplaneSearchDomain = ctlplaneSearchDomain // Issue certs for TLS for services that need them - for _, serviceName := range instance.Spec.Services { - service, err := deployment.GetService(ctx, helper, serviceName) - if err != nil { - return ctrl.Result{}, err - } - if service.Spec.HasTLSCerts != nil && *service.Spec.HasTLSCerts { - result, err = deployment.EnsureTLSCerts(ctx, helper, instance, allHostnames, allIPs, serviceName) + if instance.Spec.TLSEnabled != nil && *instance.Spec.TLSEnabled { + for _, serviceName := range instance.Spec.Services { + service, err := deployment.GetService(ctx, helper, serviceName) if err != nil { return ctrl.Result{}, err - } else if (result != ctrl.Result{}) { - return result, nil + } + if service.Spec.HasTLSCerts != nil && *service.Spec.HasTLSCerts { + result, err = deployment.EnsureTLSCerts(ctx, helper, instance, allHostnames, allIPs, service) + if err != nil { + return ctrl.Result{}, err + } else if (result != ctrl.Result{}) { + return result, nil + } } } } diff --git a/docs/openstack_dataplanenodeset.md b/docs/openstack_dataplanenodeset.md index e8c3e0a5f..d5bcef245 100644 --- a/docs/openstack_dataplanenodeset.md +++ b/docs/openstack_dataplanenodeset.md @@ -129,6 +129,7 @@ OpenStackDataPlaneNodeSetSpec defines the desired state of OpenStackDataPlaneNod | env | Env is a list containing the environment variables to pass to the pod | []corev1.EnvVar | false | | networkAttachments | NetworkAttachments is a list of NetworkAttachment resource names to pass to the ansibleee resource which allows to connect the ansibleee runner to the given network | []string | false | | services | Services list | []string | true | +| tlsEnabled | TLSEnabled - Whether the node set has TLS enabled. | *bool | false | [Back to Custom Resources](#custom-resources) diff --git a/docs/openstack_dataplaneservice.md b/docs/openstack_dataplaneservice.md index 8ad55f387..0666b6d1f 100644 --- a/docs/openstack_dataplaneservice.md +++ b/docs/openstack_dataplaneservice.md @@ -126,6 +126,8 @@ OpenStackDataPlaneServiceSpec defines the desired state of OpenStackDataPlaneSer | secrets | Secrets list of Secret names to mount as ExtraMounts for the OpenStackAnsibleEE | []string | false | | openStackAnsibleEERunnerImage | OpenStackAnsibleEERunnerImage image to use as the ansibleEE runner image | string | false | | hasTLSCerts | HasTLSCerts - Whether the nodes have TLS certs | *bool | false | +| issuers | Issuers - Issuers to issue TLS Certificates | map[string]string | false | +| caCerts | CACerts - Secret containing the CA certificate chain | string | false | [Back to Custom Resources](#custom-resources) diff --git a/go.mod b/go.mod index 5563ff57d..e35bf5d91 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/openstack-k8s-operators/dataplane-operator/api v0.0.0-20230724101130-2d6fe1f4706b github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231122104142-3b449040167e github.com/openstack-k8s-operators/lib-common/modules/ansible v0.3.1-0.20231122111552-6bd6025ade37 - github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1 + github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231109064837-a0ac89bc5a39 github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231122111552-6bd6025ade37 github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231122111552-6bd6025ade37 github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20231122111552-6bd6025ade37 @@ -28,6 +28,7 @@ require ( k8s.io/api v0.26.11 k8s.io/apimachinery v0.26.11 k8s.io/client-go v0.26.11 + k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf sigs.k8s.io/controller-runtime v0.14.7 ) @@ -86,7 +87,7 @@ require ( k8s.io/component-base v0.26.11 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230515203736-54b630e78af5 // indirect - k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf // indirect + sigs.k8s.io/gateway-api v0.6.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index a3cf0cf89..e3b4dd26e 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,8 @@ github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231122104142-3 github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231122104142-3b449040167e/go.mod h1:FnKU6sravC43Uj0iq2bhZaPMjoPCBhkNlVdiVoGi5/E= github.com/openstack-k8s-operators/lib-common/modules/ansible v0.3.1-0.20231122111552-6bd6025ade37 h1:DpfHnE6YERlwPX/zd0eaZ59uv/l6+uXThwHTaxdRPQ4= github.com/openstack-k8s-operators/lib-common/modules/ansible v0.3.1-0.20231122111552-6bd6025ade37/go.mod h1:A9sWNibvjr1a9B/mpy4k6J9xkH11fnn0Dx/X1EZ3On8= -github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1 h1:sE/qio/WNUEng0VBmefSr46e/cq4R83payEzge/Y48U= -github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1/go.mod h1:u1pqzqGNLcof95aqhLfU6xHVTD6ZTc5gWy2FE03UrZQ= +github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231109064837-a0ac89bc5a39 h1:f6F22jZ6HNBdlrTBDziaoWM1HqW2LOME3nq+07SuC+s= +github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231109064837-a0ac89bc5a39/go.mod h1:Gr8E0kTkczsoUJ1AIzj9Z5vhl6V21ZrNJXICMB527qI= github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231122111552-6bd6025ade37 h1:ftwUwA41Y6R8U883Saz7aDg2lqUTh2ewm0qKwLuGLcU= github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231122111552-6bd6025ade37/go.mod h1:/6//JWNEY68jOMoaoaSI0koL2jzpEKim3m60+jFCbqY= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231122111552-6bd6025ade37 h1:F/sQ5+TzB1dVf4VyeyLDtcyNQDHnIkqZPK9V+cr/f6s= diff --git a/pkg/deployment/cert.go b/pkg/deployment/cert.go index a423d922c..05899230d 100644 --- a/pkg/deployment/cert.go +++ b/pkg/deployment/cert.go @@ -28,7 +28,9 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" dataplanev1 "github.com/openstack-k8s-operators/dataplane-operator/api/v1beta1" + infranetworkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/certmanager" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" @@ -38,18 +40,18 @@ import ( // This secret will be mounted by the ansibleEE pod as an extra mount when the service is deployed. func EnsureTLSCerts(ctx context.Context, helper *helper.Helper, instance *dataplanev1.OpenStackDataPlaneNodeSet, - allHostnames map[string][]string, - allIPs map[string][]string, - serviceName string) (ctrl.Result, error) { + allHostnames map[string]map[infranetworkv1.NetNameStr]string, + allIPs map[string]map[infranetworkv1.NetNameStr]string, + service dataplanev1.OpenStackDataPlaneService) (ctrl.Result, error) { certsData := map[string][]byte{} // for each node in the nodeset, issue all the TLS certs needed based on the // ips or DNS Names for nodeName := range instance.Spec.Nodes { - var dnsNames []string + var dnsNames map[infranetworkv1.NetNameStr]string + var ips map[infranetworkv1.NetNameStr]string var secretName string - var certName string var certSecret *corev1.Secret = nil var err error var result ctrl.Result @@ -58,59 +60,59 @@ func EnsureTLSCerts(ctx context.Context, helper *helper.Helper, // For now we just add the hostname so we can select all the certs on one node labels := map[string]string{ "hostname": nodeName, + "service": service.Name, } + secretName = "cert-" + service.Name + "-" + nodeName dnsNames = allHostnames[nodeName] - // ips = allIPs[nodeName] - - switch serviceName { + ips = allIPs[nodeName] + + switch service.Name { + case "nova", "libvirt": + // nova and libvirt want a cert with ctlplane ip and dns name + hosts := []string{dnsNames[CtlPlaneNetwork]} + ctlIPs := []string{ips[CtlPlaneNetwork]} + certSecret, result, err = GetTLSNodeCert(ctx, helper, instance, secretName, + service.Spec.Issuers["default"], labels, + nodeName, hosts, ctlIPs, nil) default: // The default case provides a cert with all the dns names for the host. // This will probably be sufficient for most services. If a service needs // a different kind of cert (for example, containing ips, or using a different // issuer) then add a case for the service in this switch statement - - secretName = "cert-" + nodeName - certSecret, _, err = secret.GetSecret(ctx, helper, secretName, instance.Namespace) - if err != nil { - if !k8serrors.IsNotFound(err) { - err = fmt.Errorf("Error retrieving secret %s - %w", secretName, err) - return ctrl.Result{}, err - } - - certName = secretName - duration := ptr.To(time.Hour * 24 * 365) - certSecret, result, err = certmanager.EnsureCert(ctx, helper, certmanager.RootCAIssuerInternalLabel, - certName, duration, dnsNames, nil, labels) - if err != nil { - return ctrl.Result{}, err - } else if (result != ctrl.Result{}) { - return result, nil - } + hosts := make([]string, 0, len(dnsNames)) + for _, host := range dnsNames { + hosts = append(hosts, host) } + secretName = "cert-default-" + nodeName + certSecret, result, err = GetTLSNodeCert(ctx, helper, instance, secretName, + certmanager.RootCAIssuerInternalLabel, labels, + nodeName, hosts, nil, nil) } + // handle cert request errors + if (err != nil) || (result != ctrl.Result{}) { + return result, err + } // TODO(alee) Add an owner reference to the secret so it can be monitored // We'll do this once stuggi adds a function to do this in libcommon // To use this cert, add it to the relevant service data - // TODO(alee) We only need the cert and key. The cacert will come from another label - for key, value := range certSecret.Data { - certsData[nodeName+"-"+key] = value - } + certsData[nodeName+"-tls.key"] = certSecret.Data["tls.key"] + certsData[nodeName+"-tls.crt"] = certSecret.Data["tls.crt"] } // create a secret to hold the certs for the service serviceCertsSecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: GetServiceCertsSecretName(instance, serviceName), + Name: GetServiceCertsSecretName(instance, service.Name), Namespace: instance.Namespace, }, Data: certsData, } _, result, err := secret.CreateOrPatchSecret(ctx, helper, instance, serviceCertsSecret) if err != nil { - err = fmt.Errorf("Error creating certs secret for %s - %w", serviceName, err) + err = fmt.Errorf("Error creating certs secret for %s - %w", service.Name, err) return ctrl.Result{}, err } else if result != controllerutil.OperationResultNone { return ctrl.Result{RequeueAfter: time.Second * 5}, nil @@ -119,6 +121,42 @@ func EnsureTLSCerts(ctx context.Context, helper *helper.Helper, return ctrl.Result{}, nil } +// GetTLSNodeCert creates or retrieves the cert for a node for a given service +func GetTLSNodeCert(ctx context.Context, helper *helper.Helper, + instance *dataplanev1.OpenStackDataPlaneNodeSet, + secretName string, issuer string, + labels map[string]string, nodeName string, + hostnames []string, ips []string, usages []certmgrv1.KeyUsage) (*corev1.Secret, ctrl.Result, error) { + certSecret, _, err := secret.GetSecret(ctx, helper, secretName, instance.Namespace) + var result ctrl.Result + if err != nil { + if !k8serrors.IsNotFound(err) { + err = fmt.Errorf("Error retrieving secret %s - %w", secretName, err) + return nil, ctrl.Result{}, err + } + + duration := ptr.To(time.Hour * 24 * 365) + request := certmanager.CertificateRequest{ + IssuerName: issuer, + CertName: secretName, + Duration: duration, + Hostnames: hostnames, + Ips: ips, + Annotations: nil, + Labels: labels, + Usages: usages, + } + + certSecret, result, err = certmanager.EnsureCert(ctx, helper, request) + if err != nil { + return nil, ctrl.Result{}, err + } else if (result != ctrl.Result{}) { + return nil, result, nil + } + } + return certSecret, ctrl.Result{}, nil +} + // GetServiceCertsSecretName - return name of secret to be mounted in ansibleEE which contains // all the TLS certs for the relevant service // The convention we use here is "--certs", so for example, diff --git a/pkg/deployment/const.go b/pkg/deployment/const.go index eb79b5a78..04bc1342c 100644 --- a/pkg/deployment/const.go +++ b/pkg/deployment/const.go @@ -50,4 +50,7 @@ const ( // CertPaths base path for cert volume mount in OpenStackAnsibleEE pod CertPaths = "/var/lib/openstack/certs" + + // CACertPaths base path for CA cert volume mount in OpenStackAnsibleEE pod + CACertPaths = "/var/lib/openstack/cacerts" ) diff --git a/pkg/deployment/deployment.go b/pkg/deployment/deployment.go index 7bf1a4b6f..9e07cbb4e 100644 --- a/pkg/deployment/deployment.go +++ b/pkg/deployment/deployment.go @@ -31,6 +31,7 @@ import ( dataplaneutil "github.com/openstack-k8s-operators/dataplane-operator/pkg/util" condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" "github.com/openstack-k8s-operators/lib-common/modules/common/util" "github.com/openstack-k8s-operators/lib-common/modules/storage" ansibleeev1alpha1 "github.com/openstack-k8s-operators/openstack-ansibleee-operator/api/v1alpha1" @@ -82,10 +83,10 @@ func Deploy( aeeSpec.ExtraMounts = make([]storage.VolMounts, len(aeeSpecMounts)) copy(aeeSpec.ExtraMounts, aeeSpecMounts) aeeSpec, err = addServiceExtraMounts(ctx, helper, aeeSpec, foundService, nodeSet) - if err != nil { return &ctrl.Result{}, err } + err = ConditionalDeploy( ctx, helper, @@ -324,33 +325,63 @@ func addServiceExtraMounts( aeeSpec.ExtraMounts = append(aeeSpec.ExtraMounts, volMounts) } - // Add mount for TLS certs - if service.Spec.HasTLSCerts != nil && *service.Spec.HasTLSCerts { - volMounts := storage.VolMounts{} - secretName := GetServiceCertsSecretName(nodeSet, service.Name) - sec := &corev1.Secret{} - err := client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: service.Namespace}, sec) - if err != nil { - return aeeSpec, err - } - volume := corev1.Volume{ - Name: secretName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + // Add mounts for TLS certs + if nodeSet.Spec.TLSEnabled != nil && *nodeSet.Spec.TLSEnabled { + if service.Spec.HasTLSCerts != nil && *service.Spec.HasTLSCerts { + volMounts := storage.VolMounts{} + secretName := GetServiceCertsSecretName(nodeSet, service.Name) + sec := &corev1.Secret{} + err := client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: service.Namespace}, sec) + if err != nil { + return aeeSpec, err + } + volume := corev1.Volume{ + Name: secretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretName, + }, }, - }, - } + } - volumeMount := corev1.VolumeMount{ - Name: secretName, - MountPath: path.Join(CertPaths, service.Name), - } + volumeMount := corev1.VolumeMount{ + Name: secretName, + MountPath: CertPaths, + } - volMounts.Volumes = append(volMounts.Volumes, volume) - volMounts.Mounts = append(volMounts.Mounts, volumeMount) - aeeSpec.ExtraMounts = append(aeeSpec.ExtraMounts, volMounts) + volMounts.Volumes = append(volMounts.Volumes, volume) + volMounts.Mounts = append(volMounts.Mounts, volumeMount) + + // add mount for cacerts + var caCertSecretName string + if len(service.Spec.CACerts) > 0 { + caCertSecretName = service.Spec.CACerts + } else { + caCertSecretName = tls.CABundleLabel + } + + err = client.Get(ctx, types.NamespacedName{Name: caCertSecretName, Namespace: service.Namespace}, sec) + if err != nil { + return aeeSpec, err + } + volume = corev1.Volume{ + Name: caCertSecretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: caCertSecretName, + }, + }, + } + volumeMount = corev1.VolumeMount{ + Name: caCertSecretName, + MountPath: CACertPaths, + } + + volMounts.Volumes = append(volMounts.Volumes, volume) + volMounts.Mounts = append(volMounts.Mounts, volumeMount) + aeeSpec.ExtraMounts = append(aeeSpec.ExtraMounts, volMounts) + } } return aeeSpec, nil } diff --git a/pkg/deployment/inventory.go b/pkg/deployment/inventory.go index 00c1469c2..9d6eea027 100644 --- a/pkg/deployment/inventory.go +++ b/pkg/deployment/inventory.go @@ -46,6 +46,12 @@ func GenerateNodeSetInventory(ctx context.Context, helper *helper.Helper, utils.LogErrorForObject(helper, err, "Could not resolve ansible group vars", instance) return "", err } + + // add TLS ansible variable + if instance.Spec.TLSEnabled != nil && *instance.Spec.TLSEnabled { + nodeSetGroup.Vars["tls_certs_enabled"] = "true" + } + for nodeName, node := range instance.Spec.Nodes { host := nodeSetGroup.AddHost(nodeName) // Use ansible_host if provided else use hostname. Fall back to diff --git a/pkg/deployment/ipam.go b/pkg/deployment/ipam.go index 31d706e4f..f12e1736e 100644 --- a/pkg/deployment/ipam.go +++ b/pkg/deployment/ipam.go @@ -68,12 +68,13 @@ func EnsureIPSets(ctx context.Context, helper *helper.Helper, func createOrPatchDNSData(ctx context.Context, helper *helper.Helper, instance *dataplanev1.OpenStackDataPlaneNodeSet, allIPSets map[string]infranetworkv1.IPSet) ( - string, map[string][]string, map[string][]string, error) { + string, map[string]map[infranetworkv1.NetNameStr]string, + map[string]map[infranetworkv1.NetNameStr]string, error) { var allDNSRecords []infranetworkv1.DNSHost var ctlplaneSearchDomain string - allHostnames := map[string][]string{} - allIPs := map[string][]string{} + allHostnames := map[string]map[infranetworkv1.NetNameStr]string{} + allIPs := map[string]map[infranetworkv1.NetNameStr]string{} // Build DNSData CR for nodeName, node := range instance.Spec.Nodes { @@ -81,6 +82,9 @@ func createOrPatchDNSData(ctx context.Context, helper *helper.Helper, nets := node.Networks hostName := node.HostName + allHostnames[nodeName] = map[infranetworkv1.NetNameStr]string{} + allIPs[nodeName] = map[infranetworkv1.NetNameStr]string{} + if isFQDN(hostName) { shortName = strings.Split(hostName, ".")[0] } else { @@ -101,12 +105,13 @@ func createOrPatchDNSData(ctx context.Context, helper *helper.Helper, fqdnName := strings.Join([]string{shortName, res.DNSDomain}, ".") if fqdnName != hostName { fqdnNames = append(fqdnNames, fqdnName) + allHostnames[nodeName][res.Network] = fqdnName } if isFQDN(hostName) && res.Network == CtlPlaneNetwork { fqdnNames = append(fqdnNames, hostName) + allHostnames[nodeName][res.Network] = hostName } - allHostnames[nodeName] = append(allHostnames[nodeName], fqdnNames...) - allIPs[nodeName] = append(allIPs[nodeName], res.Address) + allIPs[nodeName][res.Network] = res.Address dnsRecord.Hostnames = fqdnNames allDNSRecords = append(allDNSRecords, dnsRecord) // Adding only ctlplane domain for ansibleee. @@ -146,7 +151,8 @@ func createOrPatchDNSData(ctx context.Context, helper *helper.Helper, func EnsureDNSData(ctx context.Context, helper *helper.Helper, instance *dataplanev1.OpenStackDataPlaneNodeSet, allIPSets map[string]infranetworkv1.IPSet) ( - []string, []string, string, bool, map[string][]string, map[string][]string, error) { + []string, []string, string, bool, map[string]map[infranetworkv1.NetNameStr]string, + map[string]map[infranetworkv1.NetNameStr]string, error) { // Verify dnsmasq CR exists dnsAddresses, dnsClusterAddresses, isReady, err := CheckDNSService(