From 0f7096f6b48ac0c640ebc8adc8550999db010683 Mon Sep 17 00:00:00 2001 From: Huabing Zhao Date: Tue, 7 Jan 2025 07:58:23 +0000 Subject: [PATCH] e2e test Signed-off-by: Huabing Zhao --- .../e2e/testdata/jwt-backend-remote-jwks.yaml | 194 ++++++++++++++++++ test/e2e/tests/jwt-backend-remote-jwks.go | 29 +++ test/e2e/tests/jwt.go | 128 ++++++------ 3 files changed, 289 insertions(+), 62 deletions(-) create mode 100644 test/e2e/testdata/jwt-backend-remote-jwks.yaml create mode 100644 test/e2e/tests/jwt-backend-remote-jwks.go diff --git a/test/e2e/testdata/jwt-backend-remote-jwks.yaml b/test/e2e/testdata/jwt-backend-remote-jwks.yaml new file mode 100644 index 00000000000..65cb54e8339 --- /dev/null +++ b/test/e2e/testdata/jwt-backend-remote-jwks.yaml @@ -0,0 +1,194 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: remote-jwks-server-secret + namespace: gateway-conformance-infra +type: kubernetes.io/tls +data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURmekNDQW1lZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREJETVNBd0hnWURWUVFLREJkeVpXMXYKZEdVdGFuZHJjeTF6WlhKMlpYSWdTVzVqTGpFZk1CMEdBMVVFQXd3V2NtVnRiM1JsTFdwM2EzTXRjMlZ5ZG1WeQpMbU52YlRBZUZ3MHlOVEF4TURjd056UXhNamxhRncwek5UQXhNRFV3TnpReE1qbGFNRHd4R3pBWkJnTlZCQU1NCkVuSmxiVzkwWlMxcWQydHpMWE5sY25abGNqRWRNQnNHQTFVRUNnd1VaWGhoYlhCc1pTQnZjbWRoYm1sNllYUnAKYjI0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUM5STk4bjZwMmZNYTZwRkRPTgpneDFzNkMvUmI2SU1leGZBQTR5T1VkL0EvaU1mN0haRGMzR3Q4T29oYmhQY0F5MmF0QS9mbEJ2Z1RNdHNJZ2JMCjVGUXFvQ1U1bW92OStMYW41dGp4bCttUnY4RzVqSFltWklYS29yMTg2Ly8yOFdXWVp4Rm53ZGlRMlR3SGIzSzYKaUROOWllVysrck5LOUVWVW54R2dRdENGaHVHYXNHZkE2QkxuTHBERjg3bzdSZ2ViSlo0TFpud0FzSjdyM25WMwpQa0dXMWQxcDBGNjZ0UW4xMzF3UGVhcEdJbnpaQnhhT0tZTGt6cjJIdmNnUjNvVk9SdktMcWpwK2U2MGFxd0ovCll6TFNyMkJsZlVaVEZZS2t2Qmpuc3BseFAxbWtDc2pIRndSdHdSK1llbkN0a29sb3NkbHlVdUNoMEhJZXBCQUIKWmp4WkFnTUJBQUdqZ1lRd2dZRXdDd1lEVlIwUEJBUURBZ1dnTUJNR0ExVWRKUVFNTUFvR0NDc0dBUVVGQndNQgpNQjBHQTFVZEVRUVdNQlNDRW5KbGJXOTBaUzFxZDJ0ekxYTmxjblpsY2pBZEJnTlZIUTRFRmdRVUo4M3dTdmI4Ci84c0lNZ29FSllBMWNKV1pQYWN3SHdZRFZSMGpCQmd3Rm9BVVpuUzFqWWdSVnI1WHMrZHF0TWV4RzRBNmtWa3cKRFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUt4VXJ6OUh6R0cyT3M5UkFtaXNNTUU4di95MEhocVNCSUo5U3Y3OQo3WGF1R01nYVg0NWVMNlN2MHRsa21hcW05UHQ5NmppQis5ZkR4S1NHV2xLMk03aUl5aVFyWDVsaGt4czZ1U3NJCkMyRjlUcmVFUjNCSk5uaGFDaVhXdTRQL2MvdzA4WEpmWU51WEJMVFpSc3RkNTFxMHJzMnR5cU1QQ3EyZXBvSWsKZ3duRUxVZkM3SGpoSVB1M1BoeXdxYngzY0F3MUJ5aVdnTUtkR3FFMUw2NkhmdDRlTFdNQzBnUURPUWZnQmZjRQpWbUlnVVNXYWFIbU5VUDdzQk03S1NTTnRJOFVvNjF6SVl4R2dwVnRPOXc0YjBneVV5MTJQRXgreW1RN0FiTWRHCmFMNUJZUDhGY1dRMjlsd1Vua2RXR1VoNnFNNmd1cXJ6WFBiTXpKL3hnaERtMlVJPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzlJOThuNnAyZk1hNnAKRkRPTmd4MXM2Qy9SYjZJTWV4ZkFBNHlPVWQvQS9pTWY3SFpEYzNHdDhPb2hiaFBjQXkyYXRBL2ZsQnZnVE10cwpJZ2JMNUZRcW9DVTVtb3Y5K0xhbjV0anhsK21SdjhHNWpIWW1aSVhLb3IxODYvLzI4V1dZWnhGbndkaVEyVHdICmIzSzZpRE45aWVXKytyTks5RVZVbnhHZ1F0Q0ZodUdhc0dmQTZCTG5McERGODdvN1JnZWJKWjRMWm53QXNKN3IKM25WM1BrR1cxZDFwMEY2NnRRbjEzMXdQZWFwR0luelpCeGFPS1lMa3pyMkh2Y2dSM29WT1J2S0xxanArZTYwYQpxd0ovWXpMU3IyQmxmVVpURllLa3ZCam5zcGx4UDFta0NzakhGd1J0d1IrWWVuQ3Rrb2xvc2RseVV1Q2gwSEllCnBCQUJaanhaQWdNQkFBRUNnZ0VBRmdMZUVpQkR5RzVnMmhDdHFMVDI2RkVUbW9za0o5RnQ2OFRGOTF5WUhuYTgKNmZiTDh4RFU3SllXT3o1N0hXNDV3UkNlTGNubjNoZzF6cjlkZk40MVBOSXZEdGQ1WGZ5ekxoSkhra01ZZGFPawpKUWF2aTh1RVJmY2ZOL0hqazQ2WGdROVNsMWwzN1hCNGc5R0FuNnhnMktYakNMRVdpejBtOGVDQ3JiekUxVnNRCkc1NzhGbmtQYmZBZ1Q3a2dWRjFzekRzS2p6Si9yREtkTVg0dXpvY2NlTzJoTUJrU0hYMU1BbmFsUkxBampGTFkKcGJkN2ZZK0xlR2Z5ZXQ3ZDZGMDdaUDNBUzFRVkVGczVHRVYwSHFHS3paS2JkSHF6dG1XeW9xd3ZvQmJVd2lVLwo5elRtQktQcFNoZW9SakJudVhJTFBILzE1cTFodHNSak4wczRTc0dxUVFLQmdRRHRGanNZSUNENXgrY1BDYm1pCmpQK2U3YVZJRkw3K3hsWDdReUZxSWc3eXVzRlYyUGtyOXhXT2pjS0owcVlmU2UxaWlIaU4wQUJJcUFjMDRmUm0KbXUvMmhtRU85RVdJaUhTQk44VXkzRmh3Zk1tUnpWRWZEemljT2NJZ1gxRWFudlZmMnlOMWtxblc2VWRtcDlJYgpKejQ5RzliM2s3NDdhS3NxTWZMR2Z1dmhHUUtCZ1FETU9ub0xrQkxyOWJnYU1lU1hTZXdoQkw1VmkxZmxxUk83ClNqU1FzYTU0azN1aWZZTEM0MlZMMkJDdDlYZ2JVWE5hNzBBTC9KcXovRUxKTm5uWGt1bVUwK2F6cVU0QUJoOFcKcUFTWk9GdGowTHptL1V6VHdVUkVwemxpQkFacnBNdDU1S3EzQmV4L2xMS2pJYi9lNENtZkxSdW1lWTlYYlFyNwpvZWtrT0J4ZFFRS0JnQW5PckowZjN4MVdCcG5acGlNeVAvUzhFZVU4Ym5ZdGtDcjNxTzh4LzNwTS9XaG10RS84ClJaa0RCalFiVWFIanRmMG9kZ3d2dVlOSDZCeG82R3BDS0lFREtBcXRVaDhHdmdNR1lwTHJDSUdHdC9QZkVXYisKZ3pIN05hdVBKZFM3RkoxbGZEOEYxUjY5d2FWZWRkT0h1UXhnRlhGaVhERXE4RUdybFVaZXc3VXBBb0dBRE4waQpFdGhnV0x5QmZDVG9ZUjhtNEcyTUQ1ZFhVZi8wWGpldVYrN1pMbjhicW9COVhBazJ1REJEM0xFNWYzOEI1UmhzCjBGUjQ2aDFabDVMMjJiMUhPVGlmcjNGYW1HWEtUNE1GeHlEbG9NUGxJaWVTVDBROUtKWGY1MnlaZXU1R1lzY2sKZWFMRjRzTmEvU3VEQ21iVU9GSi9DMTFjeWdUMFRDVkdxaUZlcUFFQ2dZRUFsckUxVFVCeDRDbGQvNU9SemVkOApnK1g3S2RORXhtOCtjTkdDM3g0bUpzOWpybXFXN01wKzlab1RSR2ROemdBY1luRjMvZkZVV1ZkbEo1bkczVzZVCk44blJvVWtneSs2a1lzTExUT2NXOGxHMHlyRXZ0WVA5Ujk0aStqaCtzd3NPUEUvb0FsMG9EbklldE1WUmpQaXYKWEVJRWNrSUdMbHhQTmtwZmNBMEp2UU09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: remote-jwks-server-ca + namespace: gateway-conformance-infra +data: + ca.crt: | + -----BEGIN CERTIFICATE----- + MIIDZzCCAk+gAwIBAgIUdKqpVkYMQWraGhwBrL26NPO2ocYwDQYJKoZIhvcNAQEL + BQAwQzEgMB4GA1UECgwXcmVtb3RlLWp3a3Mtc2VydmVyIEluYy4xHzAdBgNVBAMM + FnJlbW90ZS1qd2tzLXNlcnZlci5jb20wHhcNMjUwMTA3MDc0MTI5WhcNMzUwMTA1 + MDc0MTI5WjBDMSAwHgYDVQQKDBdyZW1vdGUtandrcy1zZXJ2ZXIgSW5jLjEfMB0G + A1UEAwwWcmVtb3RlLWp3a3Mtc2VydmVyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD + ggEPADCCAQoCggEBAMA7NXKfnnEthULdenoA+AJzSRuPZaiHyrwGqVGm8gEKJ02U + 8IIj5ztcurooBtuDZQvuKRjMFOFPGuG3UGdzR+rRQ7Wenp9qy0E7C0q6WXxS9B/W + mGJ/JcttZO0JvNTWm1fByKrvM4OmokFkEKQX7pnwQyRV2gkckOuAwyWUsD1eHp/b + /ke4uZB0M9M1Ll+TBw8l1qG7GclcjOE41kW2Y1S6h5umGBn/g2SqN47sWj4G0ork + No4JICik4FXO3h1UBnnEgbsgHplnyT3i9OZydfgToOEXjW+w8EE8JwRVNpIiYLTE + lwrq7FhrhvnVZ+hQ9u0Pu+8p9CmdA91dKuqGq8kCAwEAAaNTMFEwHQYDVR0OBBYE + FGZ0tY2IEVa+V7PnarTHsRuAOpFZMB8GA1UdIwQYMBaAFGZ0tY2IEVa+V7PnarTH + sRuAOpFZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAB3aGMrx + 7aAmUEuEcYibbUbMYKXis94hh2rOqREZDTWsH91JAdqfDpoIkjjgpTusK67Jgr7z + YV1v2f5qFMSoRHd7aKJr5zsBpl616kdya4a3hv7iqBypldXekNo8zteJHjC9ryyZ + znDcuxPKGkib2Nitck/rWhq+T1ncKTz2QU1oI/EqUwPe4IBThdMnHIPxa4EvABv0 + d1EPZUtZdOr8/fet4Z4KF9zIHrJiBwApw6AFs6x84XyRKCQwpwMZdxDNWa/tZ7A3 + x82ma7q4/PV/IuP+wOJx1B1JNO1vqlM/STbQf0JFw1/C7KHLDQjZGMV53Fcrj4J8 + POACnSGEb+8C9Sw= + -----END CERTIFICATE----- +--- +apiVersion: v1 +kind: Service +metadata: + name: remote-jwks-server + namespace: gateway-conformance-infra +spec: + selector: + app: remote-jwks-server + ports: + - protocol: TCP + port: 443 + targetPort: 8443 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: remote-jwks-server + namespace: gateway-conformance-infra + labels: + app: remote-jwks-server +spec: + replicas: 1 + selector: + matchLabels: + app: remote-jwks-server + template: + metadata: + labels: + app: remote-jwks-server + spec: + containers: + - name: remote-jwks-server + image: envoyproxy/gateway-static-file-server + imagePullPolicy: IfNotPresent + args: + - --port=8443 + - --certPath=/etc/certs + volumeMounts: + - name: remote-jwks-server-secret + mountPath: /etc/certs + volumes: + - name: remote-jwks-server-secret + secret: + secretName: remote-jwks-server-secret + items: + - key: tls.crt + path: server.crt + - key: tls.key + path: server.key +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: remote-jwks + namespace: gateway-conformance-infra +spec: + endpoints: + - fqdn: + hostname: 'remote-jwks-server' + port: 443 +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: remote-jwks-btls + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Backend + name: remote-jwks + sectionName: 443 + validation: + caCertificateRefs: + - name: remote-jwks-server-ca + group: '' + kind: ConfigMap + hostname: remote-jwks-server +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: jwt-example + namespace: gateway-conformance-infra +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: jwt-claim-routing + jwt: + providers: + - name: example + recomputeRoute: true + claimToHeaders: + - claim: sub + header: x-sub + - claim: admin + header: x-admin + - claim: name + header: x-name + remoteJWKS: + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: remote-jwks + port: 443 + backendSettings: + retry: + numRetries: 3 + perRetry: + backOff: + baseInterval: 1s + maxInterval: 5s + retryOn: + triggers: ["5xx", "gateway-error", "reset"] + uri: https://remote-jwks-server/jwt/jwks.json +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: jwt-claim-routing + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - backendRefs: + - kind: Service + name: infra-backend-v1 + port: 8080 + weight: 1 + matches: + - headers: + - name: x-name + value: John Doe + - backendRefs: + - kind: Service + name: infra-backend-v2 + port: 8080 + weight: 1 + matches: + - headers: + - name: x-name + value: Tom + # catch all + - backendRefs: + - kind: Service + name: infra-backend-invalid + port: 8080 + weight: 1 + matches: + - path: + type: PathPrefix + value: / diff --git a/test/e2e/tests/jwt-backend-remote-jwks.go b/test/e2e/tests/jwt-backend-remote-jwks.go new file mode 100644 index 00000000000..601ae78ccc0 --- /dev/null +++ b/test/e2e/tests/jwt-backend-remote-jwks.go @@ -0,0 +1,29 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +//go:build e2e + +package tests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/suite" +) + +func init() { + ConformanceTests = append(ConformanceTests, JWTBackendRemoteJWKSTest) +} + +var JWTBackendRemoteJWKSTest = suite.ConformanceTest{ + ShortName: "JWTBackendRemoteJWKS", + Description: "JWT with Backend as remote JWKS", + Manifests: []string{"testdata/jwt-backend-remote-jwks.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("jwt claim base routing", func(t *testing.T) { + testClaimBasedRouting(t, suite) + }) + }, +} diff --git a/test/e2e/tests/jwt.go b/test/e2e/tests/jwt.go index 2ab756fcf3c..38af783d1ff 100644 --- a/test/e2e/tests/jwt.go +++ b/test/e2e/tests/jwt.go @@ -39,75 +39,79 @@ var JWTTest = suite.ConformanceTest{ Manifests: []string{"testdata/jwt.yaml"}, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { t.Run("jwt claim base routing", func(t *testing.T) { - ns := "gateway-conformance-infra" - routeNN := types.NamespacedName{Name: "jwt-claim-routing", Namespace: ns} - gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} - gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + testClaimBasedRouting(t, suite) + }) + }, +} - testCases := []http.ExpectedResponse{ - { - Request: http.Request{ - Path: "/get", - Headers: map[string]string{ - "Authorization": "Bearer " + v1Token, - }, - }, - Backend: "infra-backend-v1", - Response: http.Response{ - StatusCode: 200, - }, - Namespace: ns, +func testClaimBasedRouting(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "jwt-claim-routing", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Path: "/get", + Headers: map[string]string{ + "Authorization": "Bearer " + v1Token, }, - { - Request: http.Request{ - Path: "/get", - Headers: map[string]string{ - "Authorization": "Bearer " + v2Token, - }, - }, - Backend: "infra-backend-v2", - Response: http.Response{ - StatusCode: 200, - }, - Namespace: ns, + }, + Backend: "infra-backend-v1", + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/get", + Headers: map[string]string{ + "Authorization": "Bearer " + v2Token, }, - { - Request: http.Request{ - Path: "/get", - Headers: map[string]string{ - "Authorization": "Bearer " + anotherToken, - }, - }, - Backend: "infra-backend-v1", - Response: http.Response{ - StatusCode: 500, - }, - Namespace: ns, + }, + Backend: "infra-backend-v2", + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/get", + Headers: map[string]string{ + "Authorization": "Bearer " + anotherToken, }, - { - Request: http.Request{ - Path: "/get", - Headers: map[string]string{ - "x-name": "Tom", - }, - }, - Backend: "infra-backend-v2", - Response: http.Response{ - StatusCode: 401, - }, - Namespace: ns, + }, + Backend: "infra-backend-v1", + Response: http.Response{ + StatusCode: 500, + }, + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/get", + Headers: map[string]string{ + "x-name": "Tom", }, - } + }, + Backend: "infra-backend-v2", + Response: http.Response{ + StatusCode: 401, + }, + Namespace: ns, + }, + } - for i := range testCases { - tc := testCases[i] - t.Run(tc.GetTestCaseName(i), func(t *testing.T) { - t.Parallel() - http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) - }) - } + for i := range testCases { + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) }) - }, + } } var OptionalJWTTest = suite.ConformanceTest{