mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-07 14:05:50 +00:00
Be sure to update the DEFAULT cert instead of the per-FederationDomain cert when the supervisor is using an IP address
This commit is contained in:
@@ -38,7 +38,6 @@ import (
|
|||||||
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||||
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||||
supervisorclient "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
|
supervisorclient "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/config/v1alpha1"
|
||||||
"go.pinniped.dev/internal/certauthority"
|
|
||||||
"go.pinniped.dev/internal/crud"
|
"go.pinniped.dev/internal/crud"
|
||||||
"go.pinniped.dev/internal/here"
|
"go.pinniped.dev/internal/here"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
@@ -66,6 +65,16 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
|
|||||||
|
|
||||||
topSetupCtx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Minute)
|
topSetupCtx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
|
supervisorClient := testlib.NewSupervisorClientset(t)
|
||||||
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(
|
||||||
|
topSetupCtx,
|
||||||
|
t,
|
||||||
|
env.SupervisorNamespace,
|
||||||
|
env.DefaultTLSCertSecretName(),
|
||||||
|
supervisorClient,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Build pinniped CLI.
|
// Build pinniped CLI.
|
||||||
pinnipedExe := testlib.PinnipedCLIPath(t)
|
pinnipedExe := testlib.PinnipedCLIPath(t)
|
||||||
@@ -74,58 +83,28 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
|
|||||||
|
|
||||||
// Generate a CA bundle with which to serve this provider.
|
// Generate a CA bundle with which to serve this provider.
|
||||||
t.Logf("generating test CA")
|
t.Logf("generating test CA")
|
||||||
federationDomainSelfSignedCA, err := certauthority.New("Downstream Test CA", 1*time.Hour)
|
tlsServingCertForSupervisorSecretName := "federation-domain-serving-cert-" + testlib.RandHex(t, 8)
|
||||||
require.NoError(t, err)
|
|
||||||
|
federationDomainSelfSignedCA := createTLSServingCertSecretForSupervisor(
|
||||||
|
topSetupCtx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
tlsServingCertForSupervisorSecretName,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Save that bundle plus the one that signs the upstream issuer, for test purposes.
|
// Save that bundle plus the one that signs the upstream issuer, for test purposes.
|
||||||
federationDomainCABundlePath := filepath.Join(t.TempDir(), "test-ca.pem")
|
federationDomainCABundlePath := filepath.Join(t.TempDir(), "test-ca.pem")
|
||||||
federationDomainCABundlePEM := federationDomainSelfSignedCA.Bundle()
|
federationDomainCABundlePEM := federationDomainSelfSignedCA.Bundle()
|
||||||
require.NoError(t, os.WriteFile(federationDomainCABundlePath, federationDomainCABundlePEM, 0600))
|
require.NoError(t, os.WriteFile(federationDomainCABundlePath, federationDomainCABundlePEM, 0600))
|
||||||
|
|
||||||
// Use the CA to issue a TLS server cert.
|
|
||||||
certPEM, keyPEM := supervisorIssuer.IssuerServerCert(t, federationDomainSelfSignedCA)
|
|
||||||
|
|
||||||
supervisorClient := testlib.NewSupervisorClientset(t)
|
|
||||||
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(
|
|
||||||
topSetupCtx,
|
|
||||||
t,
|
|
||||||
env.SupervisorNamespace,
|
|
||||||
env.DefaultTLSCertSecretName(),
|
|
||||||
supervisorClient,
|
|
||||||
testlib.NewKubernetesClientset(t),
|
|
||||||
)
|
|
||||||
|
|
||||||
var tlsSpecForFederationDomain *supervisorconfigv1alpha1.FederationDomainTLSSpec
|
|
||||||
if supervisorIssuer.IsIPAddress() {
|
|
||||||
testlib.CreateTestSecretWithName(
|
|
||||||
t,
|
|
||||||
env.SupervisorNamespace,
|
|
||||||
env.DefaultTLSCertSecretName(),
|
|
||||||
corev1.SecretTypeTLS,
|
|
||||||
map[string]string{
|
|
||||||
"tls.crt": string(certPEM),
|
|
||||||
"tls.key": string(keyPEM),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} 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(certPEM),
|
|
||||||
"tls.key": string(keyPEM),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
tlsSpecForFederationDomain = &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: federationDomainTLSServingCertSecret.Name}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the downstream FederationDomain.
|
// Create the downstream FederationDomain.
|
||||||
|
// This helper function will nil out spec.TLS if spec.Issuer is an IP address.
|
||||||
federationDomain := testlib.CreateTestFederationDomain(topSetupCtx, t,
|
federationDomain := testlib.CreateTestFederationDomain(topSetupCtx, t,
|
||||||
supervisorconfigv1alpha1.FederationDomainSpec{
|
supervisorconfigv1alpha1.FederationDomainSpec{
|
||||||
Issuer: supervisorIssuer.Issuer(),
|
Issuer: supervisorIssuer.Issuer(),
|
||||||
TLS: tlsSpecForFederationDomain,
|
TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: tlsServingCertForSupervisorSecretName},
|
||||||
},
|
},
|
||||||
supervisorconfigv1alpha1.FederationDomainPhaseError, // in phase error until there is an IDP created
|
supervisorconfigv1alpha1.FederationDomainPhaseError, // in phase error until there is an IDP created
|
||||||
)
|
)
|
||||||
@@ -552,6 +531,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
|
|||||||
if runtime.GOOS != "darwin" {
|
if runtime.GOOS != "darwin" {
|
||||||
// For some unknown reason this breaks the pty library on some macOS machines.
|
// For some unknown reason this breaks the pty library on some macOS machines.
|
||||||
// The problem doesn't reproduce for everyone, so this is just a workaround.
|
// The problem doesn't reproduce for everyone, so this is just a workaround.
|
||||||
|
var err error
|
||||||
kubectlStdoutPipe, err = kubectlCmd.StdoutPipe()
|
kubectlStdoutPipe, err = kubectlCmd.StdoutPipe()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,15 @@ func TestSecureTLSSupervisor(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
startKubectlPortForward(ctx, t, "10448", "443", env.SupervisorAppName+"-nodeport", env.SupervisorNamespace)
|
supervisorIssuer := testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress)
|
||||||
|
|
||||||
|
serviceSuffix := "-nodeport"
|
||||||
|
if supervisorIssuer.IsIPAddress() {
|
||||||
|
// Then there's no nodeport service to connect to, it's a load balancer service!
|
||||||
|
serviceSuffix = "-loadbalancer"
|
||||||
|
}
|
||||||
|
|
||||||
|
startKubectlPortForward(ctx, t, "10448", "443", env.SupervisorAppName+serviceSuffix, env.SupervisorNamespace)
|
||||||
|
|
||||||
stdout, stderr := testlib.RunNmapSSLEnum(t, "127.0.0.1", 10448)
|
stdout, stderr := testlib.RunNmapSSLEnum(t, "127.0.0.1", 10448)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
applycorev1 "k8s.io/client-go/applyconfigurations/core/v1"
|
||||||
|
applymetav1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||||
|
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
"k8s.io/utils/ptr"
|
"k8s.io/utils/ptr"
|
||||||
@@ -47,16 +50,14 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) {
|
|||||||
client := testlib.NewSupervisorClientset(t)
|
client := testlib.NewSupervisorClientset(t)
|
||||||
kubeClient := testlib.NewKubernetesClientset(t)
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
|
||||||
ns := env.SupervisorNamespace
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), client, testlib.NewKubernetesClientset(t))
|
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, env.SupervisorNamespace, env.DefaultTLSCertSecretName(), client, testlib.NewKubernetesClientset(t))
|
||||||
defaultCA := createTLSCertificateSecret(
|
defaultCA := createTLSServingCertSecretForSupervisor(
|
||||||
ctx,
|
ctx,
|
||||||
t,
|
t,
|
||||||
ns,
|
env,
|
||||||
testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress),
|
testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress),
|
||||||
env.DefaultTLSCertSecretName(),
|
env.DefaultTLSCertSecretName(),
|
||||||
kubeClient,
|
kubeClient,
|
||||||
@@ -105,9 +106,9 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) {
|
|||||||
|
|
||||||
// When FederationDomains are created in sequence they each cause a discovery endpoint to appear only for as long as the FederationDomain exists.
|
// When FederationDomains are created in sequence they each cause a discovery endpoint to appear only for as long as the FederationDomain exists.
|
||||||
config1, jwks1 := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer1, client)
|
config1, jwks1 := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer1, client)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config1, client, ns, scheme, addr, caBundle, issuer1)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config1, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer1)
|
||||||
config2, jwks2 := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer2, client)
|
config2, jwks2 := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer2, client)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config2, client, ns, scheme, addr, caBundle, issuer2)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config2, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer2)
|
||||||
// The auto-created JWK's were different from each other.
|
// The auto-created JWK's were different from each other.
|
||||||
require.NotEqual(t, jwks1.Keys[0]["x"], jwks2.Keys[0]["x"])
|
require.NotEqual(t, jwks1.Keys[0]["x"], jwks2.Keys[0]["x"])
|
||||||
require.NotEqual(t, jwks1.Keys[0]["y"], jwks2.Keys[0]["y"])
|
require.NotEqual(t, jwks1.Keys[0]["y"], jwks2.Keys[0]["y"])
|
||||||
@@ -121,47 +122,47 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) {
|
|||||||
require.NotEqual(t, jwks3.Keys[0]["y"], jwks4.Keys[0]["y"])
|
require.NotEqual(t, jwks3.Keys[0]["y"], jwks4.Keys[0]["y"])
|
||||||
|
|
||||||
// Editing a FederationDomain to change the issuer URL updates the endpoints that are being served.
|
// Editing a FederationDomain to change the issuer URL updates the endpoints that are being served.
|
||||||
updatedConfig4 := editFederationDomainIssuerName(t, config4, client, ns, issuer5)
|
updatedConfig4 := editFederationDomainIssuerName(t, config4, client, env.SupervisorNamespace, issuer5)
|
||||||
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer4)
|
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer4)
|
||||||
jwks5 := requireStandardDiscoveryEndpointsAreWorking(t, scheme, addr, caBundle, issuer5, nil)
|
jwks5 := requireStandardDiscoveryEndpointsAreWorking(t, scheme, addr, caBundle, issuer5, nil)
|
||||||
// The JWK did not change when the issuer name was updated.
|
// The JWK did not change when the issuer name was updated.
|
||||||
require.Equal(t, jwks4.Keys[0], jwks5.Keys[0])
|
require.Equal(t, jwks4.Keys[0], jwks5.Keys[0])
|
||||||
|
|
||||||
// When they are deleted they stop serving discovery endpoints.
|
// When they are deleted they stop serving discovery endpoints.
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config3, client, ns, scheme, addr, caBundle, issuer3)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config3, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer3)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, updatedConfig4, client, ns, scheme, addr, caBundle, issuer5)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, updatedConfig4, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer5)
|
||||||
|
|
||||||
// When the same issuer URL is added to two FederationDomains, both FederationDomains are marked as duplicates, and neither is serving.
|
// When the same issuer URL is added to two FederationDomains, both FederationDomains are marked as duplicates, and neither is serving.
|
||||||
config6Duplicate1, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer6, client)
|
config6Duplicate1, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer6, client)
|
||||||
config6Duplicate2 := testlib.CreateTestFederationDomain(ctx, t, supervisorconfigv1alpha1.FederationDomainSpec{Issuer: issuer6}, supervisorconfigv1alpha1.FederationDomainPhaseError)
|
config6Duplicate2 := testlib.CreateTestFederationDomain(ctx, t, supervisorconfigv1alpha1.FederationDomainSpec{Issuer: issuer6}, supervisorconfigv1alpha1.FederationDomainPhaseError)
|
||||||
requireStatus(t, client, ns, config6Duplicate1.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerIsUnique"}))
|
requireStatus(t, client, env.SupervisorNamespace, config6Duplicate1.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerIsUnique"}))
|
||||||
requireStatus(t, client, ns, config6Duplicate2.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerIsUnique"}))
|
requireStatus(t, client, env.SupervisorNamespace, config6Duplicate2.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerIsUnique"}))
|
||||||
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer6)
|
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer6)
|
||||||
|
|
||||||
// If we delete the first duplicate FederationDomain, the second duplicate FederationDomain starts serving.
|
// If we delete the first duplicate FederationDomain, the second duplicate FederationDomain starts serving.
|
||||||
requireDelete(t, client, ns, config6Duplicate1.Name)
|
requireDelete(t, client, env.SupervisorNamespace, config6Duplicate1.Name)
|
||||||
requireWellKnownEndpointIsWorking(t, scheme, addr, caBundle, issuer6, nil)
|
requireWellKnownEndpointIsWorking(t, scheme, addr, caBundle, issuer6, nil)
|
||||||
requireStatus(t, client, ns, config6Duplicate2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
requireStatus(t, client, env.SupervisorNamespace, config6Duplicate2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
||||||
|
|
||||||
// When we finally delete all FederationDomains, the discovery endpoints should be down.
|
// When we finally delete all FederationDomains, the discovery endpoints should be down.
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config6Duplicate2, client, ns, scheme, addr, caBundle, issuer6)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config6Duplicate2, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer6)
|
||||||
|
|
||||||
// "Host" headers can be used to send requests to discovery endpoints when the public address is different from the issuer URL.
|
// "Host" headers can be used to send requests to discovery endpoints when the public address is different from the issuer URL.
|
||||||
issuer7 := "https://some-issuer-host-and-port-that-doesnt-match-public-supervisor-address.com:2684/issuer7"
|
issuer7 := "https://some-issuer-host-and-port-that-doesnt-match-public-supervisor-address.com:2684/issuer7"
|
||||||
config7, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer7, client)
|
config7, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer7, client)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config7, client, ns, scheme, addr, caBundle, issuer7)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config7, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer7)
|
||||||
|
|
||||||
// When we create a FederationDomain with an invalid issuer url, the status is set to invalid.
|
// When we create a FederationDomain with an invalid issuer url, the status is set to invalid.
|
||||||
badConfig := testlib.CreateTestFederationDomain(ctx, t, supervisorconfigv1alpha1.FederationDomainSpec{Issuer: badIssuer}, supervisorconfigv1alpha1.FederationDomainPhaseError)
|
badConfig := testlib.CreateTestFederationDomain(ctx, t, supervisorconfigv1alpha1.FederationDomainSpec{Issuer: badIssuer}, supervisorconfigv1alpha1.FederationDomainPhaseError)
|
||||||
requireStatus(t, client, ns, badConfig.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerURLValid"}))
|
requireStatus(t, client, env.SupervisorNamespace, badConfig.Name, supervisorconfigv1alpha1.FederationDomainPhaseError, withFalseConditions([]string{"Ready", "IssuerURLValid"}))
|
||||||
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, badIssuer)
|
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, badIssuer)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, badConfig, client, ns, scheme, addr, caBundle, badIssuer)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, badConfig, client, env.SupervisorNamespace, scheme, addr, caBundle, badIssuer)
|
||||||
|
|
||||||
issuer8 := fmt.Sprintf("https://%s/issuer8multipleIDP", addr)
|
issuer8 := fmt.Sprintf("https://%s/issuer8multipleIDP", addr)
|
||||||
config8 := requireIDPsListedByIDPDiscoveryEndpoint(t, env, ctx, kubeClient, ns, scheme, addr, caBundle, issuer8)
|
config8 := requireIDPsListedByIDPDiscoveryEndpoint(t, env, ctx, kubeClient, env.SupervisorNamespace, scheme, addr, caBundle, issuer8)
|
||||||
|
|
||||||
// requireJWKSEndpointIsWorking() will give us a bit of an idea what to do...
|
// requireJWKSEndpointIsWorking() will give us a bit of an idea what to do...
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config8, client, ns, scheme, addr, caBundle, issuer8)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config8, client, env.SupervisorNamespace, scheme, addr, caBundle, issuer8)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +173,6 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
pinnipedClient := testlib.NewSupervisorClientset(t)
|
pinnipedClient := testlib.NewSupervisorClientset(t)
|
||||||
kubeClient := testlib.NewKubernetesClientset(t)
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
|
||||||
ns := env.SupervisorNamespace
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"},
|
Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"},
|
||||||
}, idpv1alpha1.PhaseError)
|
}, idpv1alpha1.PhaseError)
|
||||||
|
|
||||||
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient)
|
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, env.SupervisorNamespace, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient)
|
||||||
|
|
||||||
scheme := "https"
|
scheme := "https"
|
||||||
supervisorIssuer := testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress)
|
supervisorIssuer := testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress)
|
||||||
@@ -203,20 +203,31 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
||||||
|
|
||||||
// Create the Secret.
|
// Create the Secret.
|
||||||
ca1 := createTLSCertificateSecret(ctx, t, ns, supervisorIssuer, certSecretName1, kubeClient)
|
ca1 := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
certSecretName1,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA.
|
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA.
|
||||||
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, address, string(ca1.Bundle()), issuer1, nil)
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, address, string(ca1.Bundle()), issuer1, nil)
|
||||||
|
|
||||||
|
// Delete the default TLS secret as well
|
||||||
|
err := kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Delete(ctx, env.DefaultTLSCertSecretName(), metav1.DeleteOptions{})
|
||||||
|
require.True(t, err == nil || apierrors.IsNotFound(err), "unexpected error when deleting the default secret: %s", err)
|
||||||
|
|
||||||
// Update the config to with a new .spec.tls.secretName.
|
// Update the config to with a new .spec.tls.secretName.
|
||||||
certSecretName1update := "integration-test-cert-1-update"
|
certSecretName1update := "integration-test-cert-1-update"
|
||||||
require.NoError(t, retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
require.NoError(t, retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
federationDomain1LatestVersion, err := pinnipedClient.ConfigV1alpha1().FederationDomains(ns).Get(ctx, federationDomain1.Name, metav1.GetOptions{})
|
federationDomain1LatestVersion, err := pinnipedClient.ConfigV1alpha1().FederationDomains(env.SupervisorNamespace).Get(ctx, federationDomain1.Name, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
federationDomain1LatestVersion.Spec.TLS = &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: certSecretName1update}
|
federationDomain1LatestVersion.Spec.TLS = &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: certSecretName1update}
|
||||||
_, err = pinnipedClient.ConfigV1alpha1().FederationDomains(ns).Update(ctx, federationDomain1LatestVersion, metav1.UpdateOptions{})
|
_, err = pinnipedClient.ConfigV1alpha1().FederationDomains(env.SupervisorNamespace).Update(ctx, federationDomain1LatestVersion, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -224,7 +235,14 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
||||||
|
|
||||||
// Create a Secret at the updated name.
|
// Create a Secret at the updated name.
|
||||||
ca1update := createTLSCertificateSecret(ctx, t, ns, supervisorIssuer, certSecretName1update, kubeClient)
|
ca1update := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
certSecretName1update,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the Secret exists at the new name, we should be able to access the endpoints by hostname using the CA.
|
// Now that the Secret exists at the new name, we should be able to access the endpoints by hostname using the CA.
|
||||||
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, address, string(ca1update.Bundle()), issuer1, nil)
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, address, string(ca1update.Bundle()), issuer1, nil)
|
||||||
@@ -244,7 +262,14 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
||||||
|
|
||||||
// Create the Secret.
|
// Create the Secret.
|
||||||
ca2 := createTLSCertificateSecret(ctx, t, ns, testlib.NewSupervisorIssuer(t, issuer2), certSecretName2, kubeClient)
|
ca2 := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
testlib.NewSupervisorIssuer(t, issuer2),
|
||||||
|
certSecretName2,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA.
|
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA.
|
||||||
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, hostname2+":"+hostnamePort2, string(ca2.Bundle()), issuer2, map[string]string{
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, hostname2+":"+hostnamePort2, string(ca2.Bundle()), issuer2, map[string]string{
|
||||||
@@ -258,7 +283,6 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
pinnipedClient := testlib.NewSupervisorClientset(t)
|
pinnipedClient := testlib.NewSupervisorClientset(t)
|
||||||
kubeClient := testlib.NewKubernetesClientset(t)
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
|
||||||
ns := env.SupervisorNamespace
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -268,7 +292,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"},
|
Client: idpv1alpha1.OIDCClient{SecretName: "this-will-not-exist-but-does-not-matter"},
|
||||||
}, idpv1alpha1.PhaseError)
|
}, idpv1alpha1.PhaseError)
|
||||||
|
|
||||||
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, ns, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient)
|
temporarilyRemoveAllFederationDomainsAndDefaultTLSCertSecret(ctx, t, env.SupervisorNamespace, env.DefaultTLSCertSecretName(), pinnipedClient, kubeClient)
|
||||||
|
|
||||||
scheme := "https"
|
scheme := "https"
|
||||||
supervisorIssuer := testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress)
|
supervisorIssuer := testlib.NewSupervisorIssuer(t, env.SupervisorHTTPSAddress)
|
||||||
@@ -296,7 +320,14 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress)
|
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress)
|
||||||
|
|
||||||
// Create a Secret at the special name which represents the default TLS cert.
|
// Create a Secret at the special name which represents the default TLS cert.
|
||||||
defaultCA := createTLSCertificateSecret(ctx, t, ns, testlib.NewSupervisorIssuer(t, issuerUsingIPAddress), env.DefaultTLSCertSecretName(), kubeClient)
|
defaultCA := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
testlib.NewSupervisorIssuer(t, issuerUsingIPAddress),
|
||||||
|
env.DefaultTLSCertSecretName(),
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the Secret exists, we should be able to access the endpoints by IP address using the CA.
|
// 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)
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, ipWithPort, string(defaultCA.Bundle()), issuerUsingIPAddress, nil)
|
||||||
@@ -311,57 +342,84 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, supervisorconfigv1alpha1.FederationDomainPhaseReady, withAllSuccessfulConditions())
|
||||||
|
|
||||||
// Create the Secret.
|
// Create the Secret.
|
||||||
certCA := createTLSCertificateSecret(ctx, t, ns, supervisorIssuer, certSecretName, kubeClient)
|
certCA := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
certSecretName,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA from the SNI cert.
|
// Now that the Secret exists, we should be able to access the endpoints by hostname using the CA from the SNI cert.
|
||||||
// Hostnames are case-insensitive, so the request should still work even if the case of the hostname is different
|
// Hostnames are case-insensitive, so the request should still work even if the case of the hostname is different
|
||||||
// from the case of the issuer URL's hostname.
|
// from the case of the issuer URL's hostname.
|
||||||
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, strings.ToUpper(hostname)+":"+port, string(certCA.Bundle()), issuerUsingHostname, nil)
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, strings.ToUpper(hostname)+":"+port, string(certCA.Bundle()), issuerUsingHostname, nil)
|
||||||
|
|
||||||
// And we can still access the other issuer using the default cert.
|
if !supervisorIssuer.IsIPAddress() {
|
||||||
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, ipWithPort, string(defaultCA.Bundle()), issuerUsingIPAddress, nil)
|
// And we can still access the other issuer using the default cert,
|
||||||
|
// except when we have an IP address, because in that case we just overwrote the default cert
|
||||||
|
_ = requireStandardDiscoveryEndpointsAreWorking(t, scheme, ipWithPort, string(defaultCA.Bundle()), issuerUsingIPAddress, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTLSCertificateSecret(
|
func createTLSServingCertSecretForSupervisor(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
namespace string,
|
env *testlib.TestEnv,
|
||||||
supervisorIssuer testlib.SupervisorIssuer,
|
supervisorIssuer testlib.SupervisorIssuer,
|
||||||
secretName string,
|
secretName string,
|
||||||
kubeClient kubernetes.Interface,
|
kubeClient kubernetes.Interface,
|
||||||
) *certauthority.CA {
|
) *certauthority.CA {
|
||||||
|
// If the issuer is an IP address, then we have to create/update the DEFAULT cert, not the given secret
|
||||||
|
if supervisorIssuer.IsIPAddress() {
|
||||||
|
secretName = env.DefaultTLSCertSecretName()
|
||||||
|
}
|
||||||
|
|
||||||
// Create a CA.
|
// Create a CA.
|
||||||
ca, err := certauthority.New("Acme Corp", 1000*time.Hour)
|
ca, err := certauthority.New("Acme Corp", 1000*time.Hour)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Using the CA, create a TLS server cert.
|
// Using the CA, create a TLS serving cert.
|
||||||
certPEM, keyPEM := supervisorIssuer.IssuerServerCert(t, ca)
|
certPEM, keyPEM := supervisorIssuer.IssuerServerCert(t, ca)
|
||||||
|
|
||||||
// Write the serving cert to the SNI secret.
|
secret := &applycorev1.SecretApplyConfiguration{
|
||||||
secret := corev1.Secret{
|
TypeMetaApplyConfiguration: applymetav1.TypeMetaApplyConfiguration{
|
||||||
Type: corev1.SecretTypeTLS,
|
Kind: ptr.To("Secret"),
|
||||||
TypeMeta: metav1.TypeMeta{},
|
APIVersion: ptr.To("v1"),
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
},
|
||||||
Name: secretName,
|
Type: ptr.To(corev1.SecretTypeTLS),
|
||||||
Namespace: namespace,
|
ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
|
||||||
|
Name: ptr.To(secretName),
|
||||||
|
Namespace: ptr.To(env.SupervisorNamespace),
|
||||||
},
|
},
|
||||||
StringData: map[string]string{
|
StringData: map[string]string{
|
||||||
"tls.crt": string(certPEM),
|
"tls.crt": string(certPEM),
|
||||||
"tls.key": string(keyPEM),
|
"tls.key": string(keyPEM),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = kubeClient.CoreV1().Secrets(namespace).Create(ctx, &secret, metav1.CreateOptions{})
|
|
||||||
|
_, err = kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Apply(ctx, secret, metav1.ApplyOptions{FieldManager: "pinniped-integration-tests"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Logf("wrote TLS cert secret to: %s/%s", namespace, secretName)
|
t.Logf("wrote TLS cert secret to: %s/%s", env.SupervisorNamespace, secretName)
|
||||||
|
|
||||||
// Delete the Secret when the test ends.
|
// Delete the Secret when the test ends.
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
deleteCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
deleteCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
err := kubeClient.CoreV1().Secrets(namespace).Delete(deleteCtx, secretName, metav1.DeleteOptions{})
|
// check to see if it exists (so that the default TLS secret doesn't get deleted multiple times)
|
||||||
require.NoError(t, err)
|
secret, err := kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Get(deleteCtx, secretName, metav1.GetOptions{})
|
||||||
|
require.True(t, err == nil || apierrors.IsNotFound(err), "unexpected error when getting secret %s/%s: %s",
|
||||||
|
env.SupervisorNamespace,
|
||||||
|
secretName,
|
||||||
|
err)
|
||||||
|
|
||||||
|
if err == nil && secret != nil {
|
||||||
|
err = kubeClient.CoreV1().Secrets(env.SupervisorNamespace).Delete(deleteCtx, secretName, metav1.DeleteOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return ca
|
return ca
|
||||||
@@ -602,7 +660,7 @@ func printServerCert(t *testing.T, address string, dnsOverrides map[string]strin
|
|||||||
|
|
||||||
host := addressURL.Host
|
host := addressURL.Host
|
||||||
if _, ok := dnsOverrides[host]; ok {
|
if _, ok := dnsOverrides[host]; ok {
|
||||||
host = dnsOverrides[address]
|
host = dnsOverrides[host]
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := tls.Dial("tcp", host, conf)
|
conn, err := tls.Dial("tcp", host, conf)
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
|
|
||||||
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||||
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||||
"go.pinniped.dev/internal/certauthority"
|
|
||||||
"go.pinniped.dev/internal/federationdomain/oidc"
|
"go.pinniped.dev/internal/federationdomain/oidc"
|
||||||
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
|
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
|
||||||
"go.pinniped.dev/internal/federationdomain/storage"
|
"go.pinniped.dev/internal/federationdomain/storage"
|
||||||
@@ -2940,15 +2939,24 @@ func testSupervisorLogin(
|
|||||||
|
|
||||||
supervisorIssuer := env.InferSupervisorIssuerURL(t)
|
supervisorIssuer := env.InferSupervisorIssuerURL(t)
|
||||||
|
|
||||||
|
tlsServingCertForSupervisorSecretName := "federation-tls-cert-" + testlib.RandHex(t, 8)
|
||||||
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
federationDomainSelfSignedCA := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
tlsServingCertForSupervisorSecretName,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Generate a CA bundle with which to serve this provider.
|
// Generate a CA bundle with which to serve this provider.
|
||||||
t.Logf("generating test CA")
|
t.Logf("generating test CA")
|
||||||
ca, err := certauthority.New("Downstream Test CA", 1*time.Hour)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Create an HTTP client that can reach the downstream discovery endpoint using the CA certs.
|
// Create an HTTP client that can reach the downstream discovery endpoint using the CA certs.
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{RootCAs: ca.Pool()}, //nolint:gosec // not concerned with TLS MinVersion here
|
TLSClientConfig: &tls.Config{RootCAs: federationDomainSelfSignedCA.Pool()}, //nolint:gosec // not concerned with TLS MinVersion here
|
||||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||||
if strings.HasPrefix(req.URL.Host, "127.0.0.1") {
|
if strings.HasPrefix(req.URL.Host, "127.0.0.1") {
|
||||||
// don't proxy requests to localhost to avoid proxying calls to our local callback listener
|
// don't proxy requests to localhost to avoid proxying calls to our local callback listener
|
||||||
@@ -2971,20 +2979,6 @@ func testSupervisorLogin(
|
|||||||
}
|
}
|
||||||
oidcHTTPClientContext := coreosoidc.ClientContext(ctx, httpClient)
|
oidcHTTPClientContext := coreosoidc.ClientContext(ctx, httpClient)
|
||||||
|
|
||||||
// Use the CA to issue a TLS server cert.
|
|
||||||
certPEM, keyPEM := supervisorIssuer.IssuerServerCert(t, ca)
|
|
||||||
|
|
||||||
// Write the serving cert to a secret.
|
|
||||||
certSecret := testlib.CreateTestSecret(t,
|
|
||||||
env.SupervisorNamespace,
|
|
||||||
"oidc-provider-tls",
|
|
||||||
corev1.SecretTypeTLS,
|
|
||||||
map[string]string{
|
|
||||||
"tls.crt": string(certPEM),
|
|
||||||
"tls.key": string(keyPEM),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create upstream IDP and wait for it to become ready.
|
// Create upstream IDP and wait for it to become ready.
|
||||||
idpName := createIDP(t)
|
idpName := createIDP(t)
|
||||||
|
|
||||||
@@ -2996,10 +2990,11 @@ func testSupervisorLogin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the downstream FederationDomain and expect it to go into the appropriate status condition.
|
// Create the downstream FederationDomain and expect it to go into the appropriate status condition.
|
||||||
|
// This helper function will nil out spec.TLS if spec.Issuer is an IP address.
|
||||||
federationDomain := testlib.CreateTestFederationDomain(ctx, t,
|
federationDomain := testlib.CreateTestFederationDomain(ctx, t,
|
||||||
supervisorconfigv1alpha1.FederationDomainSpec{
|
supervisorconfigv1alpha1.FederationDomainSpec{
|
||||||
Issuer: supervisorIssuer.Issuer(),
|
Issuer: supervisorIssuer.Issuer(),
|
||||||
TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: certSecret.Name},
|
TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: tlsServingCertForSupervisorSecretName},
|
||||||
IdentityProviders: fdIDPSpec,
|
IdentityProviders: fdIDPSpec,
|
||||||
},
|
},
|
||||||
// The IDP CR already exists, so even for legacy FederationDomains which do not explicitly list
|
// The IDP CR already exists, so even for legacy FederationDomains which do not explicitly list
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ import (
|
|||||||
"github.com/creack/pty"
|
"github.com/creack/pty"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
authorizationv1 "k8s.io/api/authorization/v1"
|
authorizationv1 "k8s.io/api/authorization/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
|
|
||||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||||
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
supervisorconfigv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||||
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||||
"go.pinniped.dev/internal/certauthority"
|
|
||||||
"go.pinniped.dev/internal/federationdomain/oidc"
|
"go.pinniped.dev/internal/federationdomain/oidc"
|
||||||
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
|
"go.pinniped.dev/internal/federationdomain/oidcclientvalidator"
|
||||||
"go.pinniped.dev/internal/federationdomain/storage"
|
"go.pinniped.dev/internal/federationdomain/storage"
|
||||||
@@ -49,37 +47,33 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
|
|||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
supervisorIssuer := env.InferSupervisorIssuerURL(t)
|
supervisorIssuer := env.InferSupervisorIssuerURL(t)
|
||||||
|
kubeClient := testlib.NewKubernetesClientset(t)
|
||||||
|
var err error
|
||||||
|
|
||||||
// Generate a CA bundle with which to serve this provider.
|
// Generate a CA bundle with which to serve this provider.
|
||||||
t.Logf("generating test CA")
|
t.Logf("generating test CA")
|
||||||
ca, err := certauthority.New("Downstream Test CA", 1*time.Hour)
|
downstreamTLSServingCertName := "oidc-provider-tls-" + testlib.RandHex(t, 8)
|
||||||
require.NoError(t, err)
|
federationDomainSelfSignedCA := createTLSServingCertSecretForSupervisor(
|
||||||
|
ctx,
|
||||||
|
t,
|
||||||
|
env,
|
||||||
|
supervisorIssuer,
|
||||||
|
downstreamTLSServingCertName,
|
||||||
|
kubeClient,
|
||||||
|
)
|
||||||
|
|
||||||
// Save that bundle plus the one that signs the upstream issuer, for test purposes.
|
// Save that bundle plus the one that signs the upstream issuer, for test purposes.
|
||||||
testCABundlePath := filepath.Join(tempDir, "test-ca.pem")
|
testCABundlePath := filepath.Join(tempDir, "test-ca.pem")
|
||||||
testCABundlePEM := []byte(string(ca.Bundle()) + "\n" + env.SupervisorUpstreamOIDC.CABundle)
|
testCABundlePEM := []byte(string(federationDomainSelfSignedCA.Bundle()) + "\n" + env.SupervisorUpstreamOIDC.CABundle)
|
||||||
testCABundleBase64 := base64.StdEncoding.EncodeToString(testCABundlePEM)
|
testCABundleBase64 := base64.StdEncoding.EncodeToString(testCABundlePEM)
|
||||||
require.NoError(t, os.WriteFile(testCABundlePath, testCABundlePEM, 0600))
|
require.NoError(t, os.WriteFile(testCABundlePath, testCABundlePEM, 0600))
|
||||||
|
|
||||||
// Use the CA to issue a TLS server cert.
|
|
||||||
certPEM, keyPEM := supervisorIssuer.IssuerServerCert(t, ca)
|
|
||||||
|
|
||||||
// Write the serving cert to a secret.
|
|
||||||
certSecret := testlib.CreateTestSecret(t,
|
|
||||||
env.SupervisorNamespace,
|
|
||||||
"oidc-provider-tls",
|
|
||||||
corev1.SecretTypeTLS,
|
|
||||||
map[string]string{
|
|
||||||
"tls.crt": string(certPEM),
|
|
||||||
"tls.key": string(keyPEM),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create the downstream FederationDomain and expect it to go into the success status condition.
|
// Create the downstream FederationDomain and expect it to go into the success status condition.
|
||||||
|
// This helper function will nil out spec.TLS if spec.Issuer is an IP address.
|
||||||
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
||||||
supervisorconfigv1alpha1.FederationDomainSpec{
|
supervisorconfigv1alpha1.FederationDomainSpec{
|
||||||
Issuer: supervisorIssuer.Issuer(),
|
Issuer: supervisorIssuer.Issuer(),
|
||||||
TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: certSecret.Name},
|
TLS: &supervisorconfigv1alpha1.FederationDomainTLSSpec{SecretName: downstreamTLSServingCertName},
|
||||||
},
|
},
|
||||||
supervisorconfigv1alpha1.FederationDomainPhaseError, // in phase error until there is an IDP created
|
supervisorconfigv1alpha1.FederationDomainPhaseError, // in phase error until there is an IDP created
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -367,6 +367,11 @@ func CreateTestFederationDomain(
|
|||||||
createContext, cancel := context.WithTimeout(ctx, time.Minute)
|
createContext, cancel := context.WithTimeout(ctx, time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
// If the issuer is an IP address, then we have to update the DEFAULT cert, and there's no secret associated with this FederationDomain
|
||||||
|
if NewSupervisorIssuer(t, spec.Issuer).IsIPAddress() {
|
||||||
|
spec.TLS = nil
|
||||||
|
}
|
||||||
|
|
||||||
federationDomainsClient := NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(testEnv.SupervisorNamespace)
|
federationDomainsClient := NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(testEnv.SupervisorNamespace)
|
||||||
federationDomain, err := federationDomainsClient.Create(createContext, &supervisorconfigv1alpha1.FederationDomain{
|
federationDomain, err := federationDomainsClient.Create(createContext, &supervisorconfigv1alpha1.FederationDomain{
|
||||||
ObjectMeta: TestObjectMeta(t, "oidc-provider"),
|
ObjectMeta: TestObjectMeta(t, "oidc-provider"),
|
||||||
|
|||||||
Reference in New Issue
Block a user