Skip to content

GEP: Add support for cookie in the HTTPRouteMatch API #2891

Open
@lianglli

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.

Metadata

Assignees

Labels

kind/featureCategorizes issue or PR as related to a new feature.kind/gepPRs related to Gateway Enhancement Proposal(GEP)lifecycle/rottenDenotes an issue or PR that has aged beyond stale and will be auto-closed.needs-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions