diff --git a/hack/prepare-for-integration-tests.sh b/hack/prepare-for-integration-tests.sh index 25c4ad0f..89b7f2f8 100755 --- a/hack/prepare-for-integration-tests.sh +++ b/hack/prepare-for-integration-tests.sh @@ -265,6 +265,11 @@ if ! tilt_mode; then popd >/dev/null fi +# +# Download the test CA bundle that was generated in the Dex pod. +# +test_ca_bundle_pem="$(kubectl exec -n dex deployment/dex -- cat /var/certs/ca.pem)" + # # Create the environment file # @@ -287,7 +292,8 @@ 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_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_ISSUER=https://dex.dex.svc.cluster.local/dex +export PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE="${test_ca_bundle_pem}" 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 447a561f..6372d49a 100644 --- a/test/deploy/dex/dex.yaml +++ b/test/deploy/dex/dex.yaml @@ -6,13 +6,15 @@ #@ load("@ytt:yaml", "yaml") #@ def dexConfig(): -issuer: http://dex.dex.svc.cluster.local/dex +issuer: https://dex.dex.svc.cluster.local/dex storage: type: sqlite3 config: file: ":memory:" web: - http: 0.0.0.0:80 + https: 0.0.0.0:443 + tlsCert: /var/certs/dex.pem + tlsKey: /var/certs/dex-key.pem oauth2: skipApprovalScreen: true staticClients: @@ -67,24 +69,59 @@ spec: annotations: dexConfigHash: #@ sha256.sum(yaml.encode(dexConfig())) spec: + initContainers: + - name: generate-certs + image: cfssl/cfssl:1.5.0 + imagePullPolicy: IfNotPresent + command: ["/bin/bash"] + args: + - -c + - | + cd /var/certs + cfssl print-defaults config > /tmp/cfssl-default.json + echo '{"CN": "Pinniped Test","hosts": [],"key": {"algo": "ecdsa","size": 256},"names": [{}]}' > csr.json + + echo "generating CA key..." + cfssl genkey \ + -config /tmp/cfssl-default.json \ + -initca csr.json \ + | cfssljson -bare ca + + echo "generating Dex server certificate..." + cfssl gencert \ + -ca ca.pem -ca-key ca-key.pem \ + -config /tmp/cfssl-default.json \ + -profile www \ + -cn "dex.dex.svc.cluster.local" \ + -hostname "dex.dex.svc.cluster.local" \ + csr.json \ + | cfssljson -bare dex + volumeMounts: + - name: certs + mountPath: /var/certs containers: - - name: dex - image: quay.io/dexidp/dex:v2.10.0 - imagePullPolicy: IfNotPresent - command: - - /usr/local/bin/dex - - serve - - /etc/dex/cfg/config.yaml - ports: - - name: http - containerPort: 80 - volumeMounts: - - name: config - mountPath: /etc/dex/cfg + - name: dex + image: quay.io/dexidp/dex:v2.10.0 + imagePullPolicy: IfNotPresent + command: + - /usr/local/bin/dex + - serve + - /etc/dex/cfg/config.yaml + ports: + - name: https + containerPort: 443 + volumeMounts: + - name: dex-config + mountPath: /etc/dex/cfg + - name: certs + mountPath: /var/certs + readOnly: true volumes: - - name: config + - name: dex-config configMap: name: dex-config + - name: certs + emptyDir: {} --- apiVersion: v1 kind: Service @@ -98,4 +135,5 @@ spec: selector: app: dex ports: - - port: 80 + - port: 443 + name: https diff --git a/test/integration/cli_test.go b/test/integration/cli_test.go index 50980e5e..6a1c2a15 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://dex\.dex\.svc\.cluster\.local/dex.*\z`), - LoginPagePattern: regexp.MustCompile(`\Ahttp://dex\.dex\.svc\.cluster\.local/dex/auth/local.+\z`), + IssuerPattern: regexp.MustCompile(`\Ahttps://dex\.dex\.svc\.cluster\.local/dex.*\z`), + LoginPagePattern: regexp.MustCompile(`\Ahttps://dex\.dex\.svc\.cluster\.local/dex/auth/local.+\z`), UsernameSelector: "input#login", PasswordSelector: "input#password", LoginButtonSelector: "button#submit-login", @@ -170,6 +170,7 @@ func TestCLILoginOIDC(t *testing.T) { agouti.Desired(caps), agouti.ChromeOptions("args", []string{ "--no-sandbox", + "--ignore-certificate-errors", "--headless", // Comment out this line to see the tests happen in a visible browser window. }), // Uncomment this to see stdout/stderr from chromedriver. @@ -413,6 +414,15 @@ func oidcLoginCommand(ctx context.Context, t *testing.T, pinnipedExe string, ses "--session-cache", sessionCachePath, "--skip-browser", ) + + // If there is a custom CA bundle, pass it via --ca-bundle and a temporary file. + if env.OIDCUpstream.CABundle != "" { + path := filepath.Join(t.TempDir(), "test-ca.pem") + require.NoError(t, ioutil.WriteFile(path, []byte(env.OIDCUpstream.CABundle), 0600)) + cmd.Args = append(cmd.Args, "--ca-bundle", path) + } + + // If there is a custom proxy, set it using standard environment variables. if env.Proxy != "" { cmd.Env = append(os.Environ(), "http_proxy="+env.Proxy, diff --git a/test/library/env.go b/test/library/env.go index 14c2ada1..ce7e5f94 100644 --- a/test/library/env.go +++ b/test/library/env.go @@ -48,6 +48,7 @@ type TestEnv struct { OIDCUpstream struct { Issuer string `json:"issuer"` + CABundle string `json:"caBundle" ` ClientID string `json:"clientID"` LocalhostPort int `json:"localhostPort"` Username string `json:"username"` @@ -130,6 +131,7 @@ func loadEnvVars(t *testing.T, result *TestEnv) { result.Proxy = os.Getenv("PINNIPED_TEST_PROXY") result.OIDCUpstream.Issuer = needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER") + result.OIDCUpstream.CABundle = os.Getenv("PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE") result.OIDCUpstream.ClientID = needEnv(t, "PINNIPED_TEST_CLI_OIDC_CLIENT_ID") result.OIDCUpstream.LocalhostPort, _ = strconv.Atoi(needEnv(t, "PINNIPED_TEST_CLI_OIDC_LOCALHOST_PORT")) result.OIDCUpstream.Username = needEnv(t, "PINNIPED_TEST_CLI_OIDC_USERNAME")