diff --git a/api/v1alpha1/cors_types.go b/api/v1alpha1/cors_types.go index c70e18886bd..328a4fe186b 100644 --- a/api/v1alpha1/cors_types.go +++ b/api/v1alpha1/cors_types.go @@ -5,10 +5,8 @@ package v1alpha1 -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" -) +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + // Origin is defined by the scheme (protocol), hostname (domain), and port of // the URL used to access it. The hostname can be "precise" which is just the @@ -32,26 +30,34 @@ type Origin string // CORS defines the configuration for Cross-Origin Resource Sharing (CORS). type CORS struct { // AllowOrigins defines the origins that are allowed to make requests. + // It specifies the allowed origins in the Access-Control-Allow-Origin header. + // The value "*" allows any origin to make requests. // // +optional AllowOrigins []Origin `json:"allowOrigins,omitempty"` // AllowMethods defines the methods that are allowed to make requests. + // It specifies the allowed methods in the Access-Control-Allow-Methods header. + // The value "*" allows any method to be used. // // +optional - AllowMethods []gwapiv1.HTTPMethod `json:"allowMethods,omitempty"` + AllowMethods []string `json:"allowMethods,omitempty"` // AllowHeaders defines the headers that are allowed to be sent with requests. + // It specifies the allowed headers in the Access-Control-Allow-Headers header. + // The value "*" allows any header to be sent. // // +optional - AllowHeaders []gwapiv1.HTTPHeaderName `json:"allowHeaders,omitempty"` + AllowHeaders []string `json:"allowHeaders,omitempty"` // ExposeHeaders defines the headers that can be exposed in the responses. + // It specifies the headers in the Access-Control-Expose-Headers header. // // +optional - ExposeHeaders []gwapiv1.HTTPHeaderName `json:"exposeHeaders,omitempty"` + ExposeHeaders []string `json:"exposeHeaders,omitempty"` // MaxAge defines how long the results of a preflight request can be cached. + // It specifies the value in the Access-Control-Max-Age header. // // +optional MaxAge *metav1.Duration `json:"maxAge,omitempty"` @@ -61,4 +67,10 @@ type CORS struct { // // +optional AllowCredentials *bool `json:"allowCredentials,omitempty"` + + //TODO zhaohuabing + // According to the CORS specification, the following rules should be enforced: + // - ExposeHeaders should also allow "*" to expose all headers. + // - If AllowCredentials is true, then the "*" shold be treated as a literal. + // Blocked by this Envoy issue: https://github.com/envoyproxy/envoy/issues/36066 } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 12542e7aff7..cde4e3b90d7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -599,17 +599,17 @@ func (in *CORS) DeepCopyInto(out *CORS) { } if in.AllowMethods != nil { in, out := &in.AllowMethods, &out.AllowMethods - *out = make([]apisv1.HTTPMethod, len(*in)) + *out = make([]string, len(*in)) copy(*out, *in) } if in.AllowHeaders != nil { in, out := &in.AllowHeaders, &out.AllowHeaders - *out = make([]apisv1.HTTPHeaderName, len(*in)) + *out = make([]string, len(*in)) copy(*out, *in) } if in.ExposeHeaders != nil { in, out := &in.ExposeHeaders, &out.ExposeHeaders - *out = make([]apisv1.HTTPHeaderName, len(*in)) + *out = make([]string, len(*in)) copy(*out, *in) } if in.MaxAge != nil { 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 a484a80a0c4..0043432dd57 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -254,59 +254,26 @@ spec: like cookies, authentication headers, or TLS client certificates. type: boolean allowHeaders: - description: AllowHeaders defines the headers that are allowed - to be sent with requests. + description: |- + AllowHeaders defines the headers that are allowed to be sent with requests. + It specifies the allowed headers in the Access-Control-Allow-Headers header. + The value "*" allows any header to be sent. items: - description: |- - HTTPHeaderName is the name of an HTTP header. - - Valid values include: - - * "Authorization" - * "Set-Cookie" - - Invalid values include: - - - ":method" - ":" is an invalid character. This means that HTTP/2 pseudo - headers are not currently supported by this type. - - "/invalid" - "/ " is an invalid character - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string type: array allowMethods: - description: AllowMethods defines the methods that are allowed - to make requests. + description: |- + AllowMethods defines the methods that are allowed to make requests. + It specifies the allowed methods in the Access-Control-Allow-Methods header. + The value "*" allows any method to be used. items: - description: |- - HTTPMethod describes how to select a HTTP route by matching the HTTP - method as defined by - [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231#section-4) and - [RFC 5789](https://datatracker.ietf.org/doc/html/rfc5789#section-2). - The value is expected in upper case. - - Note that values may be added to this enum, implementations - must ensure that unknown values will not cause a crash. - - Unknown values here must result in the implementation setting the - Accepted Condition for the Route to `status: False`, with a - Reason of `UnsupportedValue`. - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH type: string type: array allowOrigins: - description: AllowOrigins defines the origins that are allowed - to make requests. + description: |- + AllowOrigins defines the origins that are allowed to make requests. + It specifies the allowed origins in the Access-Control-Allow-Origin header. + The value "*" allows any origin to make requests. items: description: |- Origin is defined by the scheme (protocol), hostname (domain), and port of @@ -328,30 +295,16 @@ spec: type: string type: array exposeHeaders: - description: ExposeHeaders defines the headers that can be exposed - in the responses. + description: |- + ExposeHeaders defines the headers that can be exposed in the responses. + It specifies the headers in the Access-Control-Expose-Headers header. items: - description: |- - HTTPHeaderName is the name of an HTTP header. - - Valid values include: - - * "Authorization" - * "Set-Cookie" - - Invalid values include: - - - ":method" - ":" is an invalid character. This means that HTTP/2 pseudo - headers are not currently supported by this type. - - "/invalid" - "/ " is an invalid character - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ type: string type: array maxAge: - description: MaxAge defines how long the results of a preflight - request can be cached. + description: |- + MaxAge defines how long the results of a preflight request can be cached. + It specifies the value in the Access-Control-Max-Age header. type: string type: object extAuth: diff --git a/internal/xds/translator/cors.go b/internal/xds/translator/cors.go index cda5ae8a40a..542b9aa680c 100644 --- a/internal/xds/translator/cors.go +++ b/internal/xds/translator/cors.go @@ -134,8 +134,18 @@ func (*cors) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute) error { allowOrigins = append(allowOrigins, buildXdsStringMatcher(origin)) } - allowMethods = strings.Join(c.AllowMethods, ", ") - allowHeaders = strings.Join(c.AllowHeaders, ", ") + // Envoy only supports a single "*" for matching all, and treats the "*" in "*, GET" as a literal. + // https://github.com/envoyproxy/envoy/blob/eb61f368690cae173502f80549b7e2169ec24766/source/extensions/filters/http/cors/cors_filter.cc#L140-L159 + if hasWildcard(c.AllowMethods) { + allowMethods = "*" + } else { + allowMethods = strings.Join(c.AllowMethods, ", ") + } + if hasWildcard(c.AllowHeaders) { + allowHeaders = "*" + } else { + allowHeaders = strings.Join(c.AllowHeaders, ", ") + } exposeHeaders = strings.Join(c.ExposeHeaders, ", ") if c.MaxAge != nil { maxAge = strconv.Itoa(int(c.MaxAge.Seconds())) @@ -166,6 +176,15 @@ func (*cors) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute) error { return nil } +func hasWildcard(array []string) bool { + for _, s := range array { + if s == "*" { + return true + } + } + return false +} + func (c *cors) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { return nil } diff --git a/internal/xds/translator/testdata/in/xds-ir/cors.yaml b/internal/xds/translator/testdata/in/xds-ir/cors.yaml index dd9eff3418f..0e046110a00 100644 --- a/internal/xds/translator/testdata/in/xds-ir/cors.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/cors.yaml @@ -30,6 +30,7 @@ http: allowMethods: - GET - POST + - "*" allowHeaders: - "x-header-1" - "x-header-2" diff --git a/internal/xds/translator/testdata/out/xds-ir/cors.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/cors.routes.yaml index 93bfb4d3c15..12c4fce7778 100644 --- a/internal/xds/translator/testdata/out/xds-ir/cors.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/cors.routes.yaml @@ -17,7 +17,7 @@ '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy allowCredentials: true allowHeaders: x-header-1, x-header-2 - allowMethods: GET, POST + allowMethods: '*' allowOriginStringMatch: - safeRegex: regex: '*.example.com' diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 16fd6de412e..ffb388a142d 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -533,11 +533,11 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | -| `allowOrigins` | _[Origin](#origin) array_ | false | AllowOrigins defines the origins that are allowed to make requests. | -| `allowMethods` | _HTTPMethod array_ | false | AllowMethods defines the methods that are allowed to make requests. | -| `allowHeaders` | _[HTTPHeaderName](#httpheadername) array_ | false | AllowHeaders defines the headers that are allowed to be sent with requests. | -| `exposeHeaders` | _[HTTPHeaderName](#httpheadername) array_ | false | ExposeHeaders defines the headers that can be exposed in the responses. | -| `maxAge` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | MaxAge defines how long the results of a preflight request can be cached. | +| `allowOrigins` | _[Origin](#origin) array_ | false | AllowOrigins defines the origins that are allowed to make requests.
It specifies the allowed origins in the Access-Control-Allow-Origin header.
The value "*" allows any origin to make requests. | +| `allowMethods` | _string array_ | false | AllowMethods defines the methods that are allowed to make requests.
It specifies the allowed methods in the Access-Control-Allow-Methods header.
The value "*" allows any method to be used. | +| `allowHeaders` | _string array_ | false | AllowHeaders defines the headers that are allowed to be sent with requests.
It specifies the allowed headers in the Access-Control-Allow-Headers header.
The value "*" allows any header to be sent. | +| `exposeHeaders` | _string array_ | false | ExposeHeaders defines the headers that can be exposed in the responses.
It specifies the headers in the Access-Control-Expose-Headers header. | +| `maxAge` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | MaxAge defines how long the results of a preflight request can be cached.
It specifies the value in the Access-Control-Max-Age header. | | `allowCredentials` | _boolean_ | false | AllowCredentials indicates whether a request can include user credentials
like cookies, authentication headers, or TLS client certificates. | diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 16fd6de412e..ffb388a142d 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -533,11 +533,11 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | -| `allowOrigins` | _[Origin](#origin) array_ | false | AllowOrigins defines the origins that are allowed to make requests. | -| `allowMethods` | _HTTPMethod array_ | false | AllowMethods defines the methods that are allowed to make requests. | -| `allowHeaders` | _[HTTPHeaderName](#httpheadername) array_ | false | AllowHeaders defines the headers that are allowed to be sent with requests. | -| `exposeHeaders` | _[HTTPHeaderName](#httpheadername) array_ | false | ExposeHeaders defines the headers that can be exposed in the responses. | -| `maxAge` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | MaxAge defines how long the results of a preflight request can be cached. | +| `allowOrigins` | _[Origin](#origin) array_ | false | AllowOrigins defines the origins that are allowed to make requests.
It specifies the allowed origins in the Access-Control-Allow-Origin header.
The value "*" allows any origin to make requests. | +| `allowMethods` | _string array_ | false | AllowMethods defines the methods that are allowed to make requests.
It specifies the allowed methods in the Access-Control-Allow-Methods header.
The value "*" allows any method to be used. | +| `allowHeaders` | _string array_ | false | AllowHeaders defines the headers that are allowed to be sent with requests.
It specifies the allowed headers in the Access-Control-Allow-Headers header.
The value "*" allows any header to be sent. | +| `exposeHeaders` | _string array_ | false | ExposeHeaders defines the headers that can be exposed in the responses.
It specifies the headers in the Access-Control-Expose-Headers header. | +| `maxAge` | _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | false | MaxAge defines how long the results of a preflight request can be cached.
It specifies the value in the Access-Control-Max-Age header. | | `allowCredentials` | _boolean_ | false | AllowCredentials indicates whether a request can include user credentials
like cookies, authentication headers, or TLS client certificates. |