Skip to content

Commit af11f9b

Browse files
authored
Add support for API key authN in TrafficPolicy (#12962)
Signed-off-by: Yossi Mesika <[email protected]>
1 parent 026f39c commit af11f9b

40 files changed

+4685
-2
lines changed

.github/workflows/e2e.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
# August 29, 2025: ~10 minutes
5555
- cluster-name: 'cluster-five'
5656
go-test-args: '-timeout=25m'
57-
go-test-run-regex: '^TestKgateway$$/^TimeoutRetry$$|^TestKgateway$$/^HeaderModifiers$$|^TestKgateway$$/^RBAC$$|^TestKgateway$$/^Deployer$$|^TestKgateway$$/^Transforms$$|^TestRouteReplacement$$|^TestKgateway$$/^RouteDelegation$$|^TestKgateway$$/^JWT$$|^TestKgateway$$/^BasicAuth$$'
57+
go-test-run-regex: '^TestKgateway$$/^TimeoutRetry$$|^TestKgateway$$/^HeaderModifiers$$|^TestKgateway$$/^RBAC$$|^TestKgateway$$/^APIKeyAuth$$|^TestKgateway$$/^Deployer$$|^TestKgateway$$/^Transforms$$|^TestRouteReplacement$$|^TestKgateway$$/^RouteDelegation$$|^TestKgateway$$/^JWT$$|^TestKgateway$$/^BasicAuth$$'
5858
localstack: 'false'
5959
# August 29, 2025: ~9 minutes
6060
- cluster-name: 'cluster-six'

api/v1alpha1/kgateway/traffic_policy_types.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ type TrafficPolicySpec struct {
139139
// This controls authentication using username/password credentials in the Authorization header.
140140
// +optional
141141
BasicAuth *BasicAuthPolicy `json:"basicAuth,omitempty"`
142+
143+
// APIKeyAuthentication authenticates users based on a configured API Key.
144+
// +optional
145+
APIKeyAuthentication *APIKeyAuthentication `json:"apiKeyAuthentication,omitempty"`
142146
}
143147

144148
// URLRewrite specifies URL rewrite rules using regular expressions.
@@ -416,6 +420,118 @@ type CSRFPolicy struct {
416420
AdditionalOrigins []shared.StringMatcher `json:"additionalOrigins,omitempty"`
417421
}
418422

423+
// APIKeySource defines where to extract the API key from within a single key source.
424+
// Within a single key source, if multiple types are specified, precedence is:
425+
// header > query parameter > cookie. The header is checked first, and only falls back
426+
// to query parameter if the header is not present, then to cookie if both header and query
427+
// are not present.
428+
// +kubebuilder:validation:AtLeastOneOf=header;query;cookie
429+
type APIKeySource struct {
430+
// header specifies the name of the header that contains the API key.
431+
// +optional
432+
// +kubebuilder:validation:MinLength=1
433+
// +kubebuilder:validation:MaxLength=256
434+
Header *string `json:"header,omitempty"`
435+
436+
// query specifies the name of the query parameter that contains the API key.
437+
// +optional
438+
// +kubebuilder:validation:MinLength=1
439+
// +kubebuilder:validation:MaxLength=256
440+
Query *string `json:"query,omitempty"`
441+
442+
// cookie specifies the name of the cookie that contains the API key.
443+
// +optional
444+
// +kubebuilder:validation:MinLength=1
445+
// +kubebuilder:validation:MaxLength=256
446+
Cookie *string `json:"cookie,omitempty"`
447+
}
448+
449+
// +kubebuilder:validation:ExactlyOneOf=secretRef;secretSelector
450+
type APIKeyAuthentication struct {
451+
// keySources specifies the list of key sources to extract the API key from.
452+
// Key sources are processed in array order and the first one that successfully
453+
// extracts a key is used. Within each key source, if multiple types (header, query, cookie) are
454+
// specified, precedence is: header > query parameter > cookie.
455+
//
456+
// If empty, defaults to a single key source with header "api-key".
457+
//
458+
// Example:
459+
// keySources:
460+
// - header: "X-API-KEY"
461+
// - query: "api_key"
462+
// - header: "Authorization"
463+
// query: "token"
464+
// cookie: "auth_token"
465+
//
466+
// In this example, the system will:
467+
// 1. First try header "X-API-KEY"
468+
// 2. If not found, try query parameter "api_key"
469+
// 3. If not found, try header "Authorization" (then query "token", then cookie "auth_token" within that key source)
470+
//
471+
// +kubebuilder:validation:MinItems=0
472+
// +kubebuilder:validation:MaxItems=16
473+
// +optional
474+
KeySources []APIKeySource `json:"keySources,omitempty"`
475+
476+
// forwardCredential controls whether the API key is included in the request sent to the upstream.
477+
// If false (default), the API key is removed from the request before sending to upstream.
478+
// If true, the API key is included in the request sent to upstream.
479+
// This applies to all configured key sources (header, query parameter, or cookie).
480+
// +optional
481+
ForwardCredential *bool `json:"forwardCredential,omitempty"`
482+
483+
// clientIdHeader specifies the header name to forward the authenticated client identifier.
484+
// If not specified, the client identifier will not be forwarded in any header.
485+
// Example: "x-client-id"
486+
// +optional
487+
ClientIdHeader *string `json:"clientIdHeader,omitempty"`
488+
489+
// secretRef references a Kubernetes secret storing a set of API Keys. If there are many keys, 'secretSelector' can be
490+
// used instead.
491+
//
492+
// Each entry in the Secret represents one API Key. The key is an arbitrary identifier.
493+
// The value is a string, representing the API Key.
494+
//
495+
// Example:
496+
//
497+
// apiVersion: v1
498+
// kind: Secret
499+
// metadata:
500+
// name: api-key
501+
// stringData:
502+
// client1: "k-123"
503+
// client2: "k-456"
504+
//
505+
// +optional
506+
SecretRef *gwv1.SecretObjectReference `json:"secretRef,omitempty"`
507+
508+
// secretSelector selects multiple secrets containing API Keys. If the same key is defined in multiple secrets, the
509+
// behavior is undefined.
510+
//
511+
// Each entry in the Secret represents one API Key. The key is an arbitrary identifier.
512+
// The value is a string, representing the API Key.
513+
//
514+
// Example:
515+
//
516+
// apiVersion: v1
517+
// kind: Secret
518+
// metadata:
519+
// name: api-key
520+
// stringData:
521+
// client1: "k-123"
522+
// client2: "k-456"
523+
//
524+
// +optional
525+
SecretSelector *LabelSelector `json:"secretSelector,omitempty"`
526+
}
527+
528+
// LabelSelector selects resources using label selectors.
529+
type LabelSelector struct {
530+
// Label selector to select the target resource.
531+
// +required
532+
MatchLabels map[string]string `json:"matchLabels"`
533+
}
534+
419535
// +kubebuilder:validation:ExactlyOneOf=maxRequestSize;disable
420536
type Buffer struct {
421537
// MaxRequestSize sets the maximum size in bytes of a message body to buffer.

api/v1alpha1/kgateway/zz_generated.deepcopy.go

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)