Skip to content

Commit

Permalink
Merge pull request #6924 from TheThingsNetwork/feature/2969-rate-limi…
Browse files Browse the repository at this point in the history
…ting-redis-backend

Rate limiting Redis backend
  • Loading branch information
happyRip authored Feb 22, 2024
2 parents a9ae3f7 + 00c6176 commit e64c902
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ For details about compatibility between different releases, see the **Commitment

### Added

- Option to store rate limits in Redis. When used, the rate limits are applied over the entire cluster instead of per-instance.

### Changed

### Deprecated
Expand Down
6 changes: 6 additions & 0 deletions cmd/internal/shared/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ var DefaultKeyVaultConfig = config.KeyVault{
Provider: "static",
}

// DefaultRateLimitingConfig is the default config for rate limiting.
var DefaultRateLimitingConfig = config.RateLimiting{
Provider: "memory",
}

// DefaultTracingConfig is the default config for telemetry tracing.
var DefaultTracingConfig = tracing.Config{
Enable: false,
Expand Down Expand Up @@ -184,6 +189,7 @@ var DefaultServiceBase = config.ServiceBase{
FrequencyPlans: DefaultFrequencyPlansConfig,
Rights: DefaultRightsConfig,
KeyVault: DefaultKeyVaultConfig,
RateLimiting: DefaultRateLimitingConfig,
Tracing: DefaultTracingConfig,
Telemetry: DefaultTelemetryConfig,
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/ttn-lw-stack/commands/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ func NewJoinServerSessionKeyRegistryRedis(conf *Config) *redis.Client {
return redis.New(conf.Redis.WithNamespace("js", "keys"))
}

// NewRateLimitingRedis instantiates a new redis client with the Rate Limiting namespace.
func NewRateLimitingRedis(conf *Config) *redis.Client {
if conf.RateLimiting.Provider != "redis" {
return nil
}
return redis.New(conf.Cache.Redis.WithNamespace("rate-limiting"))
}

var errUnknownComponent = errors.DefineInvalidArgument("unknown_component", "unknown component `{component}`")

var startCommand = &cobra.Command{
Expand Down Expand Up @@ -218,6 +226,7 @@ var startCommand = &cobra.Command{
logger.Warn("No cookie block key configured, generated a random one")
}

config.RateLimiting.Redis.Client = NewRateLimitingRedis(config)
c, err := component.New(logger, &component.Config{ServiceBase: config.ServiceBase}, componentOptions...)
if err != nil {
return shared.ErrInitializeBaseComponent.WithCause(err)
Expand Down
4 changes: 0 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ module go.thethings.network/lorawan-stack/v3

go 1.21

// Use our fork of throttled/throttled/v2.
replace github.com/throttled/throttled/v2 => github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis

// See https://github.com/mitchellh/mapstructure/pull/278
replace github.com/mitchellh/mapstructure => github.com/TheThingsIndustries/mapstructure v0.0.0-20230413130846-941bcd1deec3

Expand Down Expand Up @@ -186,7 +183,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v1.8.9 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/wire v0.5.0 // indirect
Expand Down
23 changes: 21 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0 h1:QkFMT0vLDH4jzcnsbQh
github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0/go.mod h1:MgevoYLHRx/KP6LZeY7uMyoQPxD+11ed4eJMN5+faD4=
github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0 h1:FTaVxiDPoV9o6k2OFBijhQO8zWZf6uYHIAc/cRYsCSA=
github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0/go.mod h1:6ourNr6TBk/2SB2V4In+o2eqZd/DIdiBLnoxvQ3UyWk=
github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis h1:uashKgjy7XCNZNb00+3GheWtJXnS9DnAkYQ1X89cAIg=
github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis/go.mod h1:XC/YhKcHsxRy8shbYICwf+oWeYTCC2kpL5/clSJbt+U=
github.com/TheThingsNetwork/go-cayenne-lib v1.2.0 h1:yW4x7mNk2vyNTUYNRhda9oV8caLePMNR7Z5QbaG5Ifs=
github.com/TheThingsNetwork/go-cayenne-lib v1.2.0/go.mod h1:HTTus7UIBhXKvLIeNGybbG1o7wr4zwwVbbUXwFqrtp0=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand Down Expand Up @@ -170,8 +168,10 @@ github.com/blevesearch/zap/v15 v15.0.3/go.mod h1:iuwQrImsh1WjWJ0Ue2kBqY83a0rFtJT
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
Expand Down Expand Up @@ -258,6 +258,7 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
Expand Down Expand Up @@ -288,6 +289,8 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
Expand Down Expand Up @@ -563,13 +566,19 @@ github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
Expand Down Expand Up @@ -636,6 +645,7 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c
github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0=
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
Expand Down Expand Up @@ -722,6 +732,8 @@ github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzH
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/throttled/throttled v2.2.5+incompatible h1:65UB52X0qNTYiT0Sohp8qLYVFwZQPDw85uSa65OljjQ=
github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
github.com/throttled/throttled/v2 v2.12.0 h1:IezKE1uHlYC/0Al05oZV6Ar+uN/znw3cy9J8banxhEY=
github.com/throttled/throttled/v2 v2.12.0/go.mod h1:+EAvrG2hZAQTx8oMpBu8fq6Xmm+d1P2luKK7fIY1Esc=
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
Expand Down Expand Up @@ -763,6 +775,7 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA=
go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw=
go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY=
go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4=
Expand Down Expand Up @@ -881,10 +894,12 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand Down Expand Up @@ -939,7 +954,10 @@ 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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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 All @@ -954,6 +972,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
7 changes: 7 additions & 0 deletions pkg/config/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,11 @@ func (f MQTTConfigProviderFunc) GetMQTTConfig(ctx context.Context) (*MQTT, error
return f(ctx)
}

// RateLimitingRedis represents configuration for the in-Redis rate limiting store.
type RateLimitingRedis struct {
Client *redis.Client `name:"-"`
}

// RateLimitingProfile represents configuration for a rate limiting class.
type RateLimitingProfile struct {
Name string `name:"name" description:"Rate limiting class name"`
Expand All @@ -569,7 +574,9 @@ type RateLimiting struct {
URL string `name:"url" description:"URL, which contains rate limiting configuration"`
Blob BlobPathConfig `name:"blob"`

Provider string `name:"provider" description:"Rate limiting store provider (memory, redis)"`
Memory RateLimitingMemory `name:"memory" description:"In-memory rate limiting store configuration"`
Redis RateLimitingRedis `name:"redis" description:"In-Redis rate limiting store configuration"`
Profiles []RateLimitingProfile `name:"profiles" description:"Rate limiting profiles"`
}

Expand Down
14 changes: 10 additions & 4 deletions pkg/gatewayserver/io/udp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@

package udp

import "time"
import (
"time"

"go.thethings.network/lorawan-stack/v3/pkg/config"
)

// RateLimitingConfig contains configuration settings for the rate limiting
// capabilities of the UDP gateway frontend firewall.
type RateLimitingConfig struct {
Enable bool `name:"enable" description:"Enable rate limiting for gateways"`
Messages int `name:"messages" description:"Number of past messages to check timestamp for"`
Threshold time.Duration `name:"threshold" description:"Filter packet if timestamp is not newer than the older timestamps of the previous messages by this threshold"`
Enable bool `name:"enable" description:"Enable rate limiting for gateways"`
Messages int `name:"messages" description:"Number of past messages to check timestamp for"`
Threshold time.Duration `name:"threshold" description:"Filter packet if timestamp is not newer than the older timestamps of the previous messages by this threshold"` //nolint:lll
Provider string `name:"provider" description:"Rate limiting store provider (memory, redis)"`
Redis config.RateLimitingRedis `name:"redis" description:"In-Redis rate limiting store configuration"`
}

// Config contains configuration settings for the UDP gateway frontend.
Expand Down
5 changes: 4 additions & 1 deletion pkg/gatewayserver/io/udp/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ func Serve(ctx context.Context, server io.Server, conn *net.UDPConn, conf Config
if conf.RateLimiting.Enable {
firewall = NewRateLimitingFirewall(firewall, conf.RateLimiting.Messages, conf.RateLimiting.Threshold)
}
limitLogs, err := ratelimit.NewProfile(ctx, limitLogsConfig, limitLogsSize)
limitLogs, err := ratelimit.NewProfile(ctx, limitLogsConfig, ratelimit.StoreConfig{
Provider: conf.RateLimiting.Provider,
Redis: conf.RateLimiting.Redis.Client,
})
if err != nil {
return err
}
Expand Down
37 changes: 30 additions & 7 deletions pkg/ratelimit/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ package ratelimit
import (
"context"

"github.com/throttled/throttled"
"github.com/throttled/throttled/v2"
redisstore "github.com/throttled/throttled/v2/store/goredisstore.v9"
"github.com/throttled/throttled/v2/store/memstore"
"go.thethings.network/lorawan-stack/v3/pkg/config"
"go.thethings.network/lorawan-stack/v3/pkg/errors"
"go.thethings.network/lorawan-stack/v3/pkg/httpclient"
ttnredis "go.thethings.network/lorawan-stack/v3/pkg/redis"
"gopkg.in/yaml.v2"
)

Expand All @@ -30,6 +32,13 @@ const defaultMaxSize = 1 << 12

var errRateLimitExceeded = errors.DefineResourceExhausted("rate_limit_exceeded", "rate limit of `{rate}` accesses per minute exceeded for resource `{key}`")

// StoreConfig represents configuration for rate limiting stores.
type StoreConfig struct {
Provider string
Memory config.RateLimitingMemory
Redis *ttnredis.Client
}

// New creates a new ratelimit.Interface from configuration.
func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConfig, httpClientProvider httpclient.Provider) (Interface, error) {
defaultLimiter := &NoopRateLimiter{}
Expand Down Expand Up @@ -64,7 +73,11 @@ func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConf
if len(profile.Associations) == 0 {
continue
}
limiter, err := NewProfile(ctx, profile, conf.Memory.MaxSize)
limiter, err := NewProfile(ctx, profile, StoreConfig{
Provider: conf.Provider,
Memory: conf.Memory,
Redis: conf.Redis.Client,
})
if err != nil {
return nil, err
}
Expand All @@ -77,15 +90,25 @@ func New(ctx context.Context, conf config.RateLimiting, blobConf config.BlobConf

var errInvalidRate = errors.DefineInvalidArgument("invalid_rate", "invalid rate `{rate}` for profile `{name}`")

func newStore(conf StoreConfig) (store throttled.GCRAStoreCtx, err error) {
switch conf.Provider {
case "redis":
return redisstore.NewCtx(conf.Redis, conf.Redis.Key(""))

default:
return memstore.NewCtx(int(conf.Memory.MaxSize))
}
}

// NewProfile returns a new ratelimit.Interface from profile configuration.
func NewProfile(ctx context.Context, conf config.RateLimitingProfile, size uint) (Interface, error) {
if size == 0 {
size = defaultMaxSize
func NewProfile(ctx context.Context, conf config.RateLimitingProfile, storeConf StoreConfig) (Interface, error) {
if s := &storeConf.Memory.MaxSize; *s == 0 {
*s = defaultMaxSize
}
if conf.MaxPerMin == 0 {
return nil, errInvalidRate.WithAttributes("rate", conf.MaxPerMin, "name", conf.Name)
}
store, err := memstore.New(int(size))
store, err := newStore(storeConf)
if err != nil {
return nil, err
}
Expand All @@ -96,7 +119,7 @@ func NewProfile(ctx context.Context, conf config.RateLimitingProfile, size uint)
MaxRate: throttled.PerMin(int(conf.MaxPerMin)),
MaxBurst: int(conf.MaxBurst - 1),
}
limiter, err := throttled.NewGCRARateLimiter(store, quota)
limiter, err := throttled.NewGCRARateLimiterCtx(store, quota)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/ratelimit/rate_limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package ratelimit
import (
"context"

"github.com/throttled/throttled"
"github.com/throttled/throttled/v2"
"go.thethings.network/lorawan-stack/v3/pkg/log"
)

Expand Down
Loading

0 comments on commit e64c902

Please sign in to comment.