Skip to content

Commit

Permalink
Build rate limit service config
Browse files Browse the repository at this point in the history
* Translates Xds IR into ratelimit service config
https://github.com/envoyproxy/ratelimit#configuration

Relates to envoyproxy#670

Signed-off-by: Arko Dasgupta <arko@tetrate.io>
  • Loading branch information
arkodg committed Jan 13, 2023
1 parent 8e4e0ce commit a7508b8
Show file tree
Hide file tree
Showing 16 changed files with 408 additions and 23 deletions.
10 changes: 7 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.19
require (
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc
github.com/envoyproxy/go-control-plane v0.10.3-0.20221028143534-ed9652aebfd9
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573
github.com/go-logr/logr v1.2.3
github.com/go-logr/zapr v1.2.3
github.com/google/go-cmp v0.5.9
Expand All @@ -17,6 +18,7 @@ require (
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
google.golang.org/grpc v1.51.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.26.0
k8s.io/apimachinery v0.26.0
k8s.io/client-go v0.26.0
Expand Down Expand Up @@ -45,12 +47,14 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/lyft/gostats v0.4.1 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -62,11 +66,12 @@ require (
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tsaarni/x500dn v0.0.0-20210331182804-14283c7f5a16 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect
golang.org/x/net v0.4.0 // indirect
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/term v0.3.0 // indirect
Expand All @@ -77,7 +82,6 @@ require (
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.26.0 // indirect
k8s.io/component-base v0.26.0 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
Expand Down
15 changes: 12 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ github.com/envoyproxy/go-control-plane v0.10.3-0.20221028143534-ed9652aebfd9/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.7 h1:qcZcULcd/abmQg6dwigimCNEyi4gg31M/xaciQlDml8=
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573 h1:R0q3SnW2O9CnSHt9Mx6I/v3nz3HH3xzqeOQ+zSpszpA=
github.com/envoyproxy/ratelimit v1.4.1-0.20230109191524-5f3f5a4cf573/go.mod h1:J780gPM5tWaDEY2n+A7q744I9Bot8OJuBHZbwCfDpVc=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
Expand Down Expand Up @@ -190,8 +192,9 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
Expand Down Expand Up @@ -219,6 +222,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand All @@ -231,6 +236,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lyft/gostats v0.4.1 h1:oR6p4HRCGxt0nUntmZIWmYMgyothBi3eZH2A71vRjsc=
github.com/lyft/gostats v0.4.1/go.mod h1:Tpx2xRzz4t+T2Tx0xdVgIoBdR2UMVz+dKnE3X01XSd8=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
Expand Down Expand Up @@ -294,6 +301,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
Expand Down Expand Up @@ -428,8 +436,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -464,6 +472,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
108 changes: 94 additions & 14 deletions internal/xds/translator/ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
ratelimitfilter "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ratelimit/v3"
hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
wkt "github.com/envoyproxy/go-control-plane/pkg/wellknown"
ratelimitserviceconfig "github.com/envoyproxy/ratelimit/src/config"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/wrapperspb"
Expand Down Expand Up @@ -102,6 +103,20 @@ func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) [
// Rules are ORed
for rIdx, rule := range global.Rules {
rlActions := []*route.RateLimit_Action{}
// Case when header match is not set and the rate limit is applied
// to all traffic.
if len(rule.HeaderMatches) == 0 {
// Setup GenericKey action
action := &route.RateLimit_Action{
ActionSpecifier: &route.RateLimit_Action_GenericKey_{
GenericKey: &route.RateLimit_Action_GenericKey{
DescriptorKey: getRateLimitDescriptorKey(descriptorPrefix, rIdx, -1),
DescriptorValue: getRateLimitDescriptorValue(descriptorPrefix, rIdx, -1),
},
},
}
rlActions = append(rlActions, action)
}
// Matches are ANDed
for mIdx, match := range rule.HeaderMatches {
// Case for distinct match
Expand Down Expand Up @@ -143,26 +158,91 @@ func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) [
}
}

// Case when header match is not set and the rate limit is applied
// to all traffic.
rateLimit := &route.RateLimit{Actions: rlActions}
rateLimits = append(rateLimits, rateLimit)
}

return rateLimits
}

// BuildRateLimitServiceConfig builds the rate limit service configuration based on
// https://github.com/envoyproxy/ratelimit#the-configuration-format
func BuildRateLimitServiceConfig(irListener *ir.HTTPListener) *ratelimitserviceconfig.YamlRoot {
yamlDescs := make([]ratelimitserviceconfig.YamlDescriptor, 0, 1)

for _, route := range irListener.Routes {
if route.RateLimit != nil && route.RateLimit.Global != nil {
descs := buildRateLimitServiceDescriptors(route.Name, route.RateLimit.Global)
yamlDescs = append(yamlDescs, descs...)
}
}

if len(yamlDescs) == 0 {
return nil
}

return &ratelimitserviceconfig.YamlRoot{
Domain: getRateLimitDomain(irListener),
Descriptors: yamlDescs,
}
}

// buildRateLimitServiceDescriptors creates the rate limit service yaml descriptors based on the global rate limit IR config.
func buildRateLimitServiceDescriptors(descriptorPrefix string, global *ir.GlobalRateLimit) []ratelimitserviceconfig.YamlDescriptor {
yamlDescs := make([]ratelimitserviceconfig.YamlDescriptor, 0, 1)

for rIdx, rule := range global.Rules {
var head, cur *ratelimitserviceconfig.YamlDescriptor
if len(rule.HeaderMatches) == 0 {
// Setup GenericKey action
action := &route.RateLimit_Action{
ActionSpecifier: &route.RateLimit_Action_GenericKey_{
GenericKey: &route.RateLimit_Action_GenericKey{
DescriptorKey: getRateLimitDescriptorKey(descriptorPrefix, rIdx, -1),
DescriptorValue: getRateLimitDescriptorValue(descriptorPrefix, rIdx, -1),
},
},
yamlDesc := new(ratelimitserviceconfig.YamlDescriptor)
// GenericKey case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, -1)
yamlDesc.Value = getRateLimitDescriptorValue(descriptorPrefix, rIdx, -1)
rateLimit := ratelimitserviceconfig.YamlRateLimit{
RequestsPerUnit: rule.Limit.Requests,
Unit: string(rule.Limit.Unit),
}
rlActions = append(rlActions, action)
yamlDesc.RateLimit = &rateLimit

head = yamlDesc
cur = head
}

rateLimit := &route.RateLimit{Actions: rlActions}
rateLimits = append(rateLimits, rateLimit)
for mIdx, match := range rule.HeaderMatches {
yamlDesc := new(ratelimitserviceconfig.YamlDescriptor)
// Case for distinct match
if match.Distinct {
// RequestHeader case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, mIdx)
} else {
// HeaderValueMatch case
yamlDesc.Key = getRateLimitDescriptorKey(descriptorPrefix, rIdx, mIdx)
yamlDesc.Value = getRateLimitDescriptorValue(descriptorPrefix, rIdx, mIdx)

}

// Add the ratelimit values to the last descriptor
if mIdx == len(rule.HeaderMatches)-1 {
rateLimit := ratelimitserviceconfig.YamlRateLimit{
RequestsPerUnit: rule.Limit.Requests,
Unit: string(rule.Limit.Unit),
}
yamlDesc.RateLimit = &rateLimit
}

if mIdx == 0 {
head = yamlDesc
} else {
cur.Descriptors = []ratelimitserviceconfig.YamlDescriptor{*yamlDesc}
}

cur = yamlDesc
}

yamlDescs = append(yamlDescs, *head)
}

return rateLimits
return yamlDescs
}

func buildRateLimitServiceCluster(irListener *ir.HTTPListener) *cluster.Cluster {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
distinct: true
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
- name: "x-user-id"
exact: "two"
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
limit:
requests: 5
unit: second
pathMatch:
exact: "foo/baz"
- name: "second-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "two"
limit:
requests: 10
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: "first-listener"
address: "0.0.0.0"
port: 10080
hostnames:
- "*"
routes:
- name: "first-route"
rateLimit:
global:
rules:
- headerMatches:
- name: "x-user-id"
exact: "one"
limit:
requests: 5
unit: second
- headerMatches:
- name: "x-user-id"
exact: "two"
limit:
requests: 10
unit: second
pathMatch:
exact: "foo/bar"
destinations:
- host: "1.2.3.4"
port: 50000
Loading

0 comments on commit a7508b8

Please sign in to comment.