diff --git a/control-plane-operator/controllers/hostedcontrolplane/pki/etcd.go b/control-plane-operator/controllers/hostedcontrolplane/pki/etcd.go index 69c6526d7b64..26a4cbc69897 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/pki/etcd.go +++ b/control-plane-operator/controllers/hostedcontrolplane/pki/etcd.go @@ -45,6 +45,11 @@ func ReconcileEtcdPeerSecret(secret, ca *corev1.Secret, ownerRef config.OwnerRef dnsNames := []string{ fmt.Sprintf("*.etcd-discovery.%s.svc", secret.Namespace), fmt.Sprintf("*.etcd-discovery.%s.svc.cluster.local", secret.Namespace), + // etcd-client headless service shares pod IPs with etcd-discovery; reverse DNS may resolve + // to etcd-client, so peer certs must include both service SANs to pass TLS verification. + fmt.Sprintf("*.etcd-client.%s.svc", secret.Namespace), + fmt.Sprintf("*.etcd-client.%s.svc.cluster.local", secret.Namespace), + // TODO(OCPBUGS-86648): move IPs to the ips parameter of reconcileSignedCertWithKeysAndAddresses. "127.0.0.1", "::1", } diff --git a/control-plane-operator/controllers/hostedcontrolplane/pki/etcd_test.go b/control-plane-operator/controllers/hostedcontrolplane/pki/etcd_test.go new file mode 100644 index 000000000000..6bf612ab53b1 --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/pki/etcd_test.go @@ -0,0 +1,82 @@ +package pki + +import ( + "crypto/x509" + "crypto/x509/pkix" + "testing" + + . "github.com/onsi/gomega" + + "github.com/openshift/hypershift/support/certs" + "github.com/openshift/hypershift/support/config" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestReconcileEtcdPeerSecret(t *testing.T) { + t.Parallel() + + caCfg := certs.CertCfg{ + IsCA: true, + Subject: pkix.Name{CommonName: "etcd-signer", OrganizationalUnit: []string{"openshift"}}, + } + caKey, caCert, err := certs.GenerateSelfSignedCertificate(&caCfg) + if err != nil { + t.Fatalf("failed to generate CA: %v", err) + } + caSecret := &corev1.Secret{ + Data: map[string][]byte{ + certs.CASignerCertMapKey: certs.CertToPem(caCert), + certs.CASignerKeyMapKey: certs.PrivateKeyToPem(caKey), + }, + } + + t.Run("When reconciling etcd peer secret it should include both etcd-discovery and etcd-client SANs", func(t *testing.T) { + g := NewWithT(t) + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "clusters-test", + }, + } + + err := ReconcileEtcdPeerSecret(secret, caSecret, config.OwnerRef{}) + g.Expect(err).ToNot(HaveOccurred()) + + certData := secret.Data[EtcdPeerCrtKey] + g.Expect(certData).ToNot(BeEmpty()) + + cert, err := certs.PemToCertificate(certData) + g.Expect(err).ToNot(HaveOccurred()) + + g.Expect(cert.DNSNames).To(ContainElements( + "*.etcd-discovery.clusters-test.svc", + "*.etcd-discovery.clusters-test.svc.cluster.local", + "*.etcd-client.clusters-test.svc", + "*.etcd-client.clusters-test.svc.cluster.local", + // TODO(OCPBUGS-86648): assert on cert.IPAddresses instead once IPs are moved out of dnsNames. + "127.0.0.1", + "::1", + )) + }) + + t.Run("When reconciling etcd peer secret it should have client and server auth usage", func(t *testing.T) { + g := NewWithT(t) + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "clusters-test", + }, + } + + err := ReconcileEtcdPeerSecret(secret, caSecret, config.OwnerRef{}) + g.Expect(err).ToNot(HaveOccurred()) + + cert, err := certs.PemToCertificate(secret.Data[EtcdPeerCrtKey]) + g.Expect(err).ToNot(HaveOccurred()) + + g.Expect(cert.ExtKeyUsage).To(ContainElements( + x509.ExtKeyUsageClientAuth, + x509.ExtKeyUsageServerAuth, + )) + }) +} diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/AROSwift/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/AROSwift/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml index 9281169c4e4c..5b38919b362b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/AROSwift/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/AROSwift/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml @@ -14,7 +14,6 @@ metadata: uid: "" resourceVersion: "1" spec: - clusterIP: None ports: - name: etcd-client port: 2379 diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/GCP/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/GCP/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml index 9281169c4e4c..5b38919b362b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/GCP/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/GCP/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml @@ -14,7 +14,6 @@ metadata: uid: "" resourceVersion: "1" spec: - clusterIP: None ports: - name: etcd-client port: 2379 diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/IBMCloud/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/IBMCloud/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml index 9281169c4e4c..5b38919b362b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/IBMCloud/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/IBMCloud/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml @@ -14,7 +14,6 @@ metadata: uid: "" resourceVersion: "1" spec: - clusterIP: None ports: - name: etcd-client port: 2379 diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml index 9281169c4e4c..5b38919b362b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml @@ -14,7 +14,6 @@ metadata: uid: "" resourceVersion: "1" spec: - clusterIP: None ports: - name: etcd-client port: 2379 diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml index 9281169c4e4c..5b38919b362b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/etcd/zz_fixture_TestControlPlaneComponents_etcd_client_service.yaml @@ -14,7 +14,6 @@ metadata: uid: "" resourceVersion: "1" spec: - clusterIP: None ports: - name: etcd-client port: 2379 diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/assets/etcd/service.yaml b/control-plane-operator/controllers/hostedcontrolplane/v2/assets/etcd/service.yaml index 1eda5d8ddffd..b2c7abe18014 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/assets/etcd/service.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/assets/etcd/service.yaml @@ -5,7 +5,6 @@ metadata: app: etcd name: etcd-client spec: - clusterIP: None ports: - name: etcd-client port: 2379