From 54803c1abaa1da282e01a7e07cfcac71c64a15f9 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Thu, 26 Oct 2023 17:16:00 -0700 Subject: [PATCH] remove RateLimitFilter in favor of BackendTrafficPolicy (#2083) * remove RateLimitFilter in favor of BackendTrafficPolicy Relates to https://github.com/envoyproxy/gateway/issues/2006 Signed-off-by: Arko Dasgupta * fix tests Signed-off-by: Arko Dasgupta * fix e2e Signed-off-by: Arko Dasgupta * fix docs Signed-off-by: Arko Dasgupta * lint Signed-off-by: Arko Dasgupta --------- Signed-off-by: Arko Dasgupta --- api/v1alpha1/backendtrafficpolicy_types.go | 2 +- ...imitfilter_types.go => ratelimit_types.go} | 39 +- api/v1alpha1/zz_generated.deepcopy.go | 100 +--- ...ateway.envoyproxy.io_ratelimitfilters.yaml | 180 ------ ...lter-single-route-single-match-to-xds.yaml | 113 ---- ...-single-route-single-match-to-xds.all.json | 512 ------------------ ...-single-route-single-match-to-xds.all.yaml | 292 ---------- ...e-route-single-match-to-xds.bootstrap.yaml | 119 ---- ...gle-route-single-match-to-xds.cluster.yaml | 63 --- ...le-route-single-match-to-xds.endpoint.yaml | 17 - ...le-route-single-match-to-xds.listener.yaml | 72 --- ...ingle-route-single-match-to-xds.route.yaml | 28 - internal/cmd/egctl/translate.go | 14 - internal/cmd/egctl/translate_test.go | 77 --- internal/gatewayapi/filters.go | 98 ---- internal/gatewayapi/helpers.go | 22 - internal/gatewayapi/helpers_test.go | 48 -- internal/gatewayapi/resource.go | 2 - internal/gatewayapi/route.go | 3 - ...pcroute-with-valid-ratelimitfilter.in.yaml | 55 -- ...croute-with-valid-ratelimitfilter.out.yaml | 133 ----- ...with-distinct-sourcecidr-ratelimit.in.yaml | 59 -- ...ith-distinct-sourcecidr-ratelimit.out.yaml | 143 ----- ...route-with-invalid-ratelimitfilter.in.yaml | 60 -- ...oute-with-invalid-ratelimitfilter.out.yaml | 116 ---- ...ttproute-with-sourcecidr-ratelimit.in.yaml | 58 -- ...tproute-with-sourcecidr-ratelimit.out.yaml | 143 ----- ...tproute-with-valid-ratelimitfilter.in.yaml | 61 --- ...proute-with-valid-ratelimitfilter.out.yaml | 143 ----- internal/gatewayapi/zz_generated.deepcopy.go | 11 - internal/provider/kubernetes/controller.go | 71 +-- internal/provider/kubernetes/filters.go | 28 - .../provider/kubernetes/kubernetes_test.go | 211 -------- internal/provider/kubernetes/predicates.go | 24 - internal/provider/kubernetes/routes.go | 46 +- internal/provider/kubernetes/routes_test.go | 317 ----------- internal/provider/kubernetes/test/utils.go | 42 -- site/content/en/latest/api/extension_types.md | 54 +- site/content/en/latest/user/rate-limit.md | 429 +++------------ .../testdata/ratelimit-based-jwt-claims.yaml | 33 +- .../e2e/testdata/ratelimit-block-all-ips.yaml | 34 +- tools/crd-ref-docs/config.yaml | 2 +- 42 files changed, 170 insertions(+), 3904 deletions(-) rename api/v1alpha1/{ratelimitfilter_types.go => ratelimit_types.go} (84%) delete mode 100644 charts/gateway-helm/crds/generated/gateway.envoyproxy.io_ratelimitfilters.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/in/rate-limit-filter-single-route-single-match-to-xds.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.json delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.bootstrap.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.cluster.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.endpoint.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.listener.yaml delete mode 100644 internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.route.yaml delete mode 100644 internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.out.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.in.yaml delete mode 100644 internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.out.yaml diff --git a/api/v1alpha1/backendtrafficpolicy_types.go b/api/v1alpha1/backendtrafficpolicy_types.go index f01bb401d02..1d092a31dc5 100644 --- a/api/v1alpha1/backendtrafficpolicy_types.go +++ b/api/v1alpha1/backendtrafficpolicy_types.go @@ -49,7 +49,7 @@ type BackendTrafficPolicySpec struct { // RateLimit allows the user to limit the number of incoming requests // to a predefined value based on attributes within the traffic flow. // +optional - RateLimit *RateLimitFilterSpec `json:"rateLimit,omitempty"` + RateLimit *RateLimitSpec `json:"rateLimit,omitempty"` // LoadBalancer policy to apply when routing traffic from the gateway to // the backend endpoints diff --git a/api/v1alpha1/ratelimitfilter_types.go b/api/v1alpha1/ratelimit_types.go similarity index 84% rename from api/v1alpha1/ratelimitfilter_types.go rename to api/v1alpha1/ratelimit_types.go index 5ee825d3b3c..e013579efdf 100644 --- a/api/v1alpha1/ratelimitfilter_types.go +++ b/api/v1alpha1/ratelimit_types.go @@ -5,31 +5,9 @@ package v1alpha1 -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - // KindRateLimitFilter is the name of the RateLimitFilter kind. - KindRateLimitFilter = "RateLimitFilter" -) - -// +kubebuilder:object:root=true -// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` - -// RateLimitFilter allows the user to limit the number of incoming requests -// to a predefined value based on attributes within the traffic flow. -type RateLimitFilter struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of RateLimitFilter. - Spec RateLimitFilterSpec `json:"spec"` -} - -// RateLimitFilterSpec defines the desired state of RateLimitFilter. +// RateLimitSpec defines the desired state of RateLimitSpec. // +union -type RateLimitFilterSpec struct { +type RateLimitSpec struct { // Type decides the scope for the RateLimits. // Valid RateLimitType values are "Global". // @@ -184,16 +162,3 @@ type RateLimitValue struct { // // +kubebuilder:validation:Enum=Second;Minute;Hour;Day type RateLimitUnit string - -//+kubebuilder:object:root=true - -// RateLimitFilterList contains a list of RateLimitFilter resources. -type RateLimitFilterList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []RateLimitFilter `json:"items"` -} - -func init() { - SchemeBuilder.Register(&RateLimitFilter{}, &RateLimitFilterList{}) -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index be47b98c57d..603df02472e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -162,7 +162,7 @@ func (in *BackendTrafficPolicySpec) DeepCopyInto(out *BackendTrafficPolicySpec) in.TargetRef.DeepCopyInto(&out.TargetRef) if in.RateLimit != nil { in, out := &in.RateLimit, &out.RateLimit - *out = new(RateLimitFilterSpec) + *out = new(RateLimitSpec) (*in).DeepCopyInto(*out) } if in.LoadBalancer != nil { @@ -1985,84 +1985,6 @@ func (in *RateLimitDatabaseBackend) DeepCopy() *RateLimitDatabaseBackend { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RateLimitFilter) DeepCopyInto(out *RateLimitFilter) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitFilter. -func (in *RateLimitFilter) DeepCopy() *RateLimitFilter { - if in == nil { - return nil - } - out := new(RateLimitFilter) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RateLimitFilter) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RateLimitFilterList) DeepCopyInto(out *RateLimitFilterList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]RateLimitFilter, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitFilterList. -func (in *RateLimitFilterList) DeepCopy() *RateLimitFilterList { - if in == nil { - return nil - } - out := new(RateLimitFilterList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RateLimitFilterList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RateLimitFilterSpec) DeepCopyInto(out *RateLimitFilterSpec) { - *out = *in - if in.Global != nil { - in, out := &in.Global, &out.Global - *out = new(GlobalRateLimit) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitFilterSpec. -func (in *RateLimitFilterSpec) DeepCopy() *RateLimitFilterSpec { - if in == nil { - return nil - } - out := new(RateLimitFilterSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RateLimitRedisSettings) DeepCopyInto(out *RateLimitRedisSettings) { *out = *in @@ -2133,6 +2055,26 @@ func (in *RateLimitSelectCondition) DeepCopy() *RateLimitSelectCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitSpec) DeepCopyInto(out *RateLimitSpec) { + *out = *in + if in.Global != nil { + in, out := &in.Global, &out.Global + *out = new(GlobalRateLimit) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitSpec. +func (in *RateLimitSpec) DeepCopy() *RateLimitSpec { + if in == nil { + return nil + } + out := new(RateLimitSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RateLimitValue) DeepCopyInto(out *RateLimitValue) { *out = *in diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_ratelimitfilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_ratelimitfilters.yaml deleted file mode 100644 index 1c403566111..00000000000 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_ratelimitfilters.yaml +++ /dev/null @@ -1,180 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.13.0 - name: ratelimitfilters.gateway.envoyproxy.io -spec: - group: gateway.envoyproxy.io - names: - kind: RateLimitFilter - listKind: RateLimitFilterList - plural: ratelimitfilters - singular: ratelimitfilter - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: RateLimitFilter allows the user to limit the number of incoming - requests to a predefined value based on attributes within the traffic flow. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of RateLimitFilter. - properties: - global: - description: Global defines global rate limit configuration. - properties: - rules: - description: Rules are a list of RateLimit selectors and limits. - Each rule and its associated limit is applied in a mutually - exclusive way i.e. if multiple rules get selected, each of their - associated limits get applied, so a single traffic request might - increase the rate limit counters for multiple rules if selected. - items: - description: RateLimitRule defines the semantics for matching - attributes from the incoming requests, and setting limits - for them. - properties: - clientSelectors: - description: ClientSelectors holds the list of select conditions - to select specific clients using attributes from the traffic - flow. All individual select conditions must hold True - for this rule and its limit to be applied. If this field - is empty, it is equivalent to True, and the limit is applied. - items: - description: RateLimitSelectCondition specifies the attributes - within the traffic flow that can be used to select a - subset of clients to be ratelimited. All the individual - conditions must hold True for the overall condition - to hold True. - properties: - headers: - description: Headers is a list of request headers - to match. Multiple header values are ANDed together, - meaning, a request MUST match all the specified - headers. - items: - description: HeaderMatch defines the match attributes - within the HTTP Headers of the request. - properties: - name: - description: Name of the HTTP header. - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: Type specifies how to match against - the value of the header. - enum: - - Exact - - RegularExpression - - Distinct - type: string - value: - description: Value within the HTTP header. Due - to the case-insensitivity of header names, - "foo" and "Foo" are considered equivalent. - Do not set this field when Type="Distinct", - implying matching on any/all unique values - within the header. - maxLength: 1024 - type: string - required: - - name - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - sourceCIDR: - description: SourceCIDR is the client IP Address range - to match on. - properties: - type: - default: Exact - type: string - value: - description: Value is the IP CIDR that represents - the range of Source IP Addresses of the client. - These could also be the intermediate addresses - through which the request has flown through - and is part of the `X-Forwarded-For` header. - For example, `192.168.0.1/32`, `192.168.0.0/24`, - `001:db8::/64`. - maxLength: 256 - minLength: 1 - type: string - required: - - value - type: object - type: object - maxItems: 8 - type: array - limit: - description: Limit holds the rate limit values. This limit - is applied for traffic flows when the selectors compute - to True, causing the request to be counted towards the - limit. The limit is enforced and the request is ratelimited, - i.e. a response with 429 HTTP status code is sent back - to the client when the selected requests have reached - the limit. - properties: - requests: - type: integer - unit: - description: RateLimitUnit specifies the intervals for - setting rate limits. Valid RateLimitUnit values are - "Second", "Minute", "Hour", and "Day". - enum: - - Second - - Minute - - Hour - - Day - type: string - required: - - requests - - unit - type: object - required: - - limit - type: object - maxItems: 16 - type: array - required: - - rules - type: object - type: - description: Type decides the scope for the RateLimits. Valid RateLimitType - values are "Global". - enum: - - Global - type: string - required: - - type - type: object - required: - - spec - type: object - served: true - storage: true - subresources: {} diff --git a/internal/cmd/egctl/testdata/translate/in/rate-limit-filter-single-route-single-match-to-xds.yaml b/internal/cmd/egctl/testdata/translate/in/rate-limit-filter-single-route-single-match-to-xds.yaml deleted file mode 100644 index af4c794e82a..00000000000 --- a/internal/cmd/egctl/testdata/translate/in/rate-limit-filter-single-route-single-match-to-xds.yaml +++ /dev/null @@ -1,113 +0,0 @@ -apiVersion: gateway.networking.k8s.io/v1 -kind: GatewayClass -metadata: - name: eg -spec: - controllerName: gateway.envoyproxy.io/gatewayclass-controller ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: Gateway -metadata: - name: eg -spec: - gatewayClassName: eg - listeners: - - name: http - protocol: HTTP - port: 80 ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: backend ---- -apiVersion: v1 -kind: Service -metadata: - name: backend - labels: - app: backend - service: backend -spec: - clusterIP: 7.7.7.7 - ports: - - name: http - port: 3000 - targetPort: 3000 - selector: - app: backend ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: backend -spec: - replicas: 1 - selector: - matchLabels: - app: backend - version: v1 - template: - metadata: - labels: - app: backend - version: v1 - spec: - serviceAccountName: backend - containers: - - image: gcr.io/k8s-staging-ingressconformance/echoserver:v20221109-7ee2f3e - imagePullPolicy: IfNotPresent - name: backend - ports: - - containerPort: 3000 - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace ---- -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: RateLimitFilter -metadata: - name: ratelimit-specific-user -spec: - type: Global - global: - rules: - - clientSelectors: - - headers: - - name: x-user-id - value: one - limit: - requests: 3 - unit: Hour ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: http-ratelimit -spec: - parentRefs: - - name: eg - hostnames: - - "ratelimit.example" - rules: - - matches: - - path: - type: PathPrefix - value: / - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: ratelimit-specific-user - backendRefs: - - group: "" - kind: Service - name: backend - port: 3000 diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.json b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.json deleted file mode 100644 index 144c585d40f..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.json +++ /dev/null @@ -1,512 +0,0 @@ -{ - "xds": { - "envoy-gateway-system/eg": { - "configs": [ - { - "@type": "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump", - "bootstrap": { - "admin": { - "accessLog": [ - { - "name": "envoy.access_loggers.file", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog", - "path": "/dev/null" - } - } - ], - "address": { - "socketAddress": { - "address": "127.0.0.1", - "portValue": 19000 - } - } - }, - "dynamicResources": { - "adsConfig": { - "apiType": "DELTA_GRPC", - "grpcServices": [ - { - "envoyGrpc": { - "clusterName": "xds_cluster" - } - } - ], - "setNodeOnFirstMessageOnly": true, - "transportApiVersion": "V3" - }, - "cdsConfig": { - "ads": {}, - "resourceApiVersion": "V3" - }, - "ldsConfig": { - "ads": {}, - "resourceApiVersion": "V3" - } - }, - "staticResources": { - "clusters": [ - { - "connectTimeout": "0.250s", - "loadAssignment": { - "clusterName": "prometheus_stats", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "127.0.0.1", - "portValue": 19000 - } - } - } - } - ] - } - ] - }, - "name": "prometheus_stats", - "type": "STATIC" - }, - { - "connectTimeout": "10s", - "http2ProtocolOptions": { - "connectionKeepalive": { - "interval": "30s", - "timeout": "5s" - } - }, - "loadAssignment": { - "clusterName": "xds_cluster", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "envoy-gateway", - "portValue": 18000 - } - } - }, - "loadBalancingWeight": 1 - } - ], - "loadBalancingWeight": 1 - } - ] - }, - "name": "xds_cluster", - "transportSocket": { - "name": "envoy.transport_sockets.tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", - "commonTlsContext": { - "tlsCertificateSdsSecretConfigs": [ - { - "name": "xds_certificate", - "sdsConfig": { - "pathConfigSource": { - "path": "/sds/xds-certificate.json" - }, - "resourceApiVersion": "V3" - } - } - ], - "tlsParams": { - "tlsMaximumProtocolVersion": "TLSv1_3" - }, - "validationContextSdsSecretConfig": { - "name": "xds_trusted_ca", - "sdsConfig": { - "pathConfigSource": { - "path": "/sds/xds-trusted-ca.json" - }, - "resourceApiVersion": "V3" - } - } - } - } - }, - "type": "STRICT_DNS", - "typedExtensionProtocolOptions": { - "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": { - "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions", - "explicitHttpConfig": { - "http2ProtocolOptions": {} - } - } - } - } - ], - "listeners": [ - { - "address": { - "socketAddress": { - "address": "0.0.0.0", - "portValue": 19001 - } - }, - "filterChains": [ - { - "filters": [ - { - "name": "envoy.filters.network.http_connection_manager", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", - "httpFilters": [ - { - "name": "envoy.filters.http.health_check", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck", - "headers": [ - { - "name": ":path", - "stringMatch": { - "exact": "/ready" - } - } - ], - "passThroughMode": false - } - }, - { - "name": "envoy.filters.http.router", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" - } - } - ], - "routeConfig": { - "name": "local_route", - "virtualHosts": [ - { - "domains": [ - "*" - ], - "name": "prometheus_stats", - "routes": [ - { - "match": { - "prefix": "/stats/prometheus" - }, - "route": { - "cluster": "prometheus_stats" - } - } - ] - } - ] - }, - "statPrefix": "eg-ready-http" - } - } - ] - } - ], - "name": "envoy-gateway-proxy-ready-0.0.0.0-19001" - } - ] - } - } - }, - { - "@type": "type.googleapis.com/envoy.admin.v3.EndpointsConfigDump", - "dynamicEndpointConfigs": [ - { - "endpointConfig": { - "@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment", - "clusterName": "httproute/envoy-gateway-system/http-ratelimit/rule/0", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "7.7.7.7", - "portValue": 3000 - } - } - }, - "loadBalancingWeight": 1 - } - ], - "loadBalancingWeight": 1, - "locality": {} - } - ] - } - } - ] - }, - { - "@type": "type.googleapis.com/envoy.admin.v3.ClustersConfigDump", - "dynamicActiveClusters": [ - { - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "commonLbConfig": { - "localityWeightedLbConfig": {} - }, - "connectTimeout": "10s", - "dnsLookupFamily": "V4_ONLY", - "edsClusterConfig": { - "edsConfig": { - "ads": {}, - "resourceApiVersion": "V3" - }, - "serviceName": "httproute/envoy-gateway-system/http-ratelimit/rule/0" - }, - "lbPolicy": "LEAST_REQUEST", - "name": "httproute/envoy-gateway-system/http-ratelimit/rule/0", - "outlierDetection": {}, - "perConnectionBufferLimitBytes": 32768, - "type": "EDS" - } - }, - { - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "commonLbConfig": { - "localityWeightedLbConfig": {} - }, - "connectTimeout": "10s", - "dnsLookupFamily": "V4_ONLY", - "dnsRefreshRate": "30s", - "lbPolicy": "LEAST_REQUEST", - "loadAssignment": { - "clusterName": "ratelimit_cluster", - "endpoints": [ - { - "lbEndpoints": [ - { - "endpoint": { - "address": { - "socketAddress": { - "address": "envoy-ratelimit.envoy-gateway.svc.cluster.local", - "portValue": 8081 - } - } - }, - "loadBalancingWeight": 1 - } - ], - "loadBalancingWeight": 1, - "locality": {} - } - ] - }, - "name": "ratelimit_cluster", - "outlierDetection": {}, - "perConnectionBufferLimitBytes": 32768, - "respectDnsTtl": true, - "transportSocket": { - "name": "envoy.transport_sockets.tls", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", - "commonTlsContext": { - "tlsCertificates": [ - { - "certificateChain": { - "filename": "/certs/tls.crt" - }, - "privateKey": { - "filename": "/certs/tls.key" - } - } - ], - "validationContext": { - "trustedCa": { - "filename": "/certs/ca.crt" - } - } - } - } - }, - "type": "STRICT_DNS", - "typedExtensionProtocolOptions": { - "envoy.extensions.upstreams.http.v3.HttpProtocolOptions": { - "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions", - "explicitHttpConfig": { - "http2ProtocolOptions": {} - } - } - } - } - } - ] - }, - { - "@type": "type.googleapis.com/envoy.admin.v3.ListenersConfigDump", - "dynamicListeners": [ - { - "activeState": { - "listener": { - "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", - "accessLog": [ - { - "filter": { - "responseFlagFilter": { - "flags": [ - "NR" - ] - } - }, - "name": "envoy.access_loggers.file", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog", - "logFormat": { - "textFormatSource": { - "inlineString": "{\"start_time\":\"%START_TIME%\",\"method\":\"%REQ(:METHOD)%\",\"x-envoy-origin-path\":\"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%\",\"protocol\":\"%PROTOCOL%\",\"response_code\":\"%RESPONSE_CODE%\",\"response_flags\":\"%RESPONSE_FLAGS%\",\"response_code_details\":\"%RESPONSE_CODE_DETAILS%\",\"connection_termination_details\":\"%CONNECTION_TERMINATION_DETAILS%\",\"upstream_transport_failure_reason\":\"%UPSTREAM_TRANSPORT_FAILURE_REASON%\",\"bytes_received\":\"%BYTES_RECEIVED%\",\"bytes_sent\":\"%BYTES_SENT%\",\"duration\":\"%DURATION%\",\"x-envoy-upstream-service-time\":\"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%\",\"x-forwarded-for\":\"%REQ(X-FORWARDED-FOR)%\",\"user-agent\":\"%REQ(USER-AGENT)%\",\"x-request-id\":\"%REQ(X-REQUEST-ID)%\",\":authority\":\"%REQ(:AUTHORITY)%\",\"upstream_host\":\"%UPSTREAM_HOST%\",\"upstream_cluster\":\"%UPSTREAM_CLUSTER%\",\"upstream_local_address\":\"%UPSTREAM_LOCAL_ADDRESS%\",\"downstream_local_address\":\"%DOWNSTREAM_LOCAL_ADDRESS%\",\"downstream_remote_address\":\"%DOWNSTREAM_REMOTE_ADDRESS%\",\"requested_server_name\":\"%REQUESTED_SERVER_NAME%\",\"route_name\":\"%ROUTE_NAME%\"}\n" - } - }, - "path": "/dev/stdout" - } - } - ], - "address": { - "socketAddress": { - "address": "0.0.0.0", - "portValue": 10080 - } - }, - "defaultFilterChain": { - "filters": [ - { - "name": "envoy.filters.network.http_connection_manager", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", - "accessLog": [ - { - "name": "envoy.access_loggers.file", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog", - "logFormat": { - "textFormatSource": { - "inlineString": "{\"start_time\":\"%START_TIME%\",\"method\":\"%REQ(:METHOD)%\",\"x-envoy-origin-path\":\"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%\",\"protocol\":\"%PROTOCOL%\",\"response_code\":\"%RESPONSE_CODE%\",\"response_flags\":\"%RESPONSE_FLAGS%\",\"response_code_details\":\"%RESPONSE_CODE_DETAILS%\",\"connection_termination_details\":\"%CONNECTION_TERMINATION_DETAILS%\",\"upstream_transport_failure_reason\":\"%UPSTREAM_TRANSPORT_FAILURE_REASON%\",\"bytes_received\":\"%BYTES_RECEIVED%\",\"bytes_sent\":\"%BYTES_SENT%\",\"duration\":\"%DURATION%\",\"x-envoy-upstream-service-time\":\"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%\",\"x-forwarded-for\":\"%REQ(X-FORWARDED-FOR)%\",\"user-agent\":\"%REQ(USER-AGENT)%\",\"x-request-id\":\"%REQ(X-REQUEST-ID)%\",\":authority\":\"%REQ(:AUTHORITY)%\",\"upstream_host\":\"%UPSTREAM_HOST%\",\"upstream_cluster\":\"%UPSTREAM_CLUSTER%\",\"upstream_local_address\":\"%UPSTREAM_LOCAL_ADDRESS%\",\"downstream_local_address\":\"%DOWNSTREAM_LOCAL_ADDRESS%\",\"downstream_remote_address\":\"%DOWNSTREAM_REMOTE_ADDRESS%\",\"requested_server_name\":\"%REQUESTED_SERVER_NAME%\",\"route_name\":\"%ROUTE_NAME%\"}\n" - } - }, - "path": "/dev/stdout" - } - } - ], - "commonHttpProtocolOptions": { - "headersWithUnderscoresAction": "REJECT_REQUEST" - }, - "http2ProtocolOptions": { - "initialConnectionWindowSize": 1048576, - "initialStreamWindowSize": 65536, - "maxConcurrentStreams": 100 - }, - "httpFilters": [ - { - "name": "envoy.filters.http.ratelimit", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit", - "domain": "envoy-gateway-system/eg/http", - "enableXRatelimitHeaders": "DRAFT_VERSION_03", - "rateLimitService": { - "grpcService": { - "envoyGrpc": { - "clusterName": "ratelimit_cluster" - } - }, - "transportApiVersion": "V3" - } - } - }, - { - "name": "envoy.filters.http.router", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router" - } - } - ], - "mergeSlashes": true, - "normalizePath": true, - "pathWithEscapedSlashesAction": "UNESCAPE_AND_REDIRECT", - "rds": { - "configSource": { - "ads": {}, - "resourceApiVersion": "V3" - }, - "routeConfigName": "envoy-gateway-system/eg/http" - }, - "statPrefix": "http", - "upgradeConfigs": [ - { - "upgradeType": "websocket" - } - ], - "useRemoteAddress": true - } - } - ] - }, - "name": "envoy-gateway-system/eg/http", - "perConnectionBufferLimitBytes": 32768 - } - } - } - ] - }, - { - "@type": "type.googleapis.com/envoy.admin.v3.RoutesConfigDump", - "dynamicRouteConfigs": [ - { - "routeConfig": { - "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", - "ignorePortInHostMatching": true, - "name": "envoy-gateway-system/eg/http", - "virtualHosts": [ - { - "domains": [ - "ratelimit.example" - ], - "name": "envoy-gateway-system/eg/http/ratelimit_example", - "routes": [ - { - "match": { - "prefix": "/" - }, - "name": "httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example", - "route": { - "cluster": "httproute/envoy-gateway-system/http-ratelimit/rule/0", - "rateLimits": [ - { - "actions": [ - { - "headerValueMatch": { - "descriptorKey": "httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-key-rule-0-match-0", - "descriptorValue": "httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-value-rule-0-match-0", - "expectMatch": true, - "headers": [ - { - "name": "x-user-id", - "stringMatch": { - "exact": "one" - } - } - ] - } - } - ] - } - ] - } - } - ] - } - ] - } - } - ] - } - ] - } - } -} \ No newline at end of file diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.yaml deleted file mode 100644 index 8168cf49122..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.all.yaml +++ /dev/null @@ -1,292 +0,0 @@ -xds: - envoy-gateway-system/eg: - configs: - - '@type': type.googleapis.com/envoy.admin.v3.BootstrapConfigDump - bootstrap: - admin: - accessLog: - - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - path: /dev/null - address: - socketAddress: - address: 127.0.0.1 - portValue: 19000 - dynamicResources: - adsConfig: - apiType: DELTA_GRPC - grpcServices: - - envoyGrpc: - clusterName: xds_cluster - setNodeOnFirstMessageOnly: true - transportApiVersion: V3 - cdsConfig: - ads: {} - resourceApiVersion: V3 - ldsConfig: - ads: {} - resourceApiVersion: V3 - staticResources: - clusters: - - connectTimeout: 0.250s - loadAssignment: - clusterName: prometheus_stats - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 127.0.0.1 - portValue: 19000 - name: prometheus_stats - type: STATIC - - connectTimeout: 10s - http2ProtocolOptions: - connectionKeepalive: - interval: 30s - timeout: 5s - loadAssignment: - clusterName: xds_cluster - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: envoy-gateway - portValue: 18000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - name: xds_cluster - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - tlsCertificateSdsSecretConfigs: - - name: xds_certificate - sdsConfig: - pathConfigSource: - path: /sds/xds-certificate.json - resourceApiVersion: V3 - tlsParams: - tlsMaximumProtocolVersion: TLSv1_3 - validationContextSdsSecretConfig: - name: xds_trusted_ca - sdsConfig: - pathConfigSource: - path: /sds/xds-trusted-ca.json - resourceApiVersion: V3 - type: STRICT_DNS - typedExtensionProtocolOptions: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicitHttpConfig: - http2ProtocolOptions: {} - listeners: - - address: - socketAddress: - address: 0.0.0.0 - portValue: 19001 - filterChains: - - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - httpFilters: - - name: envoy.filters.http.health_check - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck - headers: - - name: :path - stringMatch: - exact: /ready - passThroughMode: false - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - routeConfig: - name: local_route - virtualHosts: - - domains: - - '*' - name: prometheus_stats - routes: - - match: - prefix: /stats/prometheus - route: - cluster: prometheus_stats - statPrefix: eg-ready-http - name: envoy-gateway-proxy-ready-0.0.0.0-19001 - - '@type': type.googleapis.com/envoy.admin.v3.EndpointsConfigDump - dynamicEndpointConfigs: - - endpointConfig: - '@type': type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment - clusterName: httproute/envoy-gateway-system/http-ratelimit/rule/0 - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 7.7.7.7 - portValue: 3000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - - '@type': type.googleapis.com/envoy.admin.v3.ClustersConfigDump - dynamicActiveClusters: - - cluster: - '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster - commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: httproute/envoy-gateway-system/http-ratelimit/rule/0 - lbPolicy: LEAST_REQUEST - name: httproute/envoy-gateway-system/http-ratelimit/rule/0 - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS - - cluster: - '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster - commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: ratelimit_cluster - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: envoy-ratelimit.envoy-gateway.svc.cluster.local - portValue: 8081 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: ratelimit_cluster - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - tlsCertificates: - - certificateChain: - filename: /certs/tls.crt - privateKey: - filename: /certs/tls.key - validationContext: - trustedCa: - filename: /certs/ca.crt - type: STRICT_DNS - typedExtensionProtocolOptions: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicitHttpConfig: - http2ProtocolOptions: {} - - '@type': type.googleapis.com/envoy.admin.v3.ListenersConfigDump - dynamicListeners: - - activeState: - listener: - '@type': type.googleapis.com/envoy.config.listener.v3.Listener - accessLog: - - filter: - responseFlagFilter: - flags: - - NR - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - accessLog: - - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.ratelimit - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit - domain: envoy-gateway-system/eg/http - enableXRatelimitHeaders: DRAFT_VERSION_03 - rateLimitService: - grpcService: - envoyGrpc: - clusterName: ratelimit_cluster - transportApiVersion: V3 - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: envoy-gateway-system/eg/http - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: envoy-gateway-system/eg/http - perConnectionBufferLimitBytes: 32768 - - '@type': type.googleapis.com/envoy.admin.v3.RoutesConfigDump - dynamicRouteConfigs: - - routeConfig: - '@type': type.googleapis.com/envoy.config.route.v3.RouteConfiguration - ignorePortInHostMatching: true - name: envoy-gateway-system/eg/http - virtualHosts: - - domains: - - ratelimit.example - name: envoy-gateway-system/eg/http/ratelimit_example - routes: - - match: - prefix: / - name: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example - route: - cluster: httproute/envoy-gateway-system/http-ratelimit/rule/0 - rateLimits: - - actions: - - headerValueMatch: - descriptorKey: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-key-rule-0-match-0 - descriptorValue: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-value-rule-0-match-0 - expectMatch: true - headers: - - name: x-user-id - stringMatch: - exact: one diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.bootstrap.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.bootstrap.yaml deleted file mode 100644 index 169f3f954c6..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.bootstrap.yaml +++ /dev/null @@ -1,119 +0,0 @@ -xds: - envoy-gateway-system/eg: - '@type': type.googleapis.com/envoy.admin.v3.BootstrapConfigDump - bootstrap: - admin: - accessLog: - - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - path: /dev/null - address: - socketAddress: - address: 127.0.0.1 - portValue: 19000 - dynamicResources: - adsConfig: - apiType: DELTA_GRPC - grpcServices: - - envoyGrpc: - clusterName: xds_cluster - setNodeOnFirstMessageOnly: true - transportApiVersion: V3 - cdsConfig: - ads: {} - resourceApiVersion: V3 - ldsConfig: - ads: {} - resourceApiVersion: V3 - staticResources: - clusters: - - connectTimeout: 0.250s - loadAssignment: - clusterName: prometheus_stats - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 127.0.0.1 - portValue: 19000 - name: prometheus_stats - type: STATIC - - connectTimeout: 10s - http2ProtocolOptions: - connectionKeepalive: - interval: 30s - timeout: 5s - loadAssignment: - clusterName: xds_cluster - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: envoy-gateway - portValue: 18000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - name: xds_cluster - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - tlsCertificateSdsSecretConfigs: - - name: xds_certificate - sdsConfig: - pathConfigSource: - path: /sds/xds-certificate.json - resourceApiVersion: V3 - tlsParams: - tlsMaximumProtocolVersion: TLSv1_3 - validationContextSdsSecretConfig: - name: xds_trusted_ca - sdsConfig: - pathConfigSource: - path: /sds/xds-trusted-ca.json - resourceApiVersion: V3 - type: STRICT_DNS - typedExtensionProtocolOptions: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicitHttpConfig: - http2ProtocolOptions: {} - listeners: - - address: - socketAddress: - address: 0.0.0.0 - portValue: 19001 - filterChains: - - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - httpFilters: - - name: envoy.filters.http.health_check - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck - headers: - - name: :path - stringMatch: - exact: /ready - passThroughMode: false - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - routeConfig: - name: local_route - virtualHosts: - - domains: - - '*' - name: prometheus_stats - routes: - - match: - prefix: /stats/prometheus - route: - cluster: prometheus_stats - statPrefix: eg-ready-http - name: envoy-gateway-proxy-ready-0.0.0.0-19001 diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.cluster.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.cluster.yaml deleted file mode 100644 index 2bcdcb87388..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.cluster.yaml +++ /dev/null @@ -1,63 +0,0 @@ -xds: - envoy-gateway-system/eg: - '@type': type.googleapis.com/envoy.admin.v3.ClustersConfigDump - dynamicActiveClusters: - - cluster: - '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster - commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - edsClusterConfig: - edsConfig: - ads: {} - resourceApiVersion: V3 - serviceName: httproute/envoy-gateway-system/http-ratelimit/rule/0 - lbPolicy: LEAST_REQUEST - name: httproute/envoy-gateway-system/http-ratelimit/rule/0 - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - type: EDS - - cluster: - '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster - commonLbConfig: - localityWeightedLbConfig: {} - connectTimeout: 10s - dnsLookupFamily: V4_ONLY - dnsRefreshRate: 30s - lbPolicy: LEAST_REQUEST - loadAssignment: - clusterName: ratelimit_cluster - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: envoy-ratelimit.envoy-gateway.svc.cluster.local - portValue: 8081 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} - name: ratelimit_cluster - outlierDetection: {} - perConnectionBufferLimitBytes: 32768 - respectDnsTtl: true - transportSocket: - name: envoy.transport_sockets.tls - typedConfig: - '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - commonTlsContext: - tlsCertificates: - - certificateChain: - filename: /certs/tls.crt - privateKey: - filename: /certs/tls.key - validationContext: - trustedCa: - filename: /certs/ca.crt - type: STRICT_DNS - typedExtensionProtocolOptions: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicitHttpConfig: - http2ProtocolOptions: {} diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.endpoint.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.endpoint.yaml deleted file mode 100644 index d30d56266be..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.endpoint.yaml +++ /dev/null @@ -1,17 +0,0 @@ -xds: - envoy-gateway-system/eg: - '@type': type.googleapis.com/envoy.admin.v3.EndpointsConfigDump - dynamicEndpointConfigs: - - endpointConfig: - '@type': type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment - clusterName: httproute/envoy-gateway-system/http-ratelimit/rule/0 - endpoints: - - lbEndpoints: - - endpoint: - address: - socketAddress: - address: 7.7.7.7 - portValue: 3000 - loadBalancingWeight: 1 - loadBalancingWeight: 1 - locality: {} diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.listener.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.listener.yaml deleted file mode 100644 index 112a3fd288f..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.listener.yaml +++ /dev/null @@ -1,72 +0,0 @@ -xds: - envoy-gateway-system/eg: - '@type': type.googleapis.com/envoy.admin.v3.ListenersConfigDump - dynamicListeners: - - activeState: - listener: - '@type': type.googleapis.com/envoy.config.listener.v3.Listener - accessLog: - - filter: - responseFlagFilter: - flags: - - NR - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - address: - socketAddress: - address: 0.0.0.0 - portValue: 10080 - defaultFilterChain: - filters: - - name: envoy.filters.network.http_connection_manager - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - accessLog: - - name: envoy.access_loggers.file - typedConfig: - '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog - logFormat: - textFormatSource: - inlineString: | - {"start_time":"%START_TIME%","method":"%REQ(:METHOD)%","x-envoy-origin-path":"%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%","protocol":"%PROTOCOL%","response_code":"%RESPONSE_CODE%","response_flags":"%RESPONSE_FLAGS%","response_code_details":"%RESPONSE_CODE_DETAILS%","connection_termination_details":"%CONNECTION_TERMINATION_DETAILS%","upstream_transport_failure_reason":"%UPSTREAM_TRANSPORT_FAILURE_REASON%","bytes_received":"%BYTES_RECEIVED%","bytes_sent":"%BYTES_SENT%","duration":"%DURATION%","x-envoy-upstream-service-time":"%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%","x-forwarded-for":"%REQ(X-FORWARDED-FOR)%","user-agent":"%REQ(USER-AGENT)%","x-request-id":"%REQ(X-REQUEST-ID)%",":authority":"%REQ(:AUTHORITY)%","upstream_host":"%UPSTREAM_HOST%","upstream_cluster":"%UPSTREAM_CLUSTER%","upstream_local_address":"%UPSTREAM_LOCAL_ADDRESS%","downstream_local_address":"%DOWNSTREAM_LOCAL_ADDRESS%","downstream_remote_address":"%DOWNSTREAM_REMOTE_ADDRESS%","requested_server_name":"%REQUESTED_SERVER_NAME%","route_name":"%ROUTE_NAME%"} - path: /dev/stdout - commonHttpProtocolOptions: - headersWithUnderscoresAction: REJECT_REQUEST - http2ProtocolOptions: - initialConnectionWindowSize: 1048576 - initialStreamWindowSize: 65536 - maxConcurrentStreams: 100 - httpFilters: - - name: envoy.filters.http.ratelimit - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit - domain: envoy-gateway-system/eg/http - enableXRatelimitHeaders: DRAFT_VERSION_03 - rateLimitService: - grpcService: - envoyGrpc: - clusterName: ratelimit_cluster - transportApiVersion: V3 - - name: envoy.filters.http.router - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - mergeSlashes: true - normalizePath: true - pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT - rds: - configSource: - ads: {} - resourceApiVersion: V3 - routeConfigName: envoy-gateway-system/eg/http - statPrefix: http - upgradeConfigs: - - upgradeType: websocket - useRemoteAddress: true - name: envoy-gateway-system/eg/http - perConnectionBufferLimitBytes: 32768 diff --git a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.route.yaml b/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.route.yaml deleted file mode 100644 index 91c3754dd2a..00000000000 --- a/internal/cmd/egctl/testdata/translate/out/rate-limit-filter-single-route-single-match-to-xds.route.yaml +++ /dev/null @@ -1,28 +0,0 @@ -xds: - envoy-gateway-system/eg: - '@type': type.googleapis.com/envoy.admin.v3.RoutesConfigDump - dynamicRouteConfigs: - - routeConfig: - '@type': type.googleapis.com/envoy.config.route.v3.RouteConfiguration - ignorePortInHostMatching: true - name: envoy-gateway-system/eg/http - virtualHosts: - - domains: - - ratelimit.example - name: envoy-gateway-system/eg/http/ratelimit_example - routes: - - match: - prefix: / - name: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example - route: - cluster: httproute/envoy-gateway-system/http-ratelimit/rule/0 - rateLimits: - - actions: - - headerValueMatch: - descriptorKey: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-key-rule-0-match-0 - descriptorValue: httproute/envoy-gateway-system/http-ratelimit/rule/0/match/0/ratelimit_example-value-rule-0-match-0 - expectMatch: true - headers: - - name: x-user-id - stringMatch: - exact: one diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go index c46be9a8495..5850f96a1fa 100644 --- a/internal/cmd/egctl/translate.go +++ b/internal/cmd/egctl/translate.go @@ -766,20 +766,6 @@ func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayap Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec), } resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy) - case egv1a1.KindRateLimitFilter: - typedSpec := spec.Interface() - rateLimitFilter := &egv1a1.RateLimitFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindRateLimitFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - }, - Spec: typedSpec.(egv1a1.RateLimitFilterSpec), - } - resources.RateLimitFilters = append(resources.RateLimitFilters, rateLimitFilter) } } diff --git a/internal/cmd/egctl/translate_test.go b/internal/cmd/egctl/translate_test.go index 4b13327b682..03ab44345a1 100644 --- a/internal/cmd/egctl/translate_test.go +++ b/internal/cmd/egctl/translate_test.go @@ -186,83 +186,6 @@ func TestTranslate(t *testing.T) { resourceType: string(AllEnvoyConfigType), expect: true, }, - { - - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: jsonOutput, - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: "unknown", - expect: false, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(AllEnvoyConfigType), - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(BootstrapEnvoyConfigType), - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(ClusterEnvoyConfigType), - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(ListenerEnvoyConfigType), - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(RouteEnvoyConfigType), - expect: true, - }, - { - name: "rate-limit-filter-single-route-single-match-to-xds", - from: "gateway-api", - to: "xds", - output: yamlOutput, - resourceType: string(EndpointEnvoyConfigType), - expect: true, - }, { name: "default-resources", from: "gateway-api", diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index a701b801080..961b2fd6ec4 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -7,7 +7,6 @@ package gatewayapi import ( "fmt" - "net" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -59,7 +58,6 @@ type HTTPFilterIR struct { Mirrors []*ir.RouteDestination RequestAuthentication *ir.RequestAuthentication - RateLimit *ir.RateLimit ExtensionRefs []*ir.UnstructuredRef } @@ -679,102 +677,6 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec } } - // Set the filter context and return early if a matching RateLimitFilter is found. - if string(extFilter.Kind) == egv1a1.KindRateLimitFilter { - for _, rateLimitFilter := range resources.RateLimitFilters { - if rateLimitFilter.Namespace == filterNs && - rateLimitFilter.Name == string(extFilter.Name) { - if rateLimitFilter.Spec.Global == nil { - errMsg := fmt.Sprintf("Global configuration empty for RateLimitFilter: %s/%s", filterNs, - extFilter.Name) - t.processUnresolvedHTTPFilter(errMsg, filterContext) - return - } - if !t.GlobalRateLimitEnabled { - errMsg := fmt.Sprintf("Enable Ratelimit in the EnvoyGateway config to configure RateLimitFilter: %s/%s", - filterNs, extFilter.Name) - t.processUnresolvedHTTPFilter(errMsg, filterContext) - return - } - rateLimit := &ir.RateLimit{ - Global: &ir.GlobalRateLimit{ - Rules: make([]*ir.RateLimitRule, len(rateLimitFilter.Spec.Global.Rules)), - }, - } - rules := rateLimit.Global.Rules - for i, rule := range rateLimitFilter.Spec.Global.Rules { - rules[i] = &ir.RateLimitRule{ - Limit: &ir.RateLimitValue{ - Requests: rule.Limit.Requests, - Unit: ir.RateLimitUnit(rule.Limit.Unit), - }, - HeaderMatches: make([]*ir.StringMatch, 0), - } - for _, match := range rule.ClientSelectors { - for _, header := range match.Headers { - switch { - case header.Type == nil && header.Value != nil: - fallthrough - case *header.Type == egv1a1.HeaderMatchExact && header.Value != nil: - m := &ir.StringMatch{ - Name: header.Name, - Exact: header.Value, - } - rules[i].HeaderMatches = append(rules[i].HeaderMatches, m) - case *header.Type == egv1a1.HeaderMatchRegularExpression && header.Value != nil: - m := &ir.StringMatch{ - Name: header.Name, - SafeRegex: header.Value, - } - rules[i].HeaderMatches = append(rules[i].HeaderMatches, m) - case *header.Type == egv1a1.HeaderMatchDistinct && header.Value == nil: - m := &ir.StringMatch{ - Name: header.Name, - Distinct: true, - } - rules[i].HeaderMatches = append(rules[i].HeaderMatches, m) - default: - // set negative status condition. - errMsg := fmt.Sprintf("Unable to translate RateLimitFilter. Either the header.Type is not valid or the header is missing a value: %s/%s", filterNs, - extFilter.Name) - t.processUnresolvedHTTPFilter(errMsg, filterContext) - return - } - } - - if match.SourceCIDR != nil { - // distinct means that each IP Address within the specified Source IP CIDR is treated as a - // distinct client selector and uses a separate rate limit bucket/counter. - distinct := false - sourceCIDR := match.SourceCIDR.Value - if match.SourceCIDR.Type != nil && *match.SourceCIDR.Type == egv1a1.SourceMatchDistinct { - distinct = true - } - - ip, ipn, err := net.ParseCIDR(sourceCIDR) - if err != nil { - errMsg := fmt.Sprintf("Unable to translate RateLimitFilter: %s/%s", filterNs, - extFilter.Name) - t.processUnresolvedHTTPFilter(errMsg, filterContext) - return - } - - mask, _ := ipn.Mask.Size() - rules[i].CIDRMatch = &ir.CIDRMatch{ - CIDR: ipn.String(), - IPv6: ip.To4() == nil, - MaskLen: mask, - Distinct: distinct, - } - } - } - } - filterContext.HTTPFilterIR.RateLimit = rateLimit - return - } - } - } - // This list of resources will be empty unless an extension is loaded (and introduces resources) for _, res := range resources.ExtensionRefFilters { if res.GetKind() == string(extFilter.Kind) && res.GetName() == string(extFilter.Name) && res.GetNamespace() == filterNs { diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index f9a6732dbae..fc221085af3 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -192,9 +192,6 @@ func ValidateHTTPRouteFilter(filter *gwapiv1.HTTPRouteFilter, extGKs ...schema.G case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter: return nil - case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindRateLimitFilter: - return nil default: for _, gk := range extGKs { if filter.ExtensionRef.Group == gwapiv1.Group(gk.Group) && @@ -217,14 +214,6 @@ func IsAuthnHTTPFilter(filter *gwapiv1.HTTPRouteFilter) bool { string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter } -// IsRateLimitHTTPFilter returns true if the provided filter is a RateLimitFilter. -func IsRateLimitHTTPFilter(filter *gwapiv1.HTTPRouteFilter) bool { - return filter.Type == gwapiv1.HTTPRouteFilterExtensionRef && - filter.ExtensionRef != nil && - string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindRateLimitFilter -} - // ValidateGRPCRouteFilter validates the provided filter within GRPCRoute. func ValidateGRPCRouteFilter(filter *v1alpha2.GRPCRouteFilter, extGKs ...schema.GroupKind) error { switch { @@ -241,9 +230,6 @@ func ValidateGRPCRouteFilter(filter *v1alpha2.GRPCRouteFilter, extGKs ...schema. case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter: return nil - case string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindRateLimitFilter: - return nil default: for _, gk := range extGKs { if filter.ExtensionRef.Group == gwapiv1.Group(gk.Group) && @@ -266,14 +252,6 @@ func IsAuthnGRPCFilter(filter *v1alpha2.GRPCRouteFilter) bool { string(filter.ExtensionRef.Kind) == egv1a1.KindAuthenticationFilter } -// IsRateLimitGRPCFilter returns true if the provided filter is an RateLimitFilter. -func IsRateLimitGRPCFilter(filter *v1alpha2.GRPCRouteFilter) bool { - return filter.Type == v1alpha2.GRPCRouteFilterExtensionRef && - filter.ExtensionRef != nil && - string(filter.ExtensionRef.Group) == egv1a1.GroupVersion.Group && - string(filter.ExtensionRef.Kind) == egv1a1.KindRateLimitFilter -} - // GatewayOwnerLabels returns the Gateway Owner labels using // the provided namespace and name as the values. func GatewayOwnerLabels(namespace, name string) map[string]string { diff --git a/internal/gatewayapi/helpers_test.go b/internal/gatewayapi/helpers_test.go index 426845870b4..6ded00f8c72 100644 --- a/internal/gatewayapi/helpers_test.go +++ b/internal/gatewayapi/helpers_test.go @@ -128,42 +128,6 @@ func TestValidateGRPCFilterRef(t *testing.T) { }, expected: true, }, - { - name: "invalid ratelimitfilter group", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: "UnsupportedGroup", - Kind: egv1a1.KindRateLimitFilter, - Name: "test", - }, - }, - expected: false, - }, - { - name: "invalid ratelimitfilter kind", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: "UnsupportedKind", - Name: "test", - }, - }, - expected: false, - }, - { - name: "valid ratelimitfilter", - filter: &gwapiv1a2.GRPCRouteFilter{ - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindRateLimitFilter, - Name: "test", - }, - }, - expected: true, - }, } for _, tc := range testCases { tc := tc @@ -267,18 +231,6 @@ func TestValidateHTTPFilterRef(t *testing.T) { }, expected: true, }, - { - name: "valid rateLimitfilter", - filter: &gwapiv1.HTTPRouteFilter{ - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: egv1a1.KindRateLimitFilter, - Name: "test", - }, - }, - expected: true, - }, { name: "valid extension resource", filter: &gwapiv1.HTTPRouteFilter{ diff --git a/internal/gatewayapi/resource.go b/internal/gatewayapi/resource.go index 318728afce7..6bd0fc4f696 100644 --- a/internal/gatewayapi/resource.go +++ b/internal/gatewayapi/resource.go @@ -41,7 +41,6 @@ type Resources struct { EndpointSlices []*discoveryv1.EndpointSlice `json:"endpointSlices,omitempty" yaml:"endpointSlices,omitempty"` Secrets []*v1.Secret `json:"secrets,omitempty" yaml:"secrets,omitempty"` AuthenticationFilters []*egv1a1.AuthenticationFilter `json:"authenticationFilters,omitempty" yaml:"authenticationFilters,omitempty"` - RateLimitFilters []*egv1a1.RateLimitFilter `json:"rateLimitFilters,omitempty" yaml:"rateLimitFilters,omitempty"` EnvoyProxy *egv1a1.EnvoyProxy `json:"envoyProxy,omitempty" yaml:"envoyProxy,omitempty"` ExtensionRefFilters []unstructured.Unstructured `json:"extensionRefFilters,omitempty" yaml:"extensionRefFilters,omitempty"` EnvoyPatchPolicies []*egv1a1.EnvoyPatchPolicy `json:"envoyPatchPolicies,omitempty" yaml:"envoyPatchPolicies,omitempty"` @@ -61,7 +60,6 @@ func NewResources() *Resources { Secrets: []*v1.Secret{}, ReferenceGrants: []*gwapiv1b1.ReferenceGrant{}, Namespaces: []*v1.Namespace{}, - RateLimitFilters: []*egv1a1.RateLimitFilter{}, AuthenticationFilters: []*egv1a1.AuthenticationFilter{}, ExtensionRefFilters: []unstructured.Unstructured{}, EnvoyPatchPolicies: []*egv1a1.EnvoyPatchPolicy{}, diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index fe0ec085def..fed00642f59 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -317,9 +317,6 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir if httpFiltersContext.RequestAuthentication != nil { irRoute.RequestAuthentication = httpFiltersContext.RequestAuthentication } - if httpFiltersContext.RateLimit != nil { - irRoute.RateLimit = httpFiltersContext.RateLimit - } if len(httpFiltersContext.ExtensionRefs) > 0 { irRoute.ExtensionRefs = httpFiltersContext.ExtensionRefs diff --git a/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.in.yaml b/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.in.yaml deleted file mode 100644 index 29ddd013056..00000000000 --- a/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.in.yaml +++ /dev/null @@ -1,55 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - allowedRoutes: - namespaces: - from: All -grpcRoutes: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: GRPCRoute - metadata: - namespace: default - name: grpcroute-1 - spec: - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - backendRefs: - - name: service-1 - port: 8080 -rateLimitFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: RateLimitFilter - metadata: - namespace: default - name: test - spec: - type: Global - global: - rules: - - clientSelectors: - - headers: - - name: x-user-id - value: one - - name: x-org-id - type: Distinct - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.out.yaml b/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.out.yaml deleted file mode 100644 index 704f48edb10..00000000000 --- a/internal/gatewayapi/testdata/grpcroute-with-valid-ratelimitfilter.out.yaml +++ /dev/null @@ -1,133 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -grpcRoutes: -- apiVersion: gateway.networking.k8s.io/v1alpha2 - kind: GRPCRoute - metadata: - creationTimestamp: null - name: grpcroute-1 - namespace: default - spec: - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - type: ExtensionRef - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: true - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: grpcroute/default/grpcroute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: '*' - name: grpcroute/default/grpcroute-1/rule/0/match/-1/* - rateLimit: - global: - rules: - - headerMatches: - - distinct: false - exact: one - name: x-user-id - - distinct: true - name: x-org-id - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.in.yaml b/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.in.yaml deleted file mode 100644 index c956ebc3117..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.in.yaml +++ /dev/null @@ -1,59 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test -rateLimitFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: RateLimitFilter - metadata: - name: test - namespace: default - spec: - type: Global - global: - rules: - - clientSelectors: - - sourceCIDR: - type: "Distinct" - value: 192.168.0.0/16 - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.out.yaml b/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.out.yaml deleted file mode 100644 index 556411900c9..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-distinct-sourcecidr-ratelimit.out.yaml +++ /dev/null @@ -1,143 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - name: "" - prefix: / - rateLimit: - global: - rules: - - cidrMatch: - cidr: 192.168.0.0/16 - distinct: true - ipv6: false - maskLen: 16 - headerMatches: [] - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.in.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.in.yaml deleted file mode 100644 index 1c0a11c7526..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.in.yaml +++ /dev/null @@ -1,60 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test -rateLimitFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: RateLimitFilter - metadata: - name: test - namespace: default - spec: - type: Global - global: - rules: - - clientSelectors: - - headers: - - type: Distinct - name: x-user-id - value: one - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.out.yaml deleted file mode 100644 index 4328150736a..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-invalid-ratelimitfilter.out.yaml +++ /dev/null @@ -1,116 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 0 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: 'Unable to translate RateLimitFilter. Either the header.Type is not - valid or the header is missing a value: default/test' - reason: UnsupportedValue - status: "False" - type: Accepted - - lastTransitionTime: null - message: 'Unable to translate RateLimitFilter. Either the header.Type is not - valid or the header is missing a value: default/test' - reason: BackendNotFound - status: "False" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 diff --git a/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.in.yaml b/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.in.yaml deleted file mode 100644 index 80512128a46..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.in.yaml +++ /dev/null @@ -1,58 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test -rateLimitFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: RateLimitFilter - metadata: - name: test - namespace: default - spec: - type: Global - global: - rules: - - clientSelectors: - - sourceCIDR: - value: 192.168.0.0/16 - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.out.yaml b/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.out.yaml deleted file mode 100644 index 3f80798c10a..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-sourcecidr-ratelimit.out.yaml +++ /dev/null @@ -1,143 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - name: "" - prefix: / - rateLimit: - global: - rules: - - cidrMatch: - cidr: 192.168.0.0/16 - distinct: false - ipv6: false - maskLen: 16 - headerMatches: [] - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.in.yaml b/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.in.yaml deleted file mode 100644 index 3d14a3e87a4..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.in.yaml +++ /dev/null @@ -1,61 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - namespace: envoy-gateway - name: gateway-1 - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - protocol: HTTP - port: 80 - hostname: "*.envoyproxy.io" - allowedRoutes: - namespaces: - from: All -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - namespace: default - name: httproute-1 - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - sectionName: http - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 - filters: - - type: ExtensionRef - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test -rateLimitFilters: -- apiVersion: gateway.envoyproxy.io/v1alpha1 - kind: RateLimitFilter - metadata: - name: test - namespace: default - spec: - type: Global - global: - rules: - - clientSelectors: - - headers: - - name: x-user-id - value: one - - name: x-org-id - type: Distinct - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.out.yaml b/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.out.yaml deleted file mode 100644 index b278efea178..00000000000 --- a/internal/gatewayapi/testdata/httproute-with-valid-ratelimitfilter.out.yaml +++ /dev/null @@ -1,143 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: All - hostname: '*.envoyproxy.io' - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 1 - conditions: - - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed - status: "True" - type: Programmed - - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Listener references have been resolved - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - name: http - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: default - spec: - hostnames: - - gateway.envoyproxy.io - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - sectionName: http - rules: - - backendRefs: - - name: service-1 - port: 8080 - filters: - - extensionRef: - group: gateway.envoyproxy.io - kind: RateLimitFilter - name: test - type: ExtensionRef - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway - sectionName: http -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*.envoyproxy.io' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - routes: - - backendWeights: - invalid: 0 - valid: 0 - destination: - name: httproute/default/httproute-1/rule/0 - settings: - - endpoints: - - host: 7.7.7.7 - port: 8080 - weight: 1 - hostname: gateway.envoyproxy.io - name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io - pathMatch: - distinct: false - name: "" - prefix: / - rateLimit: - global: - rules: - - headerMatches: - - distinct: false - exact: one - name: x-user-id - - distinct: true - name: x-org-id - limit: - requests: 10 - unit: Hour diff --git a/internal/gatewayapi/zz_generated.deepcopy.go b/internal/gatewayapi/zz_generated.deepcopy.go index fb847507b0a..56969b4480a 100644 --- a/internal/gatewayapi/zz_generated.deepcopy.go +++ b/internal/gatewayapi/zz_generated.deepcopy.go @@ -171,17 +171,6 @@ func (in *Resources) DeepCopyInto(out *Resources) { } } } - if in.RateLimitFilters != nil { - in, out := &in.RateLimitFilters, &out.RateLimitFilters - *out = make([]*apiv1alpha1.RateLimitFilter, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(apiv1alpha1.RateLimitFilter) - (*in).DeepCopyInto(*out) - } - } - } if in.EnvoyProxy != nil { in, out := &in.EnvoyProxy, &out.EnvoyProxy *out = new(apiv1alpha1.EnvoyProxy) diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 663eb80a299..be6df0d1356 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -139,9 +139,6 @@ type resourceMappings struct { // authenFilters is a map of AuthenticationFilters, where the key is the // namespaced name of the AuthenticationFilter. authenFilters map[types.NamespacedName]*egv1a1.AuthenticationFilter - // rateLimitFilters is a map of RateLimitFilters, where the key is the - // namespaced name of the RateLimitFilter. - rateLimitFilters map[types.NamespacedName]*egv1a1.RateLimitFilter // extensionRefFilters is a map of filters managed by an extension. // The key is the namespaced name of the filter and the value is the // unstructured form of the resource. @@ -154,7 +151,6 @@ func newResourceMapping() *resourceMappings { allAssociatedBackendRefs: map[gwapiv1.BackendObjectReference]struct{}{}, allAssociatedRefGrants: map[types.NamespacedName]*gwapiv1b1.ReferenceGrant{}, authenFilters: map[types.NamespacedName]*egv1a1.AuthenticationFilter{}, - rateLimitFilters: map[types.NamespacedName]*egv1a1.RateLimitFilter{}, extensionRefFilters: map[types.NamespacedName]unstructured.Unstructured{}, } } @@ -657,7 +653,7 @@ func addReferenceGrantIndexers(ctx context.Context, mgr manager.Manager) error { // addHTTPRouteIndexers adds indexing on HTTPRoute. // - For Service, ServiceImports objects that are referenced in HTTPRoute objects via `.spec.rules.backendRefs`. // This helps in querying for HTTPRoutes that are affected by a particular Service CRUD. -// - For AuthenticationFilter and RateLimitFilter objects that are referenced in HTTPRoute objects via +// - For AuthenticationFilter objects that are referenced in HTTPRoute objects via // `.spec.rules[].filters`. This helps in querying for HTTPRoutes that are affected by a // particular AuthenticationFilter CRUD. func addHTTPRouteIndexers(ctx context.Context, mgr manager.Manager) error { @@ -673,9 +669,6 @@ func addHTTPRouteIndexers(ctx context.Context, mgr manager.Manager) error { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1.HTTPRoute{}, rateLimitFilterHTTPRouteIndex, rateLimitFilterHTTPRouteIndexFunc); err != nil { - return err - } return nil } @@ -700,27 +693,6 @@ func authenFilterHTTPRouteIndexFunc(rawObj client.Object) []string { return filters } -func rateLimitFilterHTTPRouteIndexFunc(rawObj client.Object) []string { - httproute := rawObj.(*gwapiv1.HTTPRoute) - var filters []string - for _, rule := range httproute.Spec.Rules { - for i := range rule.Filters { - filter := rule.Filters[i] - if gatewayapi.IsRateLimitHTTPFilter(&filter) { - if err := gatewayapi.ValidateHTTPRouteFilter(&filter); err == nil { - filters = append(filters, - types.NamespacedName{ - Namespace: httproute.Namespace, - Name: string(filter.ExtensionRef.Name), - }.String(), - ) - } - } - } - } - return filters -} - func gatewayHTTPRouteIndexFunc(rawObj client.Object) []string { httproute := rawObj.(*gwapiv1.HTTPRoute) var gateways []string @@ -775,10 +747,6 @@ func addGRPCRouteIndexers(ctx context.Context, mgr manager.Manager) error { return err } - if err := mgr.GetFieldIndexer().IndexField(ctx, &gwapiv1a2.GRPCRoute{}, rateLimitFilterGRPCRouteIndex, rateLimitFilterGRPCRouteIndexFunc); err != nil { - return err - } - return nil } @@ -841,27 +809,6 @@ func authenFilterGRPCRouteIndexFunc(rawObj client.Object) []string { return filters } -func rateLimitFilterGRPCRouteIndexFunc(rawObj client.Object) []string { - grpcroute := rawObj.(*gwapiv1a2.GRPCRoute) - var filters []string - for _, rule := range grpcroute.Spec.Rules { - for i := range rule.Filters { - filter := rule.Filters[i] - if gatewayapi.IsRateLimitGRPCFilter(&filter) { - if err := gatewayapi.ValidateGRPCRouteFilter(&filter); err == nil { - filters = append(filters, - types.NamespacedName{ - Namespace: grpcroute.Namespace, - Name: string(filter.ExtensionRef.Name), - }.String(), - ) - } - } - } - } - return filters -} - // addTLSRouteIndexers adds indexing on TLSRoute, for Service objects that are // referenced in TLSRoute objects via `.spec.rules.backendRefs`. This helps in // querying for TLSRoutes that are affected by a particular Service CRUD. @@ -1578,22 +1525,6 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M return err } - rfPredicates := []predicate.Predicate{ - predicate.GenerationChangedPredicate{}, - predicate.NewPredicateFuncs(r.httpRoutesForRateLimitFilter), - } - if len(r.namespaceLabels) != 0 { - rfPredicates = append(rfPredicates, predicate.NewPredicateFuncs(r.hasMatchingNamespaceLabels)) - } - // Watch RateLimitFilter CRUDs and enqueue associated HTTPRoute objects. - if err := c.Watch( - source.Kind(mgr.GetCache(), &egv1a1.RateLimitFilter{}), - handler.EnqueueRequestsFromMapFunc(r.enqueueClass), - rfPredicates..., - ); err != nil { - return err - } - // Watch EnvoyPatchPolicy if enabled in config eppPredicates := []predicate.Predicate{predicate.GenerationChangedPredicate{}} if len(r.namespaceLabels) != 0 { diff --git a/internal/provider/kubernetes/filters.go b/internal/provider/kubernetes/filters.go index c7d402a8593..bd3266a7040 100644 --- a/internal/provider/kubernetes/filters.go +++ b/internal/provider/kubernetes/filters.go @@ -42,34 +42,6 @@ func (r *gatewayAPIReconciler) getAuthenticationFilters(ctx context.Context) ([] return authens, nil } -func (r *gatewayAPIReconciler) getRateLimitFilters(ctx context.Context) ([]egv1a1.RateLimitFilter, error) { - rateLimitList := new(egv1a1.RateLimitFilterList) - if err := r.client.List(ctx, rateLimitList); err != nil { - return nil, fmt.Errorf("failed to list RateLimitFilters: %v", err) - } - - rateLimits := rateLimitList.Items - if len(r.namespaceLabels) != 0 { - var rls []egv1a1.RateLimitFilter - for _, rl := range rateLimits { - ns := rl.GetNamespace() - ok, err := r.checkObjectNamespaceLabels(ns) - if err != nil { - // TODO: should return? or just proceed? - return nil, fmt.Errorf("failed to check namespace labels for RateLimitFilter %s in namespace %s: %s", rl.GetName(), ns, err) - } - - if ok { - rls = append(rls, rl) - } - } - - rateLimits = rls - } - - return rateLimits, nil -} - func (r *gatewayAPIReconciler) getExtensionRefFilters(ctx context.Context) ([]unstructured.Unstructured, error) { var resourceItems []unstructured.Unstructured for _, gvk := range r.extGVKs { diff --git a/internal/provider/kubernetes/kubernetes_test.go b/internal/provider/kubernetes/kubernetes_test.go index f76d915b931..871874b5a90 100644 --- a/internal/provider/kubernetes/kubernetes_test.go +++ b/internal/provider/kubernetes/kubernetes_test.go @@ -73,7 +73,6 @@ func TestProvider(t *testing.T) { "gateway scheduled status": testGatewayScheduledStatus, "httproute": testHTTPRoute, "tlsroute": testTLSRoute, - "ratelimit filter": testRateLimitFilter, "authentication filter": testAuthenFilter, "stale service cleanup route deletion": testServiceCleanupForMultipleRoutes, } @@ -458,182 +457,6 @@ func testLongNameHashedResources(ctx context.Context, t *testing.T, provider *Pr assert.Equal(t, gw.Spec, res.Gateways[0].Spec) } -func testRateLimitFilter(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) { - cli := provider.manager.GetClient() - - gc := test.GetGatewayClass("ratelimit-test", egv1a1.GatewayControllerName) - require.NoError(t, cli.Create(ctx, gc)) - - // Ensure the GatewayClass reports ready. - require.Eventually(t, func() bool { - if err := cli.Get(ctx, types.NamespacedName{Name: gc.Name}, gc); err != nil { - return false - } - - for _, cond := range gc.Status.Conditions { - if cond.Type == string(gwapiv1.GatewayClassConditionStatusAccepted) && cond.Status == metav1.ConditionTrue { - return true - } - } - - return false - }, defaultWait, defaultTick) - - defer func() { - require.NoError(t, cli.Delete(ctx, gc)) - }() - - // Create the namespace for the Gateway under test. - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ratelimit-test"}} - require.NoError(t, cli.Create(ctx, ns)) - - gw := &gwapiv1.Gateway{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ratelimit-test", - Namespace: ns.Name, - }, - Spec: gwapiv1.GatewaySpec{ - GatewayClassName: gwapiv1.ObjectName(gc.Name), - Listeners: []gwapiv1.Listener{ - { - Name: "test", - Port: gwapiv1.PortNumber(int32(8080)), - Protocol: gwapiv1.HTTPProtocolType, - }, - }, - }, - } - require.NoError(t, cli.Create(ctx, gw)) - - defer func() { - require.NoError(t, cli.Delete(ctx, gw)) - }() - - svc := test.GetService(types.NamespacedName{Namespace: ns.Name, Name: "test"}, nil, map[string]int32{ - "http": 80, - "https": 443, - }) - - require.NoError(t, cli.Create(ctx, svc)) - - defer func() { - require.NoError(t, cli.Delete(ctx, svc)) - }() - - rateLimitFilter := test.GetRateLimitFilter("ratelimit-test", ns.Name) - - require.NoError(t, cli.Create(ctx, rateLimitFilter)) - - defer func() { - require.NoError(t, cli.Delete(ctx, rateLimitFilter)) - }() - - var testCases = []struct { - name string - route gwapiv1.HTTPRoute - }{ - { - name: "ratelimit-test-httproute", - route: gwapiv1.HTTPRoute{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ratelimit-test", - Namespace: ns.Name, - }, - Spec: gwapiv1.HTTPRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: gwapiv1.ObjectName(gw.Name), - }, - }, - }, - Hostnames: []gwapiv1.Hostname{"test.hostname.local"}, - Rules: []gwapiv1.HTTPRouteRule{ - { - Matches: []gwapiv1.HTTPRouteMatch{ - { - Path: &gwapiv1.HTTPPathMatch{ - Type: ptr.To(gwapiv1.PathMatchPathPrefix), - Value: ptr.To("/ratelimitfilter/"), - }, - }, - }, - BackendRefs: []gwapiv1.HTTPBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Name: "test", - }, - }, - }, - }, - Filters: []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindRateLimitFilter), - Name: gwapiv1.ObjectName("ratelimit-test"), - }, - }, - }, - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - require.NoError(t, cli.Create(ctx, &testCase.route)) - defer func() { - require.NoError(t, cli.Delete(ctx, &testCase.route)) - }() - - require.Eventually(t, func() bool { - return resources.GatewayAPIResources.Len() != 0 - }, defaultWait, defaultTick) - - // Ensure the test HTTPRoute in the HTTPRoute resources is as expected. - key := types.NamespacedName{ - Namespace: testCase.route.Namespace, - Name: testCase.route.Name, - } - require.Eventually(t, func() bool { - return cli.Get(ctx, key, &testCase.route) == nil - }, defaultWait, defaultTick) - - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("ratelimit-test") - return ok && - len(res.HTTPRoutes) != 0 && - assert.Equal(t, testCase.route.Spec, res.HTTPRoutes[0].Spec) - }, defaultWait, defaultTick) - - // Ensure the RateLimitFilter is in the resource map. - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("ratelimit-test") - return ok && - len(res.RateLimitFilters) != 0 && - assert.Equal(t, rateLimitFilter.Spec, res.RateLimitFilters[0].Spec) - }, defaultWait, defaultTick) - - // Update the rate limit filter. - rateLimitFilter.Spec.Global.Rules = append(rateLimitFilter.Spec.Global.Rules, test.GetRateLimitGlobalRule("two")) - require.NoError(t, cli.Update(ctx, rateLimitFilter)) - - // Ensure the RateLimitFilter in the resource map has been updated. - require.Eventually(t, func() bool { - res, ok := resources.GatewayAPIResources.Load("ratelimit-test") - return ok && - len(res.RateLimitFilters) != 0 && - assert.Equal(t, 2, len(res.RateLimitFilters[0].Spec.Global.Rules)) - }, defaultWait, defaultTick) - }) - } -} - func testAuthenFilter(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) { cli := provider.manager.GetClient() @@ -1820,20 +1643,6 @@ func TestNamespaceSelectorsProvider(t *testing.T) { require.NoError(t, cli.Delete(ctx, nonWatchedAuthenFilter)) }() - watchedRateLimitFilter := test.GetRateLimitFilter("watched-rate-limit-filter", watchedNS.Name) - require.NoError(t, cli.Create(ctx, watchedRateLimitFilter)) - - defer func() { - require.NoError(t, cli.Delete(ctx, watchedRateLimitFilter)) - }() - - nonWatchedRateLimitFilter := test.GetRateLimitFilter("non-watched-rate-limit-filter", nonWatchedNS.Name) - require.NoError(t, cli.Create(ctx, nonWatchedRateLimitFilter)) - - defer func() { - require.NoError(t, cli.Delete(ctx, nonWatchedRateLimitFilter)) - }() - watchedSvc := test.GetService(types.NamespacedName{Namespace: watchedNS.Name, Name: "watched-service"}, nil, map[string]int32{ "http": 80, "https": 443, @@ -1870,14 +1679,6 @@ func TestNamespaceSelectorsProvider(t *testing.T) { Name: gwapiv1.ObjectName(watchedAuthenFilter.Name), }, }, - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindRateLimitFilter), - Name: gwapiv1.ObjectName(watchedRateLimitFilter.Name), - }, - }, } require.NoError(t, cli.Create(ctx, watchedHTTPRoute)) defer func() { @@ -1900,14 +1701,6 @@ func TestNamespaceSelectorsProvider(t *testing.T) { Name: gwapiv1.ObjectName(nonWatchedAuthenFilter.Name), }, }, - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindRateLimitFilter), - Name: gwapiv1.ObjectName(nonWatchedRateLimitFilter.Name), - }, - }, } require.NoError(t, cli.Create(ctx, nonWatchedHTTPRoute)) defer func() { @@ -2046,8 +1839,4 @@ func TestNamespaceSelectorsProvider(t *testing.T) { return res != nil && len(res.AuthenticationFilters) == 1 }, defaultWait, defaultTick) - require.Eventually(t, func() bool { - res, _ := resources.GatewayAPIResources.Load(gc.Name) - return res != nil && len(res.RateLimitFilters) == 1 - }, defaultWait, defaultTick) } diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index b24872447d4..343ef469d1b 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -349,30 +349,6 @@ func (r *gatewayAPIReconciler) httpRoutesForAuthenticationFilter(obj client.Obje return len(httpRoutes) != 0 } -// httpRoutesForRateLimitFilter tries finding HTTPRoute referents of the provided -// RateLimitFilter and returns true if any exist. -func (r *gatewayAPIReconciler) httpRoutesForRateLimitFilter(obj client.Object) bool { - ctx := context.Background() - filter, ok := obj.(*egv1a1.RateLimitFilter) - if !ok { - r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) - return false - } - - // Check if the RateLimitFilter belongs to a managed HTTPRoute. - httpRouteList := &gwapiv1.HTTPRouteList{} - if err := r.client.List(ctx, httpRouteList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(rateLimitFilterHTTPRouteIndex, utils.NamespacedName(filter).String()), - }); err != nil { - r.log.Error(err, "unable to find associated HTTPRoutes") - return false - } - - httpRoutes := r.filterHTTPRoutesByNamespaceLabels(httpRouteList.Items) - - return len(httpRoutes) != 0 -} - func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gwapiv1.HTTPRoute) []gwapiv1.HTTPRoute { if len(r.namespaceLabels) == 0 { return httpRoutes diff --git a/internal/provider/kubernetes/routes.go b/internal/provider/kubernetes/routes.go index d8447b9917b..c8876e28166 100644 --- a/internal/provider/kubernetes/routes.go +++ b/internal/provider/kubernetes/routes.go @@ -108,7 +108,7 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error { grpcRouteList := &gwapiv1a2.GRPCRouteList{} - // An GRPCRoute may reference an AuthenticationFilter and RateLimitFilter, + // An GRPCRoute may reference an AuthenticationFilter, // so add them to the resource map first (if they exist). authenFilters, err := r.getAuthenticationFilters(ctx) if err != nil { @@ -119,15 +119,6 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam resourceMap.authenFilters[utils.NamespacedName(&filter)] = &filter } - rateLimitFilters, err := r.getRateLimitFilters(ctx) - if err != nil { - return err - } - for i := range rateLimitFilters { - filter := rateLimitFilters[i] - resourceMap.rateLimitFilters[utils.NamespacedName(&filter)] = &filter - } - if err := r.client.List(ctx, grpcRouteList, &client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(gatewayGRPCRouteIndex, gatewayNamespaceName), }); err != nil { @@ -224,18 +215,6 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam } resourceTree.AuthenticationFilters = append(resourceTree.AuthenticationFilters, authFilter) - case egv1a1.KindRateLimitFilter: - key := types.NamespacedName{ - Namespace: grpcRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - rateLimitFilter, ok := resourceMap.rateLimitFilters[key] - if !ok { - r.log.Error(err, "RateLimitFilter not found; bypassing rule", "index", i) - continue - } - - resourceTree.RateLimitFilters = append(resourceTree.RateLimitFilters, rateLimitFilter) default: // If the Kind does not match any Envoy Gateway resources, check if it's a Kind // managed by an extension and add to resourceTree @@ -271,7 +250,7 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error { httpRouteList := &gwapiv1.HTTPRouteList{} - // An HTTPRoute may reference an AuthenticationFilter, RateLimitFilter, or a filter managed + // An HTTPRoute may reference an AuthenticationFilter, or a filter managed // by an extension so add them to the resource map first (if they exist). authenFilters, err := r.getAuthenticationFilters(ctx) if err != nil { @@ -282,15 +261,6 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam resourceMap.authenFilters[utils.NamespacedName(&filter)] = &filter } - rateLimitFilters, err := r.getRateLimitFilters(ctx) - if err != nil { - return err - } - for i := range rateLimitFilters { - filter := rateLimitFilters[i] - resourceMap.rateLimitFilters[utils.NamespacedName(&filter)] = &filter - } - extensionRefFilters, err := r.getExtensionRefFilters(ctx) if err != nil { return err @@ -451,18 +421,6 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam } resourceTree.AuthenticationFilters = append(resourceTree.AuthenticationFilters, authFilter) - case egv1a1.KindRateLimitFilter: - key := types.NamespacedName{ - Namespace: httpRoute.Namespace, - Name: string(filter.ExtensionRef.Name), - } - rateLimitFilter, ok := resourceMap.rateLimitFilters[key] - if !ok { - r.log.Error(err, "RateLimitFilter not found; bypassing rule", "index", i) - continue - } - - resourceTree.RateLimitFilters = append(resourceTree.RateLimitFilters, rateLimitFilter) default: // If the Kind does not match any Envoy Gateway resources, check if it's a Kind // managed by an extension and add to resourceTree diff --git a/internal/provider/kubernetes/routes_test.go b/internal/provider/kubernetes/routes_test.go index a0a01346986..681af679a93 100644 --- a/internal/provider/kubernetes/routes_test.go +++ b/internal/provider/kubernetes/routes_test.go @@ -64,7 +64,6 @@ func TestProcessHTTPRoutes(t *testing.T) { name string routes []*gwapiv1.HTTPRoute authenFilters []*egv1a1.AuthenticationFilter - rateLimitFilters []*egv1a1.RateLimitFilter extensionFilters []*unstructured.Unstructured extensionAPIGroups []schema.GroupVersionKind expected bool @@ -192,209 +191,6 @@ func TestProcessHTTPRoutes(t *testing.T) { }, expected: true, }, - { - name: "httproute with one rateLimitfilter", - routes: []*gwapiv1.HTTPRoute{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: gwapiv1.HTTPRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: "test", - }, - }, - }, - Rules: []gwapiv1.HTTPRouteRule{ - { - Matches: []gwapiv1.HTTPRouteMatch{ - { - Path: &gwapiv1.HTTPPathMatch{ - Type: ptr.To(gwapiv1.PathMatchPathPrefix), - Value: ptr.To("/"), - }, - }, - }, - Filters: []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindRateLimitFilter), - Name: gwapiv1.ObjectName("test"), - }, - }, - }, - BackendRefs: []gwapiv1.HTTPBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Group: gatewayapi.GroupPtr(corev1.GroupName), - Kind: gatewayapi.KindPtr(gatewayapi.KindService), - Name: "test", - }, - }, - }, - }, - }, - }, - }, - }, - }, - rateLimitFilters: []*egv1a1.RateLimitFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindRateLimitFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.RateLimitFilterSpec{ - Type: egv1a1.GlobalRateLimitType, - Global: &egv1a1.GlobalRateLimit{ - Rules: []egv1a1.RateLimitRule{ - { - ClientSelectors: []egv1a1.RateLimitSelectCondition{ - { - Headers: []egv1a1.HeaderMatch{ - { - Name: "x-user-id", - Value: ptr.To("one"), - }, - }, - }, - }, - Limit: egv1a1.RateLimitValue{ - Requests: 5, - Unit: "Second", - }, - }, - }, - }, - }, - }, - }, - expected: true, - }, - { - name: "httproute with one authenticationfilter and ratelimitfilter", - routes: []*gwapiv1.HTTPRoute{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: gwapiv1.HTTPRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: "test", - }, - }, - }, - Rules: []gwapiv1.HTTPRouteRule{ - { - Matches: []gwapiv1.HTTPRouteMatch{ - { - Path: &gwapiv1.HTTPPathMatch{ - Type: ptr.To(gwapiv1.PathMatchPathPrefix), - Value: ptr.To("/"), - }, - }, - }, - Filters: []gwapiv1.HTTPRouteFilter{ - { - Type: gwapiv1.HTTPRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindAuthenticationFilter), - Name: gwapiv1.ObjectName("test"), - }, - }, - }, - BackendRefs: []gwapiv1.HTTPBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Group: gatewayapi.GroupPtr(corev1.GroupName), - Kind: gatewayapi.KindPtr(gatewayapi.KindService), - Name: "test", - }, - }, - }, - }, - }, - }, - }, - }, - }, - authenFilters: []*egv1a1.AuthenticationFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindAuthenticationFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.AuthenticationFilterSpec{ - Type: egv1a1.JwtAuthenticationFilterProviderType, - JwtProviders: []egv1a1.JwtAuthenticationFilterProvider{ - { - Name: "test", - Issuer: "https://www.test.local", - Audiences: []string{"test.local"}, - RemoteJWKS: egv1a1.RemoteJWKS{ - URI: "https://test.local/jwt/public-key/jwks.json", - }, - }, - }, - }, - }, - }, - rateLimitFilters: []*egv1a1.RateLimitFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindRateLimitFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.RateLimitFilterSpec{ - Type: egv1a1.GlobalRateLimitType, - Global: &egv1a1.GlobalRateLimit{ - Rules: []egv1a1.RateLimitRule{ - { - ClientSelectors: []egv1a1.RateLimitSelectCondition{ - { - Headers: []egv1a1.HeaderMatch{ - { - Name: "x-user-id", - Value: ptr.To("one"), - }, - }, - }, - }, - Limit: egv1a1.RateLimitValue{ - Requests: 5, - Unit: "Second", - }, - }, - }, - }, - }, - }, - }, - expected: true, - }, { name: "httproute with one filter_from_extension", routes: []*gwapiv1.HTTPRoute{ @@ -494,9 +290,6 @@ func TestProcessHTTPRoutes(t *testing.T) { for _, filter := range tc.authenFilters { objs = append(objs, filter) } - for _, filter := range tc.rateLimitFilters { - objs = append(objs, filter) - } for _, filter := range tc.extensionFilters { objs = append(objs, filter) } @@ -527,15 +320,6 @@ func TestProcessHTTPRoutes(t *testing.T) { require.Equal(t, filter, resourceMap.authenFilters[key]) } } - if tc.rateLimitFilters != nil { - for i, filter := range tc.rateLimitFilters { - key := types.NamespacedName{ - Namespace: tc.routes[i].Namespace, - Name: filter.Name, - } - require.Equal(t, filter, resourceMap.rateLimitFilters[key]) - } - } if tc.extensionFilters != nil { for i, filter := range tc.extensionFilters { key := types.NamespacedName{ @@ -587,7 +371,6 @@ func TestProcessGRPCRoutes(t *testing.T) { name string routes []*gwapiv1a2.GRPCRoute authenFilters []*egv1a1.AuthenticationFilter - rateLimitFilters []*egv1a1.RateLimitFilter extensionAPIGroups []schema.GroupVersionKind expected bool }{ @@ -712,94 +495,6 @@ func TestProcessGRPCRoutes(t *testing.T) { }, expected: true, }, - { - name: "grpcroute with one ratelimitfilter", - routes: []*gwapiv1a2.GRPCRoute{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: gwapiv1a2.GRPCRouteSpec{ - CommonRouteSpec: gwapiv1.CommonRouteSpec{ - ParentRefs: []gwapiv1.ParentReference{ - { - Name: "test", - }, - }, - }, - Rules: []gwapiv1a2.GRPCRouteRule{ - { - Matches: []gwapiv1a2.GRPCRouteMatch{ - { - Method: &gwapiv1a2.GRPCMethodMatch{ - Method: ptr.To("Ping"), - }, - }, - }, - Filters: []gwapiv1a2.GRPCRouteFilter{ - { - Type: gwapiv1a2.GRPCRouteFilterExtensionRef, - ExtensionRef: &gwapiv1.LocalObjectReference{ - Group: gwapiv1.Group(egv1a1.GroupVersion.Group), - Kind: gwapiv1.Kind(egv1a1.KindRateLimitFilter), - Name: gwapiv1.ObjectName("test"), - }, - }, - }, - BackendRefs: []gwapiv1a2.GRPCBackendRef{ - { - BackendRef: gwapiv1.BackendRef{ - BackendObjectReference: gwapiv1.BackendObjectReference{ - Group: gatewayapi.GroupPtr(corev1.GroupName), - Kind: gatewayapi.KindPtr(gatewayapi.KindService), - Name: "test", - }, - }, - }, - }, - }, - }, - }, - }, - }, - rateLimitFilters: []*egv1a1.RateLimitFilter{ - { - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindRateLimitFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "test", - }, - Spec: egv1a1.RateLimitFilterSpec{ - Type: egv1a1.KindRateLimitFilter, - Global: &egv1a1.GlobalRateLimit{ - Rules: []egv1a1.RateLimitRule{ - { - ClientSelectors: []egv1a1.RateLimitSelectCondition{ - { - Headers: []egv1a1.HeaderMatch{ - { - Name: "x-user-id", - Value: ptr.To("one"), - }, - }, - }, - }, - Limit: egv1a1.RateLimitValue{ - Requests: 5, - Unit: "Second", - }, - }, - }, - }, - }, - }, - }, - expected: true, - }, } for i := range testCases { @@ -826,9 +521,6 @@ func TestProcessGRPCRoutes(t *testing.T) { for _, filter := range tc.authenFilters { objs = append(objs, filter) } - for _, filter := range tc.rateLimitFilters { - objs = append(objs, filter) - } if len(tc.extensionAPIGroups) > 0 { r.extGVKs = append(r.extGVKs, tc.extensionAPIGroups...) } @@ -856,15 +548,6 @@ func TestProcessGRPCRoutes(t *testing.T) { require.Equal(t, filter, resourceMap.authenFilters[key]) } } - if tc.rateLimitFilters != nil { - for i, filter := range tc.rateLimitFilters { - key := types.NamespacedName{ - Namespace: tc.routes[i].Namespace, - Name: filter.Name, - } - require.Equal(t, filter, resourceMap.rateLimitFilters[key]) - } - } } else { require.Error(t, err) } diff --git a/internal/provider/kubernetes/test/utils.go b/internal/provider/kubernetes/test/utils.go index 877e173bc29..f139d02f69a 100644 --- a/internal/provider/kubernetes/test/utils.go +++ b/internal/provider/kubernetes/test/utils.go @@ -343,48 +343,6 @@ func GetAuthenticationProvider(name string) egv1a1.JwtAuthenticationFilterProvid } } -// GetRateLimitFilter returns a pointer to an RateLimitFilter with dummy rules. -func GetRateLimitFilter(name, ns string) *egv1a1.RateLimitFilter { - rule := GetRateLimitGlobalRule("one") - return &egv1a1.RateLimitFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: egv1a1.KindRateLimitFilter, - APIVersion: egv1a1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: ns, - Name: name, - }, - Spec: egv1a1.RateLimitFilterSpec{ - Type: egv1a1.GlobalRateLimitType, - Global: &egv1a1.GlobalRateLimit{ - Rules: []egv1a1.RateLimitRule{rule}, - }, - }, - } -} - -// GetRateLimitGlobalRule returns a RateLimitRule using the val as the ClientSelectors -// headers value. -func GetRateLimitGlobalRule(val string) egv1a1.RateLimitRule { - return egv1a1.RateLimitRule{ - ClientSelectors: []egv1a1.RateLimitSelectCondition{ - { - Headers: []egv1a1.HeaderMatch{ - { - Name: "x-user-id", - Value: ptr.To(val), - }, - }, - }, - }, - Limit: egv1a1.RateLimitValue{ - Requests: 5, - Unit: "Second", - }, - } -} - func ContainsAuthenFilter(hroute *gwapiv1.HTTPRoute) bool { if hroute == nil { return false diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index b79f1dc2b94..310aa30de47 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -23,7 +23,6 @@ API group. - [EnvoyPatchPolicy](#envoypatchpolicy) - [EnvoyPatchPolicyList](#envoypatchpolicylist) - [EnvoyProxy](#envoyproxy) -- [RateLimitFilter](#ratelimitfilter) - [SecurityPolicy](#securitypolicy) - [SecurityPolicyList](#securitypolicylist) @@ -116,7 +115,7 @@ _Appears in:_ | Field | Description | | --- | --- | | `targetRef` _[PolicyTargetReferenceWithSectionName](#policytargetreferencewithsectionname)_ | targetRef is the name of the resource this policy is being attached to. This Policy and the TargetRef MUST be in the same namespace for this Policy to have effect and be applied to the Gateway. | -| `rateLimit` _[RateLimitFilterSpec](#ratelimitfilterspec)_ | RateLimit allows the user to limit the number of incoming requests to a predefined value based on attributes within the traffic flow. | +| `rateLimit` _[RateLimitSpec](#ratelimitspec)_ | RateLimit allows the user to limit the number of incoming requests to a predefined value based on attributes within the traffic flow. | | `loadBalancer` _[LoadBalancer](#loadbalancer)_ | LoadBalancer policy to apply when routing traffic from the gateway to the backend endpoints | @@ -835,7 +834,7 @@ _Appears in:_ GlobalRateLimit defines global rate limit configuration. _Appears in:_ -- [RateLimitFilterSpec](#ratelimitfilterspec) +- [RateLimitSpec](#ratelimitspec) | Field | Description | | --- | --- | @@ -1459,38 +1458,6 @@ _Appears in:_ -#### RateLimitFilter - - - -RateLimitFilter allows the user to limit the number of incoming requests to a predefined value based on attributes within the traffic flow. - - - -| Field | Description | -| --- | --- | -| `apiVersion` _string_ | `gateway.envoyproxy.io/v1alpha1` -| `kind` _string_ | `RateLimitFilter` -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | -| `spec` _[RateLimitFilterSpec](#ratelimitfilterspec)_ | Spec defines the desired state of RateLimitFilter. | - - -#### RateLimitFilterSpec - - - -RateLimitFilterSpec defines the desired state of RateLimitFilter. - -_Appears in:_ -- [BackendTrafficPolicySpec](#backendtrafficpolicyspec) -- [RateLimitFilter](#ratelimitfilter) - -| Field | Description | -| --- | --- | -| `type` _[RateLimitType](#ratelimittype)_ | Type decides the scope for the RateLimits. Valid RateLimitType values are "Global". | -| `global` _[GlobalRateLimit](#globalratelimit)_ | Global defines global rate limit configuration. | - - #### RateLimitRedisSettings @@ -1536,6 +1503,21 @@ _Appears in:_ | `sourceCIDR` _[SourceMatch](#sourcematch)_ | SourceCIDR is the client IP Address range to match on. | +#### RateLimitSpec + + + +RateLimitSpec defines the desired state of RateLimitSpec. + +_Appears in:_ +- [BackendTrafficPolicySpec](#backendtrafficpolicyspec) + +| Field | Description | +| --- | --- | +| `type` _[RateLimitType](#ratelimittype)_ | Type decides the scope for the RateLimits. Valid RateLimitType values are "Global". | +| `global` _[GlobalRateLimit](#globalratelimit)_ | Global defines global rate limit configuration. | + + #### RateLimitType _Underlying type:_ `string` @@ -1543,7 +1525,7 @@ _Underlying type:_ `string` RateLimitType specifies the types of RateLimiting. _Appears in:_ -- [RateLimitFilterSpec](#ratelimitfilterspec) +- [RateLimitSpec](#ratelimitspec) diff --git a/site/content/en/latest/user/rate-limit.md b/site/content/en/latest/user/rate-limit.md index cee28080b9c..c27eefaf90a 100644 --- a/site/content/en/latest/user/rate-limit.md +++ b/site/content/en/latest/user/rate-limit.md @@ -14,8 +14,8 @@ Envoy Gateway supports [Global rate limiting][], where the rate limit is common i.e. if the data plane has 2 replicas of Envoy running, and the rate limit is 10 requests/second, this limit is common and will be hit if 5 requests pass through the first replica and 5 requests pass through the second replica within the same second. -Envoy Gateway introduces a new CRD called [RateLimitFilter][] that allows the user to describe their rate limit intent. This instantiated resource -can be linked to a [HTTPRoute][] or [GRPCRoute][] resource using an [ExtensionRef][] filter. +Envoy Gateway introduces a new CRD called [BackendTrafficPolicy][] that allows the user to describe their rate limit intent. This instantiated resource +can be linked to a [Gateway][], [HTTPRoute][] or [GRPCRoute][] resource. ## Prerequisites @@ -131,20 +131,26 @@ with a value set to `one`. ```shell cat <