Skip to content

Commit 47b2d19

Browse files
committed
review_comment: add a security note
Signed-off-by: Anurag Aggarwal <kanurag94@gmail.com>
1 parent a2a0eec commit 47b2d19

4 files changed

Lines changed: 57 additions & 8 deletions

File tree

api/v1beta1/ai_gateway_route.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,14 @@ type AIGatewayRouteSpec struct {
206206
// +kubebuilder:validation:MaxItems=36
207207
LLMRequestCosts []LLMRequestCost `json:"llmRequestCosts,omitempty"`
208208

209-
// RateLimitsFromHeaders emits per-request rate-limit override structs from trusted request
210-
// headers into io.envoy.ai_gateway dynamic metadata. Each header value must be formatted as
209+
// RateLimitsFromHeaders emits per-request rate-limit override structs from request headers
210+
// into io.envoy.ai_gateway dynamic metadata. Each header value must be formatted as
211211
// "<count>/<unit>" (e.g. "100000/HOUR"). Overrides the global defaults from GatewayConfig
212212
// for entries with the same MetadataKey.
213213
//
214+
// See RateLimitFromHeader for the security requirement to strip these headers from client
215+
// requests using ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove.
216+
//
214217
// +optional
215218
// +listType=map
216219
// +listMapKey=metadataKey

api/v1beta1/gateway_config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,12 @@ type GatewayConfigSpec struct {
8282
GlobalLLMRequestCosts []LLMRequestCost `json:"globalLLMRequestCosts,omitempty"`
8383

8484
// GlobalRateLimitsFromHeaders defines gateway-level defaults for emitting per-request
85-
// rate-limit override structs from trusted request headers into io.envoy.ai_gateway dynamic metadata.
85+
// rate-limit override structs from request headers into io.envoy.ai_gateway dynamic metadata.
8686
// Route-scoped entries with the same MetadataKey take precedence.
8787
//
88+
// See RateLimitFromHeader for the security requirement to strip these headers from client
89+
// requests using ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove.
90+
//
8891
// +optional
8992
// +listType=map
9093
// +listMapKey=metadataKey

api/v1beta1/shared_types.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,36 @@ const (
170170
// "COUNT/UNIT" (e.g. "100000/HOUR"). The gateway parses it and writes a struct with
171171
// requests_per_unit and unit fields under MetadataKey — the struct
172172
// Envoy's RateLimit.Override.DynamicMetadata reads. If the header is absent or malformed the key is omitted.
173+
//
174+
// Security note: this feature reads the rate-limit value directly from an incoming request header.
175+
// A client that can set this header can inflate its own quota. To prevent spoofing, you MUST strip
176+
// the header from client requests before the HTTP filter chain (including ext-authz) processes it.
177+
// Use ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove on the associated Gateway:
178+
//
179+
// apiVersion: gateway.envoyproxy.io/v1alpha1
180+
// kind: ClientTrafficPolicy
181+
// spec:
182+
// targetRefs:
183+
// - group: gateway.networking.k8s.io
184+
// kind: Gateway
185+
// name: <your-gateway>
186+
// headers:
187+
// earlyRequestHeaders:
188+
// remove: ["<header-name>"]
189+
//
190+
// After stripping, only the trusted ext-authz (or another filter running after the strip)
191+
// can set the header, ensuring the value reflects the actual tenant quota.
173192
type RateLimitFromHeader struct {
174193
// MetadataKey is the key written under io.envoy.ai_gateway in the dynamic metadata.
175194
//
176195
// +kubebuilder:validation:Required
177196
MetadataKey string `json:"metadataKey"`
178-
// Header is the trusted request header whose value encodes the rate limit as "<count>/<unit>",
197+
// Header is the request header whose value encodes the rate limit as "<count>/<unit>",
179198
// where unit is one of SECOND, MINUTE, HOUR, DAY.
180199
//
200+
// This header must be set exclusively by a trusted component (e.g. ext-authz).
201+
// See the security note on RateLimitFromHeader for how to prevent client spoofing.
202+
//
181203
// +kubebuilder:validation:Required
182204
Header string `json:"header"`
183205
}

site/docs/api/api.mdx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,7 +3199,7 @@ AIGatewayRouteSpec details the AIGatewayRoute configuration.
31993199
name="rateLimitsFromHeaders"
32003200
type="[RateLimitFromHeader](#github.qkg1.top-envoyproxy-ai-gateway-api-v1beta1-ratelimitfromheader) array"
32013201
required="false"
3202-
description="RateLimitsFromHeaders emits per-request rate-limit override structs from trusted request<br />headers into io.envoy.ai_gateway dynamic metadata. Each header value must be formatted as<br />`<count>/<unit>` (e.g. `100000/HOUR`). Overrides the global defaults from GatewayConfig<br />for entries with the same MetadataKey."
3202+
description="RateLimitsFromHeaders emits per-request rate-limit override structs from request headers<br />into io.envoy.ai_gateway dynamic metadata. Each header value must be formatted as<br />`<count>/<unit>` (e.g. `100000/HOUR`). Overrides the global defaults from GatewayConfig<br />for entries with the same MetadataKey.<br /><br />See RateLimitFromHeader for the security requirement to strip these headers from client<br />requests using ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove."
32033203
/>
32043204

32053205

@@ -3939,7 +3939,7 @@ GatewayConfigSpec defines the configuration for the AI Gateway.
39393939
name="globalRateLimitsFromHeaders"
39403940
type="[RateLimitFromHeader](#github.qkg1.top-envoyproxy-ai-gateway-api-v1beta1-ratelimitfromheader) array"
39413941
required="false"
3942-
description="GlobalRateLimitsFromHeaders defines gateway-level defaults for emitting per-request<br />rate-limit override structs from trusted request headers into io.envoy.ai_gateway dynamic metadata.<br />Route-scoped entries with the same MetadataKey take precedence."
3942+
description="GlobalRateLimitsFromHeaders defines gateway-level defaults for emitting per-request<br />rate-limit override structs from request headers into io.envoy.ai_gateway dynamic metadata.<br />Route-scoped entries with the same MetadataKey take precedence.<br /><br />See RateLimitFromHeader for the security requirement to strip these headers from client<br />requests using ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove."
39433943
/>
39443944

39453945

@@ -4671,11 +4671,32 @@ References:
46714671
- [GatewayConfigSpec](#github.qkg1.top-envoyproxy-ai-gateway-api-v1beta1-gatewayconfigspec)
46724672

46734673
RateLimitFromHeader emits a per-request rate-limit override struct into io.envoy.ai_gateway
4674-
dynamic metadata from a trusted request header. The header value must be formatted as
4674+
dynamic metadata from a request header. The header value must be formatted as
46754675
"COUNT/UNIT" (e.g. "100000/HOUR"). The gateway parses it and writes a struct with
46764676
requests_per_unit and unit fields under MetadataKey — the struct
46774677
Envoy's RateLimit.Override.DynamicMetadata reads. If the header is absent or malformed the key is omitted.
46784678

4679+
**Security note**: this feature reads the rate-limit value from an incoming request header.
4680+
A client that can set this header can inflate its own quota. To prevent spoofing, you MUST strip
4681+
the header from client requests before the HTTP filter chain (including ext-authz) processes it.
4682+
Use `ClientTrafficPolicy.spec.headers.earlyRequestHeaders.remove` on the associated Gateway:
4683+
4684+
```yaml
4685+
apiVersion: gateway.envoyproxy.io/v1alpha1
4686+
kind: ClientTrafficPolicy
4687+
spec:
4688+
targetRefs:
4689+
- group: gateway.networking.k8s.io
4690+
kind: Gateway
4691+
name: <your-gateway>
4692+
headers:
4693+
earlyRequestHeaders:
4694+
remove: ["<header-name>"]
4695+
```
4696+
4697+
After stripping, only a trusted component such as ext-authz (running after the strip) can set
4698+
the header, ensuring the value reflects the actual tenant quota.
4699+
46794700
##### Fields
46804701
46814702
@@ -4689,7 +4710,7 @@ Envoy's RateLimit.Override.DynamicMetadata reads. If the header is absent or mal
46894710
name="header"
46904711
type="string"
46914712
required="true"
4692-
description="Header is the trusted request header whose value encodes the rate limit as `<count>/<unit>`,<br />where unit is one of SECOND, MINUTE, HOUR, DAY."
4713+
description="Header is the request header whose value encodes the rate limit as `<count>/<unit>`,<br />where unit is one of SECOND, MINUTE, HOUR, DAY.<br /><br />This header must be set exclusively by a trusted component (e.g. ext-authz). See the security<br />note on RateLimitFromHeader for how to prevent client spoofing."
46934714
/>
46944715

46954716

0 commit comments

Comments
 (0)