From 557dee06f0a1d45e33c3de773e2f54180a2d7455 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Fri, 30 Aug 2024 15:48:04 -0500 Subject: [PATCH] Allow the integration tests to set an IP address for the Supervisor issuer Co-authored-by: Ryan Richard --- test/integration/e2e_test.go | 54 +++++++++++++++---- test/integration/supervisor_discovery_test.go | 14 ++--- ...supervisor_federationdomain_status_test.go | 2 +- test/integration/supervisor_healthz_test.go | 4 +- test/testlib/client.go | 27 +++++++--- test/testlib/env.go | 7 +-- 6 files changed, 77 insertions(+), 31 deletions(-) diff --git a/test/integration/e2e_test.go b/test/integration/e2e_test.go index 7732e4da0..f079ce33a 100644 --- a/test/integration/e2e_test.go +++ b/test/integration/e2e_test.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "io" + "net" "net/url" "os" "os/exec" @@ -71,6 +72,11 @@ func TestE2EFullIntegration_Browser(t *testing.T) { pinnipedExe := testlib.PinnipedCLIPath(t) issuerURL, _ := env.InferSupervisorIssuerURL(t) + isIssuerAnIPAddress := net.ParseIP(issuerURL.Hostname()) != nil + var issuerIPs []net.IP + if isIssuerAnIPAddress { + issuerIPs = append(issuerIPs, net.ParseIP(issuerURL.Hostname())) + } // Generate a CA bundle with which to serve this provider. t.Logf("generating test CA") @@ -85,24 +91,52 @@ func TestE2EFullIntegration_Browser(t *testing.T) { // Use the CA to issue a TLS server cert. t.Logf("issuing test certificate") federationDomainTLSServingCert, err := federationDomainSelfSignedCA.IssueServerCert( - []string{issuerURL.Hostname()}, nil, 1*time.Hour) + []string{issuerURL.Hostname()}, issuerIPs, 1*time.Hour) require.NoError(t, err) federationDomainTLSServingCertPEM, federationDomainTLSServingCertKeyPEM, err := certauthority.ToPEM(federationDomainTLSServingCert) require.NoError(t, err) - // Write the serving cert to a secret. - federationDomainTLSServingCertSecret := testlib.CreateTestSecret(t, + supervisorClient := testlib.NewSupervisorClientset(t) + temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret( + topSetupCtx, + t, env.SupervisorNamespace, - "oidc-provider-tls", - corev1.SecretTypeTLS, - map[string]string{"tls.crt": string(federationDomainTLSServingCertPEM), "tls.key": string(federationDomainTLSServingCertKeyPEM)}, + env.DefaultTLSCertSecretName(), + supervisorClient, + testlib.NewKubernetesClientset(t), ) - // Create the downstream FederationDomain and expect it to go into the success status condition. + var tlsSpecForFederationDomain *supervisorconfigv1alpha1.FederationDomainTLSSpec + if isIssuerAnIPAddress { + testlib.CreateTestSecretWithName( + t, + env.SupervisorNamespace, + env.DefaultTLSCertSecretName(), + corev1.SecretTypeTLS, + map[string]string{ + "tls.crt": string(federationDomainTLSServingCertPEM), + "tls.key": string(federationDomainTLSServingCertKeyPEM), + }, + ) + } else { + // Write the serving cert to a secret. + federationDomainTLSServingCertSecret := testlib.CreateTestSecret(t, + env.SupervisorNamespace, + "oidc-provider-tls", + corev1.SecretTypeTLS, + map[string]string{ + "tls.crt": string(federationDomainTLSServingCertPEM), + "tls.key": string(federationDomainTLSServingCertKeyPEM), + }, + ) + tlsSpecForFederationDomain = &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: federationDomainTLSServingCertSecret.Name} + } + + // Create the downstream FederationDomain. federationDomain := testlib.CreateTestFederationDomain(topSetupCtx, t, supervisorconfigv1alpha1.FederationDomainSpec{ Issuer: issuerURL.String(), - TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: federationDomainTLSServingCertSecret.Name}, + TLS: tlsSpecForFederationDomain, }, supervisorconfigv1alpha1.FederationDomainPhaseError, // in phase error until there is an IDP created ) @@ -1416,7 +1450,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) { testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authenticationv1alpha1.JWTAuthenticatorPhaseReady) // Update the FederationDomain to use the two IDPs. - federationDomainsClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(env.SupervisorNamespace) + federationDomainsClient := supervisorClient.ConfigV1alpha1().FederationDomains(env.SupervisorNamespace) gotFederationDomain, err := federationDomainsClient.Get(testCtx, federationDomain.Name, metav1.GetOptions{}) require.NoError(t, err) @@ -1736,7 +1770,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) { testlib.WaitForJWTAuthenticatorStatusPhase(testCtx, t, authenticator.Name, authenticationv1alpha1.JWTAuthenticatorPhaseReady) // Update the FederationDomain to use the two IDPs. - federationDomainsClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(env.SupervisorNamespace) + federationDomainsClient := supervisorClient.ConfigV1alpha1().FederationDomains(env.SupervisorNamespace) gotFederationDomain, err := federationDomainsClient.Get(testCtx, federationDomain.Name, metav1.GetOptions{}) require.NoError(t, err) diff --git a/test/integration/supervisor_discovery_test.go b/test/integration/supervisor_discovery_test.go index 5c0f19db0..61528ef38 100644 --- a/test/integration/supervisor_discovery_test.go +++ b/test/integration/supervisor_discovery_test.go @@ -61,8 +61,8 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) { ips = append(ips, ip) } - temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), client, testlib.NewKubernetesClientset(t)) - defaultCA := createTLSCertificateSecret(ctx, t, ns, httpsAddress, ips, defaultTLSCertSecretName(env), kubeClient) + temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), client, testlib.NewKubernetesClientset(t)) + defaultCA := createTLSCertificateSecret(ctx, t, ns, httpsAddress, ips, env.DefaultTLSCertSecretName(), kubeClient) tests := []struct { Name string @@ -182,7 +182,7 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) { Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"}, }, idpv1alpha1.PhaseError) - temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), pinnipedClient, kubeClient) + temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient) scheme := "https" address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 8443 @@ -268,7 +268,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) { Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"}, }, idpv1alpha1.PhaseError) - temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), pinnipedClient, kubeClient) + temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient) scheme := "https" address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 8443 @@ -297,7 +297,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) { requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress) // Create a Secret at the special name which represents the default TLS cert. - defaultCA := createTLSCertificateSecret(ctx, t, ns, "cert-hostname-doesnt-matter", []net.IP{ips[0]}, defaultTLSCertSecretName(env), kubeClient) + defaultCA := createTLSCertificateSecret(ctx, t, ns, "cert-hostname-doesnt-matter", []net.IP{ips[0]}, env.DefaultTLSCertSecretName(), kubeClient) // Now that the Secret exists, we should be able to access the endpoints by IP address using the CA. _ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, ipWithPort, string(defaultCA.Bundle()), issuerUsingIPAddress, nil) @@ -323,10 +323,6 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) { _ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, ipWithPort, string(defaultCA.Bundle()), issuerUsingIPAddress, nil) } -func defaultTLSCertSecretName(env *testlib.TestEnv) string { - return env.SupervisorAppName + "-default-tls-certificate" -} - func createTLSCertificateSecret(ctx context.Context, t *testing.T, ns string, hostname string, ips []net.IP, secretName string, kubeClient kubernetes.Interface) *certauthority.CA { // Create a CA. ca, err := certauthority.New("Acme Corp", 1000*time.Hour) diff --git a/test/integration/supervisor_federationdomain_status_test.go b/test/integration/supervisor_federationdomain_status_test.go index 03ae38e56..27877b616 100644 --- a/test/integration/supervisor_federationdomain_status_test.go +++ b/test/integration/supervisor_federationdomain_status_test.go @@ -33,7 +33,7 @@ func TestSupervisorFederationDomainStatus_Disruptive(t *testing.T) { t.Cleanup(cancel) temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, - env.SupervisorNamespace, defaultTLSCertSecretName(env), supervisorClient, testlib.NewKubernetesClientset(t)) + env.SupervisorNamespace, env.DefaultTLSCertSecretName(), supervisorClient, testlib.NewKubernetesClientset(t)) tests := []struct { name string diff --git a/test/integration/supervisor_healthz_test.go b/test/integration/supervisor_healthz_test.go index d32d4a821..a84ba8534 100644 --- a/test/integration/supervisor_healthz_test.go +++ b/test/integration/supervisor_healthz_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package integration @@ -27,7 +27,7 @@ func TestSupervisorHealthzBootstrap_Disruptive(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() - temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), pinnipedClient, kubeClient) + temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient) httpClient := &http.Client{ Transport: &http.Transport{ diff --git a/test/testlib/client.go b/test/testlib/client.go index 41271f3e6..90ac06ce5 100644 --- a/test/testlib/client.go +++ b/test/testlib/client.go @@ -474,17 +474,13 @@ func CreateTestConfigMap(t *testing.T, namespace string, baseName string, string return created } -func CreateTestSecret(t *testing.T, namespace string, baseName string, secretType corev1.SecretType, stringData map[string]string) *corev1.Secret { +func createTestSecret(t *testing.T, namespace string, secret *corev1.Secret) *corev1.Secret { t.Helper() client := NewKubernetesClientset(t) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - created, err := client.CoreV1().Secrets(namespace).Create(ctx, &corev1.Secret{ - ObjectMeta: TestObjectMeta(t, baseName), - Type: secretType, - StringData: stringData, - }, metav1.CreateOptions{}) + created, err := client.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) require.NoError(t, err) t.Cleanup(func() { @@ -496,6 +492,25 @@ func CreateTestSecret(t *testing.T, namespace string, baseName string, secretTyp return created } +func CreateTestSecret(t *testing.T, namespace string, baseName string, secretType corev1.SecretType, stringData map[string]string) *corev1.Secret { + return createTestSecret(t, namespace, &corev1.Secret{ + ObjectMeta: TestObjectMeta(t, baseName), + Type: secretType, + StringData: stringData, + }) +} + +func CreateTestSecretWithName(t *testing.T, namespace string, name string, secretType corev1.SecretType, stringData map[string]string) *corev1.Secret { + secret := &corev1.Secret{ + ObjectMeta: TestObjectMeta(t, ""), + Type: secretType, + StringData: stringData, + } + secret.GenerateName = "" + secret.Name = name + return createTestSecret(t, namespace, secret) +} + func CreateTestSecretBytes(t *testing.T, namespace string, baseName string, secretType corev1.SecretType, data map[string][]byte) *corev1.Secret { t.Helper() client := NewKubernetesClientset(t) diff --git a/test/testlib/env.go b/test/testlib/env.go index 23833c783..bb1977c27 100644 --- a/test/testlib/env.go +++ b/test/testlib/env.go @@ -98,6 +98,10 @@ func (e *TestEnv) InferSupervisorIssuerURL(t *testing.T) (*url.URL, string) { return issuerURL, issuerAsString } +func (e *TestEnv) DefaultTLSCertSecretName() string { + return e.SupervisorAppName + "-default-tls-certificate" +} + type TestLDAPUpstream struct { Host string `json:"host"` Domain string `json:"domain"` @@ -262,9 +266,6 @@ func loadEnvVars(t *testing.T, result *TestEnv) { result.SupervisorHTTPSIngressAddress = os.Getenv("PINNIPED_TEST_SUPERVISOR_HTTPS_INGRESS_ADDRESS") result.SupervisorHTTPSAddress = needEnv(t, "PINNIPED_TEST_SUPERVISOR_HTTPS_ADDRESS") - require.NotRegexp(t, "^[0-9]", result.SupervisorHTTPSAddress, - "PINNIPED_TEST_SUPERVISOR_HTTPS_ADDRESS must be a hostname with an optional port and cannot be an IP address", - ) result.SupervisorHTTPSIngressCABundle = base64Decoded(t, os.Getenv("PINNIPED_TEST_SUPERVISOR_HTTPS_INGRESS_CA_BUNDLE")) conciergeCustomLabelsYAML := needEnv(t, "PINNIPED_TEST_CONCIERGE_CUSTOM_LABELS")