diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index f03e46590db..67260cb13ec 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -589,7 +589,18 @@ func (t *Translator) buildOIDC( } // Generate a unique cookie suffix for oauth filters - suffix := utils.Digest32(string(policy.UID)) + // We use the digest of the redirect URL to generate the cookie suffix so that + // multiple OIDC configurations with the same redirect URL will have the same + // cookie suffix. This allows us to share the same cookies across multiple + // oauth filters at multiple routes. Once users log in at one route, they will + // be able to access other routes with the same OIDC redirect URL (the same + // OIDC clientID) without logging in again. + // + // zhaohuabing: This is a workaround to allow multiple routes to share the same OIDC configuration. + // We should change this back to use policy UID after Gateway API supports + // targeting a policy to multiple routes. + // See https://github.com/kubernetes-sigs/gateway-api/discussions/2927#discussioncomment-8991869 + suffix := utils.Digest32(*oidc.RedirectURL) // Get the HMAC secret // HMAC secret is generated by the CertGen job and stored in a secret diff --git a/internal/gatewayapi/testdata/securitypolicy-with-oidc.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-oidc.out.yaml index 2015f492d63..04a16d8d076 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-oidc.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-oidc.out.yaml @@ -261,7 +261,7 @@ xdsIR: oidc: clientID: client2.oauth.foo.com clientSecret: Y2xpZW50MTpzZWNyZXQK - cookieSuffix: 5f93c2e4 + cookieSuffix: 7f4620b9 hmacSecret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= logoutPath: /foo/logout name: securitypolicy/default/policy-for-http-route @@ -299,7 +299,7 @@ xdsIR: oidc: clientID: client1.apps.googleusercontent.com clientSecret: Y2xpZW50MTpzZWNyZXQK - cookieSuffix: b0a1b740 + cookieSuffix: d3d6eea4 hmacSecret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY= logoutPath: /bar/logout name: securitypolicy/envoy-gateway/policy-for-gateway diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index 968b4d4a505..323d2593d6e 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -169,7 +169,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, fmt.Sprintf("--service-cluster %s", infra.Name), fmt.Sprintf("--service-node $(%s)", envoyPodEnvVar), fmt.Sprintf("--config-yaml %s", bootstrapConfigurations), - fmt.Sprintf("--log-level %s", "debug"), + fmt.Sprintf("--log-level %s", logging.DefaultEnvoyProxyLoggingLevel()), "--cpuset-threads", } diff --git a/test/e2e/testdata/oidc-securitypolicy.yaml b/test/e2e/testdata/oidc-securitypolicy.yaml index 0350979aa18..f72442655cf 100644 --- a/test/e2e/testdata/oidc-securitypolicy.yaml +++ b/test/e2e/testdata/oidc-securitypolicy.yaml @@ -2,7 +2,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: - name: http-with-oidc + name: http-with-oidc-myapp namespace: gateway-conformance-infra spec: parentRefs: @@ -19,6 +19,24 @@ spec: --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute +metadata: + name: http-with-oidc-foo + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + hostnames: ["www.example.com"] + rules: + - matches: + - path: + type: PathPrefix + value: /foo # This is the path that will be protected by OIDC + backendRefs: + - name: infra-backend-v1 + port: 8080 +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute metadata: name: http-without-oidc namespace: gateway-conformance-infra @@ -60,13 +78,34 @@ data: apiVersion: gateway.envoyproxy.io/v1alpha1 kind: SecurityPolicy metadata: - name: oidc-test + name: oidc-test-myapp + namespace: gateway-conformance-infra +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: http-with-oidc-myapp + oidc: + provider: + issuer: "http://keycloak.gateway-conformance-infra/realms/master" + authorizationEndpoint: "http://keycloak.gateway-conformance-infra/realms/master/protocol/openid-connect/auth" + tokenEndpoint: "http://keycloak.gateway-conformance-infra/realms/master/protocol/openid-connect/token" + clientID: "oidctest" + clientSecret: + name: "oidctest-secret" + redirectURL: "http://www.example.com/myapp/oauth2/callback" + logoutPath: "/myapp/logout" +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: oidc-test-foo namespace: gateway-conformance-infra spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute - name: http-with-oidc + name: http-with-oidc-foo oidc: provider: issuer: "http://keycloak.gateway-conformance-infra/realms/master" diff --git a/test/e2e/tests/oidc.go b/test/e2e/tests/oidc.go index ec162294d9c..22d01aca0ce 100644 --- a/test/e2e/tests/oidc.go +++ b/test/e2e/tests/oidc.go @@ -47,7 +47,7 @@ var OIDCTest = suite.ConformanceTest{ Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { t.Run("http route with oidc authentication", func(t *testing.T) { ns := "gateway-conformance-infra" - routeNN := types.NamespacedName{Name: "http-with-oidc", Namespace: ns} + routeNN := types.NamespacedName{Name: "http-with-oidc-myapp", Namespace: ns} gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) @@ -57,7 +57,8 @@ var OIDCTest = suite.ConformanceTest{ Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), Name: gwv1.ObjectName(gwNN.Name), } - SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "oidc-test", Namespace: ns}, suite.ControllerName, ancestorRef) + SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "oidc-test-myapp", Namespace: ns}, suite.ControllerName, ancestorRef) + SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "oidc-test-foo", Namespace: ns}, suite.ControllerName, ancestorRef) podInitialized := corev1.PodCondition{Type: corev1.PodInitialized, Status: corev1.ConditionTrue} @@ -101,6 +102,13 @@ var OIDCTest = suite.ConformanceTest{ require.Equal(t, http.StatusOK, res.StatusCode) require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") + // Myapp and bar are using the same OIDC configuration, so the client + // should be able to access bar without logging in again + res, err = client.Get("http://www.example.com/foo", false) + require.NoError(t, err) + require.Equal(t, http.StatusOK, res.StatusCode) + require.Contains(t, string(body), "infra-backend-v1", "Expected response from the application") + // Verify that we can logout // Note: OAuth2 filter just clears its cookies and does not log out from the IdP. res, err = client.Get(logoutURL, false)