diff --git a/api/v1alpha1/oidc_types.go b/api/v1alpha1/oidc_types.go
index 61476ee6b4..d87f2f2037 100644
--- a/api/v1alpha1/oidc_types.go
+++ b/api/v1alpha1/oidc_types.go
@@ -37,6 +37,11 @@ type OIDC struct {
// +optional
CookieNames *OIDCCookieNames `json:"cookieNames,omitempty"`
+ // CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ // If a specific cookie is not configured, it will use the "Strict" SameSite policy by default.
+ // +optional
+ CookieConfig *OIDCCookieConfig `json:"cookieConfig,omitempty"`
+
// The optional domain to set the access and ID token cookies on.
// If not set, the cookies will default to the host of the request, not including the subdomains.
// If set, the cookies will be set on the specified domain and all subdomains.
@@ -187,3 +192,24 @@ type OIDCCookieNames struct {
// +optional
IDToken *string `json:"idToken,omitempty"`
}
+
+type SameSite string
+
+const (
+ // SameSiteLax specifies the "Lax" SameSite policy.
+ SameSiteLax SameSite = "Lax"
+ // SameSiteStrict specifies the "Strict" SameSite policy.
+ SameSiteStrict SameSite = "Strict"
+ // SameSiteNone specifies the "None" SameSite policy. Requires a Secure cookie.
+ SameSiteNone SameSite = "None"
+
+ // SameSiteDisabled specifies the "Disabled" SameSite policy.
+ SameSiteDisabled SameSite = "Disabled"
+)
+
+type OIDCCookieConfig struct {
+ // +optional
+ // +kubebuilder:validation:Enum=Lax;Strict;None;Disabled
+ // +kubebuilder:default=Strict
+ SameSite *string `json:"sameSite,omitempty"`
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 8669528496..e86891239b 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -4469,6 +4469,11 @@ func (in *OIDC) DeepCopyInto(out *OIDC) {
*out = new(OIDCCookieNames)
(*in).DeepCopyInto(*out)
}
+ if in.CookieConfig != nil {
+ in, out := &in.CookieConfig, &out.CookieConfig
+ *out = new(OIDCCookieConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.CookieDomain != nil {
in, out := &in.CookieDomain, &out.CookieDomain
*out = new(string)
@@ -4536,6 +4541,26 @@ func (in *OIDC) DeepCopy() *OIDC {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OIDCCookieConfig) DeepCopyInto(out *OIDCCookieConfig) {
+ *out = *in
+ if in.SameSite != nil {
+ in, out := &in.SameSite, &out.SameSite
+ *out = new(string)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCCookieConfig.
+func (in *OIDCCookieConfig) DeepCopy() *OIDCCookieConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(OIDCCookieConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCCookieNames) DeepCopyInto(out *OIDCCookieNames) {
*out = *in
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
index fdf41f34c3..92691532b9 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
@@ -3612,6 +3612,20 @@ spec:
required:
- name
type: object
+ cookieConfig:
+ description: |-
+ CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ If a specific cookie is not configured, it will use the "Strict" SameSite policy by default.
+ properties:
+ sameSite:
+ default: Strict
+ enum:
+ - Lax
+ - Strict
+ - None
+ - Disabled
+ type: string
+ type: object
cookieDomain:
description: |-
The optional domain to set the access and ID token cookies on.
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
index cd4f50f04d..952d290438 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
@@ -3611,6 +3611,20 @@ spec:
required:
- name
type: object
+ cookieConfig:
+ description: |-
+ CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ If a specific cookie is not configured, it will use the "Strict" SameSite policy by default.
+ properties:
+ sameSite:
+ default: Strict
+ enum:
+ - Lax
+ - Strict
+ - None
+ - Disabled
+ type: string
+ type: object
cookieDomain:
description: |-
The optional domain to set the access and ID token cookies on.
diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go
index b40257d963..6c136941fd 100644
--- a/internal/gatewayapi/securitypolicy.go
+++ b/internal/gatewayapi/securitypolicy.go
@@ -1049,6 +1049,7 @@ func (t *Translator) buildOIDC(
CookieSuffix: suffix,
CookieNameOverrides: policy.Spec.OIDC.CookieNames,
CookieDomain: policy.Spec.OIDC.CookieDomain,
+ CookieConfig: policy.Spec.OIDC.CookieConfig,
HMACSecret: hmacData,
PassThroughAuthHeader: passThroughAuthHeader,
DenyRedirect: oidc.DenyRedirect,
diff --git a/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.in.yaml
new file mode 100644
index 0000000000..8c396b4713
--- /dev/null
+++ b/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.in.yaml
@@ -0,0 +1,75 @@
+secrets:
+- apiVersion: v1
+ kind: Secret
+ metadata:
+ namespace: envoy-gateway
+ name: client1-secret
+ data:
+ client-secret: Y2xpZW50MTpzZWNyZXQK
+- apiVersion: v1
+ kind: Secret
+ metadata:
+ namespace: envoy-gateway-system
+ name: envoy-oidc-hmac
+ data:
+ hmac-secret: qrOYACHXoe7UEDI/raOjNSx+Z9ufXSc/22C3T6X/zPY=
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+ kind: Gateway
+ metadata:
+ namespace: envoy-gateway
+ name: gateway-1
+ spec:
+ gatewayClassName: envoy-gateway-class
+ listeners:
+ - name: http
+ protocol: HTTP
+ port: 80
+ allowedRoutes:
+ namespaces:
+ from: All
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+ kind: HTTPRoute
+ metadata:
+ namespace: default
+ name: httproute-1
+ spec:
+ hostnames:
+ - www.example.com
+ parentRefs:
+ - namespace: envoy-gateway
+ name: gateway-1
+ sectionName: http
+ rules:
+ - matches:
+ - path:
+ value: "/foo"
+ backendRefs:
+ - name: service-1
+ port: 8080
+securityPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+ kind: SecurityPolicy
+ metadata:
+ namespace: envoy-gateway
+ name: policy-for-gateway # This policy should attach httproute-2
+ uid: b8284d0f-de82-4c65-b204-96a0d3f258a1
+ spec:
+ targetRef:
+ group: gateway.networking.k8s.io
+ kind: Gateway
+ name: gateway-1
+ oidc:
+ provider:
+ issuer: "https://accounts.google.com"
+ clientID: "client1.apps.googleusercontent.com"
+ clientSecret:
+ name: "client1-secret"
+ redirectURL: "https://www.example.com/bar/oauth2/callback"
+ logoutPath: "/bar/logout"
+ cookieNames:
+ idToken: "CustomIdTokenCookie"
+ accessToken: "CustomAccessTokenCookie"
+ cookieConfig:
+ sameSite: None
diff --git a/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.out.yaml
new file mode 100644
index 0000000000..2927b1a496
--- /dev/null
+++ b/internal/gatewayapi/testdata/securitypolicy-with-oidc-custom-cookies-samesite.out.yaml
@@ -0,0 +1,217 @@
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+ kind: Gateway
+ metadata:
+ creationTimestamp: null
+ name: gateway-1
+ namespace: envoy-gateway
+ spec:
+ gatewayClassName: envoy-gateway-class
+ listeners:
+ - allowedRoutes:
+ namespaces:
+ from: All
+ name: http
+ port: 80
+ protocol: HTTP
+ status:
+ listeners:
+ - attachedRoutes: 1
+ conditions:
+ - lastTransitionTime: null
+ message: Sending translated listener configuration to the data plane
+ reason: Programmed
+ status: "True"
+ type: Programmed
+ - lastTransitionTime: null
+ message: Listener has been successfully translated
+ reason: Accepted
+ status: "True"
+ type: Accepted
+ - lastTransitionTime: null
+ message: Listener references have been resolved
+ reason: ResolvedRefs
+ status: "True"
+ type: ResolvedRefs
+ name: http
+ supportedKinds:
+ - group: gateway.networking.k8s.io
+ kind: HTTPRoute
+ - group: gateway.networking.k8s.io
+ kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+ kind: HTTPRoute
+ metadata:
+ creationTimestamp: null
+ name: httproute-1
+ namespace: default
+ spec:
+ hostnames:
+ - www.example.com
+ parentRefs:
+ - name: gateway-1
+ namespace: envoy-gateway
+ sectionName: http
+ rules:
+ - backendRefs:
+ - name: service-1
+ port: 8080
+ matches:
+ - path:
+ value: /foo
+ status:
+ parents:
+ - conditions:
+ - lastTransitionTime: null
+ message: Route is accepted
+ reason: Accepted
+ status: "True"
+ type: Accepted
+ - lastTransitionTime: null
+ message: Resolved all the Object references for the Route
+ reason: ResolvedRefs
+ status: "True"
+ type: ResolvedRefs
+ controllerName: gateway.envoyproxy.io/gatewayclass-controller
+ parentRef:
+ name: gateway-1
+ namespace: envoy-gateway
+ sectionName: http
+infraIR:
+ envoy-gateway/gateway-1:
+ proxy:
+ listeners:
+ - address: null
+ name: envoy-gateway/gateway-1/http
+ ports:
+ - containerPort: 10080
+ name: http-80
+ protocol: HTTP
+ servicePort: 80
+ metadata:
+ labels:
+ gateway.envoyproxy.io/owning-gateway-name: gateway-1
+ gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+ ownerReference:
+ kind: GatewayClass
+ name: envoy-gateway-class
+ name: envoy-gateway/gateway-1
+ namespace: envoy-gateway-system
+securityPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+ kind: SecurityPolicy
+ metadata:
+ creationTimestamp: null
+ name: policy-for-gateway
+ namespace: envoy-gateway
+ uid: b8284d0f-de82-4c65-b204-96a0d3f258a1
+ spec:
+ oidc:
+ clientID: client1.apps.googleusercontent.com
+ clientSecret:
+ group: null
+ kind: null
+ name: client1-secret
+ cookieConfig:
+ sameSite: None
+ cookieNames:
+ accessToken: CustomAccessTokenCookie
+ idToken: CustomIdTokenCookie
+ logoutPath: /bar/logout
+ provider:
+ issuer: https://accounts.google.com
+ redirectURL: https://www.example.com/bar/oauth2/callback
+ targetRef:
+ group: gateway.networking.k8s.io
+ kind: Gateway
+ name: gateway-1
+ status:
+ ancestors:
+ - ancestorRef:
+ group: gateway.networking.k8s.io
+ kind: Gateway
+ name: gateway-1
+ namespace: envoy-gateway
+ conditions:
+ - lastTransitionTime: null
+ message: Policy has been accepted.
+ reason: Accepted
+ status: "True"
+ type: Accepted
+ controllerName: gateway.envoyproxy.io/gatewayclass-controller
+xdsIR:
+ envoy-gateway/gateway-1:
+ accessLog:
+ json:
+ - path: /dev/stdout
+ http:
+ - address: 0.0.0.0
+ hostnames:
+ - '*'
+ isHTTP2: false
+ metadata:
+ kind: Gateway
+ name: gateway-1
+ namespace: envoy-gateway
+ sectionName: http
+ name: envoy-gateway/gateway-1/http
+ path:
+ escapedSlashesAction: UnescapeAndRedirect
+ mergeSlashes: true
+ port: 10080
+ routes:
+ - destination:
+ metadata:
+ kind: HTTPRoute
+ name: httproute-1
+ namespace: default
+ name: httproute/default/httproute-1/rule/0
+ settings:
+ - addressType: IP
+ endpoints:
+ - host: 7.7.7.7
+ port: 8080
+ metadata:
+ name: service-1
+ namespace: default
+ sectionName: "8080"
+ name: httproute/default/httproute-1/rule/0/backend/0
+ protocol: HTTP
+ weight: 1
+ hostname: www.example.com
+ isHTTP2: false
+ metadata:
+ kind: HTTPRoute
+ name: httproute-1
+ namespace: default
+ name: httproute/default/httproute-1/rule/0/match/0/www_example_com
+ pathMatch:
+ distinct: false
+ name: ""
+ prefix: /foo
+ security:
+ oidc:
+ clientID: client1.apps.googleusercontent.com
+ clientSecret: '[redacted]'
+ cookieConfig:
+ sameSite: None
+ cookieNameOverrides:
+ accessToken: CustomAccessTokenCookie
+ idToken: CustomIdTokenCookie
+ cookieSuffix: b0a1b740
+ hmacSecret: '[redacted]'
+ logoutPath: /bar/logout
+ name: securitypolicy/envoy-gateway/policy-for-gateway
+ provider:
+ authorizationEndpoint: https://accounts.google.com/o/oauth2/v2/auth
+ tokenEndpoint: https://oauth2.googleapis.com/token
+ redirectPath: /bar/oauth2/callback
+ redirectURL: https://www.example.com/bar/oauth2/callback
+ scopes:
+ - openid
+ readyListener:
+ address: 0.0.0.0
+ ipFamily: IPv4
+ path: /ready
+ port: 19003
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 50b4972c93..bb8c4d8186 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -1128,6 +1128,11 @@ type OIDC struct {
// CookieDomain sets the domain of the cookies set by the oauth filter.
CookieDomain *string `json:"cookieDomain,omitempty"`
+ // CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ // If a specific cookie is not configured, it will use the default xds value of disabled.
+ // +optional
+ CookieConfig *egv1a1.OIDCCookieConfig `json:"cookieConfig,omitempty"`
+
// Skips OIDC authentication when the request contains any header that will be extracted by the JWT
// filter, normally "Authorization: Bearer ...". This is typically used for non-browser clients that
// may not be able to handle OIDC redirects and wish to directly supply a token instead.
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index fb6d3b44d6..7bfbe49461 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -2397,6 +2397,11 @@ func (in *OIDC) DeepCopyInto(out *OIDC) {
*out = new(string)
**out = **in
}
+ if in.CookieConfig != nil {
+ in, out := &in.CookieConfig, &out.CookieConfig
+ *out = new(v1alpha1.OIDCCookieConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.DenyRedirect != nil {
in, out := &in.DenyRedirect, &out.DenyRedirect
*out = new(v1alpha1.OIDCDenyRedirect)
diff --git a/internal/xds/translator/oidc.go b/internal/xds/translator/oidc.go
index 266e8df586..857bfd4df1 100644
--- a/internal/xds/translator/oidc.go
+++ b/internal/xds/translator/oidc.go
@@ -139,6 +139,7 @@ func oauth2Config(securityFeatures *ir.SecurityFeatures) (*oauth2v3.OAuth2, erro
},
AuthorizationEndpoint: oidc.Provider.AuthorizationEndpoint,
RedirectUri: oidc.RedirectURL,
+ CookieConfigs: buildCookieConfigs(oidc),
RedirectPathMatcher: &matcherv3.PathMatcher{
Rule: &matcherv3.PathMatcher_Path{
Path: &matcherv3.StringMatcher{
@@ -235,6 +236,59 @@ func oauth2Config(securityFeatures *ir.SecurityFeatures) (*oauth2v3.OAuth2, erro
return oauth2, nil
}
+func getSameSiteOrDefault(config *egv1a1.OIDCCookieConfig) oauth2v3.CookieConfig_SameSite {
+ if config == nil || config.SameSite == nil {
+ return oauth2v3.CookieConfig_STRICT
+ }
+
+ samesite := egv1a1.SameSite(*config.SameSite)
+
+ switch samesite {
+ case egv1a1.SameSiteStrict:
+ return oauth2v3.CookieConfig_STRICT
+ case egv1a1.SameSiteLax:
+ return oauth2v3.CookieConfig_LAX
+ case egv1a1.SameSiteNone:
+ return oauth2v3.CookieConfig_NONE
+ case egv1a1.SameSiteDisabled:
+ return oauth2v3.CookieConfig_DISABLED
+ default:
+ return oauth2v3.CookieConfig_STRICT
+ }
+}
+
+// buildCookieConfigs translates the OIDC configuration from the US
+func buildCookieConfigs(oidc *ir.OIDC) *oauth2v3.CookieConfigs {
+ cookieConfig := &oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ }
+
+ // If the user did not specify any custom cookie configurations at all, return the defaults.
+ if oidc.CookieConfig == nil {
+ return cookieConfig
+ }
+
+ // Apply the user-defined SameSite policy for each cookie if it has been configured.
+ // The helper function handles the logic of falling back to STRICT if a specific
+ // cookie's configuration is omitted in the CRD.
+ samesite := getSameSiteOrDefault(oidc.CookieConfig)
+ cookieConfig.BearerTokenCookieConfig.SameSite = samesite
+ cookieConfig.OauthHmacCookieConfig.SameSite = samesite
+ cookieConfig.OauthExpiresCookieConfig.SameSite = samesite
+ cookieConfig.IdTokenCookieConfig.SameSite = samesite
+ cookieConfig.RefreshTokenCookieConfig.SameSite = samesite
+ cookieConfig.OauthNonceCookieConfig.SameSite = samesite
+ cookieConfig.CodeVerifierCookieConfig.SameSite = samesite
+
+ return cookieConfig
+}
+
func buildDenyRedirectMatcher(oidc *ir.OIDC) []*routev3.HeaderMatcher {
denyRedirectPathMatchers := make([]*routev3.HeaderMatcher, 0, len(oidc.DenyRedirect.Headers))
diff --git a/internal/xds/translator/oidc_test.go b/internal/xds/translator/oidc_test.go
new file mode 100644
index 0000000000..62c3693292
--- /dev/null
+++ b/internal/xds/translator/oidc_test.go
@@ -0,0 +1,138 @@
+// 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.
+
+package translator
+
+import (
+ "testing"
+
+ oauth2v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/oauth2/v3"
+ "github.com/stretchr/testify/require"
+ "k8s.io/utils/ptr"
+
+ egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+ "github.com/envoyproxy/gateway/internal/ir"
+)
+
+func TestOIDCCookieConfigSameSite(t *testing.T) {
+ tests := []struct {
+ name string
+ input ir.OIDC
+ expect oauth2v3.CookieConfigs
+ }{
+ {
+ name: "defaults all cookie to strict",
+ input: ir.OIDC{},
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ },
+ },
+ {
+ name: "all cookie configs set to None",
+ input: ir.OIDC{
+ CookieConfig: &egv1a1.OIDCCookieConfig{
+ SameSite: ptr.To("None"),
+ },
+ },
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_NONE},
+ },
+ },
+ {
+ name: "all cookie configs set to Lax",
+ input: ir.OIDC{
+ CookieConfig: &egv1a1.OIDCCookieConfig{
+ SameSite: ptr.To("Lax"),
+ },
+ },
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_LAX},
+ },
+ },
+ {
+ name: "all cookie configs set to Strict",
+ input: ir.OIDC{
+ CookieConfig: &egv1a1.OIDCCookieConfig{
+ SameSite: ptr.To("Strict"),
+ },
+ },
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ },
+ },
+ {
+ name: "all cookie configs set to Disabled",
+ input: ir.OIDC{
+ CookieConfig: &egv1a1.OIDCCookieConfig{
+ SameSite: ptr.To("Disabled"),
+ },
+ },
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_DISABLED},
+ },
+ },
+ {
+ name: "cookie config received invalid SameSite value will default to Strict",
+ input: ir.OIDC{
+ CookieConfig: &egv1a1.OIDCCookieConfig{
+ SameSite: ptr.To("InvalidValue"),
+ },
+ },
+ expect: oauth2v3.CookieConfigs{
+ BearerTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthHmacCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthExpiresCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ IdTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ RefreshTokenCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ OauthNonceCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ CodeVerifierCookieConfig: &oauth2v3.CookieConfig{SameSite: oauth2v3.CookieConfig_STRICT},
+ },
+ },
+ }
+
+ for i := range tests {
+ tc := &tests[i]
+ t.Run(tc.name, func(t *testing.T) {
+ actual := buildCookieConfigs(&tc.input)
+ require.Equal(t, tc.expect.BearerTokenCookieConfig.SameSite, actual.BearerTokenCookieConfig.SameSite)
+ require.Equal(t, tc.expect.OauthHmacCookieConfig.SameSite, actual.OauthHmacCookieConfig.SameSite)
+ require.Equal(t, tc.expect.OauthExpiresCookieConfig.SameSite, actual.OauthExpiresCookieConfig.SameSite)
+ require.Equal(t, tc.expect.IdTokenCookieConfig.SameSite, actual.IdTokenCookieConfig.SameSite)
+ require.Equal(t, tc.expect.RefreshTokenCookieConfig.SameSite, actual.RefreshTokenCookieConfig.SameSite)
+ require.Equal(t, tc.expect.OauthNonceCookieConfig.SameSite, actual.OauthNonceCookieConfig.SameSite)
+ require.Equal(t, tc.expect.CodeVerifierCookieConfig.SameSite, actual.CodeVerifierCookieConfig.SameSite)
+ })
+ }
+}
diff --git a/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port-with-different-filters.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port-with-different-filters.listeners.yaml
index 5c6552fd10..bbaf7a47c4 100755
--- a/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port-with-different-filters.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/multiple-listeners-same-port-with-different-filters.listeners.yaml
@@ -115,6 +115,21 @@
- profile
authType: BASIC_AUTH
authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: client.oauth.foo.com
cookieNames:
diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-and-jwt-with-passthrough.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-and-jwt-with-passthrough.listeners.yaml
index 8996b15c63..016e048f00 100644
--- a/internal/xds/translator/testdata/out/xds-ir/oidc-and-jwt-with-passthrough.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/oidc-and-jwt-with-passthrough.listeners.yaml
@@ -23,6 +23,21 @@
- openid
authType: BASIC_AUTH
authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: client.oauth.foo.com
cookieNames:
diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml
index ab9e55eadf..945a1c4dd6 100644
--- a/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.listeners.yaml
@@ -23,6 +23,21 @@
- openid
authType: BASIC_AUTH
authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: client1.apps.googleusercontent.com
cookieNames:
diff --git a/internal/xds/translator/testdata/out/xds-ir/oidc.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/oidc.listeners.yaml
index 3a94b3a8bd..22bb54807b 100644
--- a/internal/xds/translator/testdata/out/xds-ir/oidc.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/oidc.listeners.yaml
@@ -25,6 +25,21 @@
- profile
authType: BASIC_AUTH
authorizationEndpoint: https://oauth.foo.com/oauth2/v2/auth
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: client.oauth.foo.com
cookieNames:
@@ -72,6 +87,21 @@
- profile
authType: BASIC_AUTH
authorizationEndpoint: https://oauth.bar.com/oauth2/v2/auth
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: client.oauth.bar.com
cookieDomain: example.com
diff --git a/internal/xds/translator/testdata/out/xds-ir/securitypolicy-with-oidc-jwt-authz.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/securitypolicy-with-oidc-jwt-authz.listeners.yaml
index eb5f36cb40..1bdf68e4f0 100644
--- a/internal/xds/translator/testdata/out/xds-ir/securitypolicy-with-oidc-jwt-authz.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/securitypolicy-with-oidc-jwt-authz.listeners.yaml
@@ -25,6 +25,21 @@
- profile
authType: BASIC_AUTH
authorizationEndpoint: https://oidc.example.com/authorize
+ cookieConfigs:
+ bearerTokenCookieConfig:
+ sameSite: STRICT
+ codeVerifierCookieConfig:
+ sameSite: STRICT
+ idTokenCookieConfig:
+ sameSite: STRICT
+ oauthExpiresCookieConfig:
+ sameSite: STRICT
+ oauthHmacCookieConfig:
+ sameSite: STRICT
+ oauthNonceCookieConfig:
+ sameSite: STRICT
+ refreshTokenCookieConfig:
+ sameSite: STRICT
credentials:
clientId: prometheus
cookieNames:
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index 431d6df99c..b6ad0827d2 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -3,6 +3,7 @@ date: Pending
# Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs.
breaking changes: |
Use gateway name as proxy fleet name for gateway namespace mode.
+ SameSite attribute for Oauth cookies defaults to `Strict`, make sure to set `CookieConfig.SameSite` to `Disabled` if you want to keep the previous behavior.
# Updates addressing vulnerabilities, security flaws, or compliance requirements.
security updates: |
@@ -21,9 +22,11 @@ new features: |
Added support for setting previous priorities retry predicate.
Added support for using extension server policies to in PostTranslateModify hook.
Added support for configuring cluster stat name for HTTPRoute and GRPCRoute in EnvoyProxy CRD.
+ Added support for configuring `SameSite` attribute for Oauth cookies for OIDC authentication.
Added support for configuring the cache sync period for K8s provider.
Added support for configuring user provided name to generated HorizontalPodAutoscaler and PodDisruptionBudget resources.
+
bug fixes: |
Handle integer zone annotation values
Fixed issue where WASM cache init failure caused routes with WASM-less EnvoyExtensionPolicies to have 500 direct responses.
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index ed9fbc2f58..97829cfab4 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -3180,6 +3180,7 @@ _Appears in:_
| `clientID` | _string_ | true | | The client ID to be used in the OIDC
[Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). |
| `clientSecret` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.SecretObjectReference)_ | true | | The Kubernetes secret which contains the OIDC client secret to be used in the
[Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
This is an Opaque secret. The client secret should be stored in the key
"client-secret". |
| `cookieNames` | _[OIDCCookieNames](#oidccookienames)_ | false | | The optional cookie name overrides to be used for Bearer and IdToken cookies in the
[Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
If not specified, uses a randomly generated suffix |
+| `cookieConfig` | _[OIDCCookieConfig](#oidccookieconfig)_ | false | | CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
If a specific cookie is not configured, it will use the "Strict" SameSite policy by default. |
| `cookieDomain` | _string_ | false | | The optional domain to set the access and ID token cookies on.
If not set, the cookies will default to the host of the request, not including the subdomains.
If set, the cookies will be set on the specified domain and all subdomains.
This means that requests to any subdomain will not require reauthentication after users log in to the parent domain. |
| `scopes` | _string array_ | false | | The OIDC scopes to be used in the
[Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
The "openid" scope is always added to the list of scopes if not already
specified. |
| `resources` | _string array_ | false | | The OIDC resources to be used in the
[Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). |
@@ -3193,6 +3194,20 @@ _Appears in:_
| `passThroughAuthHeader` | _boolean_ | false | | Skips OIDC authentication when the request contains a header that will be extracted by the JWT filter. Unless
explicitly stated otherwise in the extractFrom field, this will be the "Authorization: Bearer ..." header.
The passThroughAuthHeader option is typically used for non-browser clients that may not be able to handle OIDC
redirects and wish to directly supply a token instead.
If not specified, defaults to false. |
+#### OIDCCookieConfig
+
+
+
+
+
+_Appears in:_
+- [OIDC](#oidc)
+
+| Field | Type | Required | Default | Description |
+| --- | --- | --- | --- | --- |
+| `sameSite` | _string_ | false | Strict | |
+
+
#### OIDCCookieNames
@@ -4285,6 +4300,8 @@ _Appears in:_
| `Endpoint` | EndpointRoutingType is the RoutingType for Endpoint routing.
|
+
+
#### SecurityPolicy
diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml
index 423d51f43a..80666cf0ca 100644
--- a/test/helm/gateway-crds-helm/all.out.yaml
+++ b/test/helm/gateway-crds-helm/all.out.yaml
@@ -42266,6 +42266,20 @@ spec:
required:
- name
type: object
+ cookieConfig:
+ description: |-
+ CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ If a specific cookie is not configured, it will use the "Strict" SameSite policy by default.
+ properties:
+ sameSite:
+ default: Strict
+ enum:
+ - Lax
+ - Strict
+ - None
+ - Disabled
+ type: string
+ type: object
cookieDomain:
description: |-
The optional domain to set the access and ID token cookies on.
diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
index d24bf7a201..fa488365ef 100644
--- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
+++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
@@ -24954,6 +24954,20 @@ spec:
required:
- name
type: object
+ cookieConfig:
+ description: |-
+ CookieConfigs allows overriding the SameSite attribute for OIDC cookies.
+ If a specific cookie is not configured, it will use the "Strict" SameSite policy by default.
+ properties:
+ sameSite:
+ default: Strict
+ enum:
+ - Lax
+ - Strict
+ - None
+ - Disabled
+ type: string
+ type: object
cookieDomain:
description: |-
The optional domain to set the access and ID token cookies on.