From c8b17978a991916d8c08bd224d9c00521cc47c7f Mon Sep 17 00:00:00 2001 From: Matt Moyer Date: Mon, 16 Nov 2020 10:40:18 -0600 Subject: [PATCH] Convert CLI tests to work through an HTTP forward proxy. This change deploys a small Squid-based proxy into the `dex` namespace in our integration test environment. This lets us use the cluster-local DNS name (`http://dex.dex.svc.cluster.local/dex`) as the OIDC issuer. It will make generating certificates easier, and most importantly it will mean that our CLI can see Dex at the same name/URL as the supervisor running inside the cluster. Signed-off-by: Matt Moyer --- hack/prepare-for-integration-tests.sh | 3 +- test/deploy/dex/dex.yaml | 11 +++-- test/deploy/dex/proxy.yaml | 58 +++++++++++++++++++++++++++ test/deploy/dex/values.yaml | 6 +-- test/integration/cli_test.go | 25 ++++++++++-- test/library/env.go | 2 + 6 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 test/deploy/dex/proxy.yaml diff --git a/hack/prepare-for-integration-tests.sh b/hack/prepare-for-integration-tests.sh index d3d7cb24..25c4ad0f 100755 --- a/hack/prepare-for-integration-tests.sh +++ b/hack/prepare-for-integration-tests.sh @@ -286,7 +286,8 @@ export PINNIPED_TEST_SUPERVISOR_APP_NAME=${supervisor_app_name} export PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS='${supervisor_custom_labels}' export PINNIPED_TEST_SUPERVISOR_HTTP_ADDRESS="127.0.0.1:12345" export PINNIPED_TEST_SUPERVISOR_HTTPS_ADDRESS="localhost:12344" -export PINNIPED_TEST_CLI_OIDC_ISSUER=http://127.0.0.1:12346/dex +export PINNIPED_TEST_PROXY=http://127.0.0.1:12346 +export PINNIPED_TEST_CLI_OIDC_ISSUER=http://dex.dex.svc.cluster.local/dex export PINNIPED_TEST_CLI_OIDC_CLIENT_ID=pinniped-cli export PINNIPED_TEST_CLI_OIDC_LOCALHOST_PORT=48095 export PINNIPED_TEST_CLI_OIDC_USERNAME=pinny@example.com diff --git a/test/deploy/dex/dex.yaml b/test/deploy/dex/dex.yaml index dcea584f..447a561f 100644 --- a/test/deploy/dex/dex.yaml +++ b/test/deploy/dex/dex.yaml @@ -6,13 +6,13 @@ #@ load("@ytt:yaml", "yaml") #@ def dexConfig(): -issuer: #@ "http://127.0.0.1:" + str(data.values.ports.local) + "/dex" +issuer: http://dex.dex.svc.cluster.local/dex storage: type: sqlite3 config: file: ":memory:" web: - http: 0.0.0.0:5556 + http: 0.0.0.0:80 oauth2: skipApprovalScreen: true staticClients: @@ -77,7 +77,7 @@ spec: - /etc/dex/cfg/config.yaml ports: - name: http - containerPort: 5556 + containerPort: 80 volumeMounts: - name: config mountPath: /etc/dex/cfg @@ -94,9 +94,8 @@ metadata: labels: app: dex spec: - type: NodePort + type: ClusterIP selector: app: dex ports: - - port: 5556 - nodePort: #@ data.values.ports.node + - port: 80 diff --git a/test/deploy/dex/proxy.yaml b/test/deploy/dex/proxy.yaml new file mode 100644 index 00000000..1d7d8a66 --- /dev/null +++ b/test/deploy/dex/proxy.yaml @@ -0,0 +1,58 @@ +#! Copyright 2020 the Pinniped contributors. All Rights Reserved. +#! SPDX-License-Identifier: Apache-2.0 + +#@ load("@ytt:data", "data") +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: proxy + namespace: dex + labels: + app: proxy +spec: + replicas: 1 + selector: + matchLabels: + app: proxy + template: + metadata: + labels: + app: proxy + spec: + containers: + - name: proxy + image: docker.io/getpinniped/test-forward-proxy + imagePullPolicy: Always + ports: + - name: http + containerPort: 3128 + resources: + requests: + cpu: "10m" + memory: "64Mi" + limits: + cpu: "10m" + memory: "64Mi" + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 5 + failureThreshold: 2 +--- +apiVersion: v1 +kind: Service +metadata: + name: proxy + namespace: dex + labels: + app: proxy +spec: + type: NodePort + selector: + app: proxy + ports: + - port: 3128 + nodePort: #@ data.values.ports.node \ No newline at end of file diff --git a/test/deploy/dex/values.yaml b/test/deploy/dex/values.yaml index 7d04cdb1..27022cdb 100644 --- a/test/deploy/dex/values.yaml +++ b/test/deploy/dex/values.yaml @@ -8,10 +8,10 @@ ports: #! Used in the Dex configuration to form the valid redirect URIs for our test client. cli: 48095 - #! Kubernetes NodePort that should be forwarded to the Dex service. + #! Kubernetes NodePort that should be forwarded to the proxy service. #! Used to create a Service of type: NodePort node: 31235 - #! External port where Dex ends up exposed on localhost during tests. This value comes from our - #! Kind configuration which maps 127.0.0.1:12346 to port 31235 on the Kind worker node. + #! External port where the proxy ends up exposed on localhost during tests. This value comes from + #! our Kind configuration which maps 127.0.0.1:12346 to port 31235 on the Kind worker node. local: 12346 diff --git a/test/integration/cli_test.go b/test/integration/cli_test.go index 93d8fb19..50980e5e 100644 --- a/test/integration/cli_test.go +++ b/test/integration/cli_test.go @@ -130,8 +130,8 @@ func getLoginProvider(t *testing.T) *loginProviderPatterns { }, { Name: "Dex", - IssuerPattern: regexp.MustCompile(`\Ahttp://127\.0\.0\.1.+/dex.*\z`), - LoginPagePattern: regexp.MustCompile(`\Ahttp://127\.0\.0\.1.+/dex/auth/local.+\z`), + IssuerPattern: regexp.MustCompile(`\Ahttp://dex\.dex\.svc\.cluster\.local/dex.*\z`), + LoginPagePattern: regexp.MustCompile(`\Ahttp://dex\.dex\.svc\.cluster\.local/dex/auth/local.+\z`), UsernameSelector: "input#login", PasswordSelector: "input#password", LoginButtonSelector: "button#submit-login", @@ -156,7 +156,18 @@ func TestCLILoginOIDC(t *testing.T) { // Start the browser driver. t.Logf("opening browser driver") + caps := agouti.NewCapabilities() + if env.Proxy != "" { + t.Logf("configuring Chrome to use proxy %q", env.Proxy) + caps = caps.Proxy(agouti.ProxyConfig{ + ProxyType: "manual", + HTTPProxy: env.Proxy, + SSLProxy: env.Proxy, + NoProxy: "127.0.0.1", + }) + } agoutiDriver := agouti.ChromeDriver( + agouti.Desired(caps), agouti.ChromeOptions("args", []string{ "--no-sandbox", "--headless", // Comment out this line to see the tests happen in a visible browser window. @@ -395,11 +406,19 @@ func spawnTestGoroutine(t *testing.T, f func() error) { func oidcLoginCommand(ctx context.Context, t *testing.T, pinnipedExe string, sessionCachePath string) *exec.Cmd { env := library.IntegrationEnv(t) - return exec.CommandContext(ctx, pinnipedExe, "login", "oidc", + cmd := exec.CommandContext(ctx, pinnipedExe, "login", "oidc", "--issuer", env.OIDCUpstream.Issuer, "--client-id", env.OIDCUpstream.ClientID, "--listen-port", strconv.Itoa(env.OIDCUpstream.LocalhostPort), "--session-cache", sessionCachePath, "--skip-browser", ) + if env.Proxy != "" { + cmd.Env = append(os.Environ(), + "http_proxy="+env.Proxy, + "https_proxy="+env.Proxy, + "no_proxy=127.0.0.1", + ) + } + return cmd } diff --git a/test/library/env.go b/test/library/env.go index 8cba1c11..14c2ada1 100644 --- a/test/library/env.go +++ b/test/library/env.go @@ -38,6 +38,7 @@ type TestEnv struct { SupervisorHTTPSAddress string `json:"supervisorHttpsAddress"` SupervisorHTTPSIngressAddress string `json:"supervisorHttpsIngressAddress"` SupervisorHTTPSIngressCABundle string `json:"supervisorHttpsIngressCABundle"` + Proxy string `json:"proxy"` TestUser struct { Token string `json:"token"` @@ -126,6 +127,7 @@ func loadEnvVars(t *testing.T, result *TestEnv) { require.NoErrorf(t, err, "PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS must be a YAML map of string to string") result.SupervisorCustomLabels = supervisorCustomLabels require.NotEmpty(t, result.SupervisorCustomLabels, "PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS cannot be empty") + result.Proxy = os.Getenv("PINNIPED_TEST_PROXY") result.OIDCUpstream.Issuer = needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER") result.OIDCUpstream.ClientID = needEnv(t, "PINNIPED_TEST_CLI_OIDC_CLIENT_ID")