GEP: Add support for cookie in the HTTPRouteMatch API #2891
Description
What would you like to be added:
It would be great if HTTPRouteMatch had a field to select a HTTP route by matching HTTP request cookies.
Moreover, a new match type "list" is added. Matches if the value of the cookie with name field is present in a list of strings.
This match type "list" can be applied to serving HTTPHeaderMatch and HTTPQueryParamMatch as well.
Similar specifications can be seen in ingress like ingress-nginx (ref: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary) nginx.ingress.kubernetes.io/canary-by-cookie, kubernetes-ingress (ref: https://docs.nginx.com/nginx-ingress-controller/configuration/virtualserver-and-virtualserverroute-resources/#condition) and tengine-ingress (ref: https://tengine.taobao.org/document/ingress_routes.html).
// CookieMatchType specifies the semantics of how HTTP cookie values should be
// compared. Valid CookieMatchType values, along with their conformance levels, are:
//
// * "Exact" - Core
// * "List" - Extended
// * "RegularExpression" - Implementation Specific
//
// * "Exact" matching exact string
// * "List" matching string in a list of strings
//
// 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`.
//
// +kubebuilder:validation:Enum=Exact;RegularExpression
type CookieMatchType string
// CookieMatchType constants.
const (
CookieMatchExact CookieMatchType = "Exact"
CookieMatchList CookieMatchType = "List"
CookieMatchRegularExpression CookieMatchType = "RegularExpression"
)
// HTTPCookieMatch describes how to select a HTTP route by matching HTTP request
// cookies.
type HTTPCookieMatch struct {
// Type specifies how to match against the value of the cookie.
//
// Support: Core (Exact)
//
// Support: Extended (List)
//
// Support: Implementation-specific (RegularExpression)
//
// Since RegularExpression CookieMatchType has implementation-specific
// conformance, implementations can support POSIX, PCRE or any other dialects
// of regular expressions. Please read the implementation's documentation to
// determine the supported dialect.
//
// +optional
// +kubebuilder:default=Exact
Type *CookieMatchType `json:"type,omitempty"`
// Name is the cookie-name of the cookie-pair in the HTTP Cookie header to be matched.
// (See https://datatracker.ietf.org/doc/html/rfc6265#section-4.2.1)
// cookie-header = "Cookie:" OWS cookie-string OWS
// cookie-string = cookie-pair *( ";" SP cookie-pair )
// (See https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1)
// cookie-pair = cookie-name "=" cookie-value
// cookie-name = token
// token = <token, defined in [RFC2616], Section 2.2>
//
// If multiple entries specify equivalent cookie names, only the first
// entry with an equivalent name MUST be considered for a match. Subsequent
// entries with an equivalent cookie name MUST be ignored. Due to the
// case-insensitivity of cookie names, "foo" and "Foo" are considered
// equivalent.
//
// When a Cookie header is repeated in an HTTP request, it is
// implementation-specific behavior as to how this is represented.
// Generally, proxies should follow the guidance from the RFC:
// https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding
// processing a repeated header.
Name HTTPHeaderName `json:"name"`
// Values is the cookie-value of the cookie-pair in the HTTP Cookie header to be matched.
// Matches if the value of the cookie with name field is present in the HTTP Cookie header.
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=1024
Value string `json:"value"`
// Values are the cookie-value list of the cookie-pair in the HTTP Cookie header to be matched.
// Matches if the value of the cookie with name field is present in the list.
//
// +optional
// +listType=set
// +kubebuilder:validation:MaxItems=16
Values []string `json:"values"`
}
Why this is needed:
Just like HTTP route based on header and query parameter is common, it is useful to match a cookie-name and cookie-value of the request for the specific backends.
Cookies are used to maintain state and identify specific users. It is an essential part of the HTTP request.
The Cookie header has multiple cookie-pair which contains the cookie-name and cookie-value.
cookie-header = "Cookie:" OWS cookie-string OWS
cookie-string = cookie-pair *( ";" SP cookie-pair )
cookie-pair = cookie-name "=" cookie-value
cookie-name = token
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
token = <token, defined in [[RFC2616], Section 2.2](https://datatracker.ietf.org/doc/html/rfc2616#section-2.2)>
E.g., backend service wants to select specific users for measuring the effectiveness of advertising campaigns. However, the cookies are used to maintain state and identify specific users. Hence, based on the following http rule, the http requests with cookie name "unb" and cookie value in a list of strings (i.e., 2426168118, 2208203664638, 2797880990, 70772956, 2215140160618) will be routed to the service "http-route-canary-campaign:7001".
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-cookie
spec:
hostnames:
- http.route.cookies.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: http-gateway
rules:
- backendRefs:
- kind: Service
name: http-route-production
port: 7001
matches:
- path:
type: PathPrefix
value: /
- backendRefs:
- kind: Service
name: http-route-canary-campaign
port: 7001
matches:
- cookies:
- name: unb
type: List
values:
- 2426168118
- 2208203664638
- 2797880990
- 70772956
- 2215140160618
Cookies, headers and query parameter are common techniques used in a canary release.
E.g., based on the following http route, the HTTP requests with cookie "gray=true" will be route to the canary service "http-site-canary:80" specifically.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-cookie
spec:
hostnames:
- http.site.cookie.com
- http.site.cookies.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: http-gateway
rules:
- backendRefs:
- kind: Service
name: http-site-production
port: 80
matches:
- path:
type: PathPrefix
value: /
- backendRefs:
- kind: Service
name: http-site-canary
port: 80
matches:
- cookies:
- name: gray
type: Exact
value: true
If this requires a GEP, I would be like to start working on it.