From 15176ba16ac4727131fbb329f8db9d6871ddb401 Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Wed, 3 Jul 2019 13:05:24 -0600 Subject: [PATCH 1/9] basic redis tls and auth client --- src/redis/driver_impl.go | 26 ++++++++++++++++++++++++++ src/service_cmd/runner/runner.go | 4 ++-- src/settings/settings.go | 3 ++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/redis/driver_impl.go b/src/redis/driver_impl.go index eac51fbf..c6e41afb 100644 --- a/src/redis/driver_impl.go +++ b/src/redis/driver_impl.go @@ -5,6 +5,7 @@ import ( "github.com/lyft/ratelimit/src/assert" "github.com/mediocregopher/radix.v2/pool" "github.com/mediocregopher/radix.v2/redis" + "crypto/tls" logger "github.com/sirupsen/logrus" ) @@ -73,6 +74,31 @@ func NewPoolImpl(scope stats.Scope, socketType string, url string, poolSize int) stats: newPoolStats(scope)} } +func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int) Pool { + logger.Warnf("connecting to redis on tls %s with pool size %d", url, poolSize) + df := func(network, addr string) (*redis.Client, error) { + conn, err := tls.Dial("tcp", addr, &tls.Config{}) + if err != nil { + return nil, err + } + client, err := redis.NewClient(conn) + + if err != nil { + return nil, err + } + if err = client.Cmd("AUTH", auth).Err; err != nil { + client.Close() + return nil, err + } + return client, nil + } + pool, err:= pool.NewCustom("tcp", url, 10, df) + checkError(err) + return &poolImpl{ + pool: pool, + stats: newPoolStats(scope)} +} + func (this *connectionImpl) PipeAppend(cmd string, args ...interface{}) { this.client.PipeAppend(cmd, args...) this.pending++ diff --git a/src/service_cmd/runner/runner.go b/src/service_cmd/runner/runner.go index cd853517..9fc027b1 100644 --- a/src/service_cmd/runner/runner.go +++ b/src/service_cmd/runner/runner.go @@ -31,14 +31,14 @@ func Run() { var perSecondPool redis.Pool if s.RedisPerSecond { - perSecondPool = redis.NewPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisPerSecondSocketType, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) + perSecondPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisAuth, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) } service := ratelimit.NewService( srv.Runtime(), redis.NewRateLimitCacheImpl( - redis.NewPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisSocketType, s.RedisUrl, s.RedisPoolSize), + redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisAuth, s.RedisUrl, s.RedisPoolSize), perSecondPool, redis.NewTimeSourceImpl(), rand.New(redis.NewLockedSource(time.Now().Unix())), diff --git a/src/settings/settings.go b/src/settings/settings.go index 89095547..13bf6da8 100644 --- a/src/settings/settings.go +++ b/src/settings/settings.go @@ -20,13 +20,14 @@ type Settings struct { RuntimeIgnoreDotFiles bool `envconfig:"RUNTIME_IGNOREDOTFILES" default:"false"` LogLevel string `envconfig:"LOG_LEVEL" default:"WARN"` RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"unix"` - RedisUrl string `envconfig:"REDIS_URL" default:"/var/run/nutcracker/ratelimit.sock"` + RedisUrl string `envconfig:"REDIS_URL" default:"127.0.0.1:6379"` RedisPoolSize int `envconfig:"REDIS_POOL_SIZE" default:"10"` RedisPerSecond bool `envconfig:"REDIS_PERSECOND" default:"false"` RedisPerSecondSocketType string `envconfig:"REDIS_PERSECOND_SOCKET_TYPE" default:"unix"` RedisPerSecondUrl string `envconfig:"REDIS_PERSECOND_URL" default:"/var/run/nutcracker/ratelimitpersecond.sock"` RedisPerSecondPoolSize int `envconfig:"REDIS_PERSECOND_POOL_SIZE" default:"10"` ExpirationJitterMaxSeconds int64 `envconfig:"EXPIRATION_JITTER_MAX_SECONDS" default:"300"` + RedisAuth string `envconfig:"REDISAUTH"` } type Option func(*Settings) From 52c438a81c875f5da6013abe6e42ae6e64ad51be Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Wed, 3 Jul 2019 14:41:04 -0600 Subject: [PATCH 2/9] toggle tls and auth using env var --- src/redis/driver_impl.go | 8 ++++---- src/service_cmd/runner/runner.go | 15 ++++++++++++--- src/settings/settings.go | 7 +++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/redis/driver_impl.go b/src/redis/driver_impl.go index c6e41afb..5b4c7c37 100644 --- a/src/redis/driver_impl.go +++ b/src/redis/driver_impl.go @@ -1,11 +1,11 @@ package redis import ( + "crypto/tls" "github.com/lyft/gostats" "github.com/lyft/ratelimit/src/assert" "github.com/mediocregopher/radix.v2/pool" "github.com/mediocregopher/radix.v2/redis" - "crypto/tls" logger "github.com/sirupsen/logrus" ) @@ -77,12 +77,12 @@ func NewPoolImpl(scope stats.Scope, socketType string, url string, poolSize int) func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int) Pool { logger.Warnf("connecting to redis on tls %s with pool size %d", url, poolSize) df := func(network, addr string) (*redis.Client, error) { - conn, err := tls.Dial("tcp", addr, &tls.Config{}) + conn, err := tls.Dial("tcp", addr, &tls.Config{}) if err != nil { return nil, err } client, err := redis.NewClient(conn) - + if err != nil { return nil, err } @@ -92,7 +92,7 @@ func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int } return client, nil } - pool, err:= pool.NewCustom("tcp", url, 10, df) + pool, err := pool.NewCustom("tcp", url, 10, df) checkError(err) return &poolImpl{ pool: pool, diff --git a/src/service_cmd/runner/runner.go b/src/service_cmd/runner/runner.go index 9fc027b1..699b7b90 100644 --- a/src/service_cmd/runner/runner.go +++ b/src/service_cmd/runner/runner.go @@ -31,14 +31,23 @@ func Run() { var perSecondPool redis.Pool if s.RedisPerSecond { - perSecondPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisAuth, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) + if s.RedisPerSecondTls { + perSecondPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisPerSecondAuth, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) + } else { + perSecondPool = redis.NewPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisSocketType, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) + } } - + var otherPool redis.Pool + if s.RedisTls { + otherPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisAuth, s.RedisUrl, s.RedisPoolSize) + } else { + otherPool = redis.NewPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisSocketType, s.RedisUrl, s.RedisPoolSize) + } service := ratelimit.NewService( srv.Runtime(), redis.NewRateLimitCacheImpl( - redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisAuth, s.RedisUrl, s.RedisPoolSize), + otherPool, perSecondPool, redis.NewTimeSourceImpl(), rand.New(redis.NewLockedSource(time.Now().Unix())), diff --git a/src/settings/settings.go b/src/settings/settings.go index 13bf6da8..b7b642cb 100644 --- a/src/settings/settings.go +++ b/src/settings/settings.go @@ -19,15 +19,18 @@ type Settings struct { RuntimeSubdirectory string `envconfig:"RUNTIME_SUBDIRECTORY"` RuntimeIgnoreDotFiles bool `envconfig:"RUNTIME_IGNOREDOTFILES" default:"false"` LogLevel string `envconfig:"LOG_LEVEL" default:"WARN"` - RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"unix"` + RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"tcp"` RedisUrl string `envconfig:"REDIS_URL" default:"127.0.0.1:6379"` RedisPoolSize int `envconfig:"REDIS_POOL_SIZE" default:"10"` + RedisAuth string `envconfig:"REDIS_AUTH"` + RedisTls bool `envconfig:"REDIS_TLS" default:"false"` RedisPerSecond bool `envconfig:"REDIS_PERSECOND" default:"false"` RedisPerSecondSocketType string `envconfig:"REDIS_PERSECOND_SOCKET_TYPE" default:"unix"` RedisPerSecondUrl string `envconfig:"REDIS_PERSECOND_URL" default:"/var/run/nutcracker/ratelimitpersecond.sock"` RedisPerSecondPoolSize int `envconfig:"REDIS_PERSECOND_POOL_SIZE" default:"10"` + RedisPerSecondAuth string `envconfig:"REDIS_PERSECOND_AUTH"` + RedisPerSecondTls bool `envconfig:"REDIS_PERSECOND_TLS" default:"false"` ExpirationJitterMaxSeconds int64 `envconfig:"EXPIRATION_JITTER_MAX_SECONDS" default:"300"` - RedisAuth string `envconfig:"REDISAUTH"` } type Option func(*Settings) From 2ae07fdb62fd0dfd8b006121426393993d4ef4d4 Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Tue, 3 Sep 2019 17:30:28 -0600 Subject: [PATCH 3/9] add integration tests --- .travis.yml | 3 ++- Makefile | 32 +++++++++++++++++++++++++++- src/redis/driver_impl.go | 14 +++++++----- src/settings/settings.go | 8 +++---- test/integration/integration_test.go | 22 +++++++++++++++---- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab08ad70..e4508c9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ sudo: required language: go go: "1.11" services: redis-server +before_install: apt-get update -y && apt-get install stunnel4 -y install: make bootstrap -before_script: redis-server --port 6380 & +before_script: redis-server --port 6380 &;redis-server --port 6381 --requirepass passowrd123 &;redis-server --port 6382 --requirepass passowrd123 & script: make check_format tests diff --git a/Makefile b/Makefile index 1ba5b8c5..81e37e0e 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,37 @@ bootstrap: .PHONY: bootstrap_tests bootstrap_tests: cd ./vendor/github.com/golang/mock/mockgen && go install - +define REDIS_STUNNEL +cert = /etc/stunnel/private.pem +pid = /var/run/stunnel.pid +[redis] +accept = 127.0.0.1:16381 +connect = 127.0.0.1:6381 +endef +define REDIS_PER_SECOND_STUNNEL +cert = /etc/stunnel/private.pem +pid = /var/run/stunnel.pid +[redis] +accept = 127.0.0.1:16382 +connect = 127.0.0.1:6382 +endef +export REDIS_STUNNEL +export REDIS_PER_SECOND_STUNNEL +/etc/stunnel/redis.conf: + echo "$$REDIS_STUNNEL" >> $@ +/etc/stunnel/redis-per-second.conf: + echo "$$REDIS_PER_SECOND_STUNNEL" >> $@ +.PHONY: bootstrap_redis_tls +bootstrap_redis_tls: /etc/stunnel/redis.conf /etc/stunnel/redis-per-second.conf + openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ + -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \ + -keyout /etc/stunnel/key.pem -out /etc/stunnel/cert.pem + cat /etc/stunnel/key.pem /etc/stunnel/cert.pem > /etc/stunnel/private.pem + cp /etc/stunnel/cert.pem /usr/local/share/ca-certificates/redis-stunnel.crt + chmod 640 /etc/stunnel/key.pem /etc/stunnel/cert.pem /etc/stunnel/private.pem + update-ca-certificates + stunnel /etc/stunnel/redis.conf + stunnel /etc/stunnel/redis-per-second.conf .PHONY: docs_format docs_format: script/docs_check_format diff --git a/src/redis/driver_impl.go b/src/redis/driver_impl.go index 5b4c7c37..15c56f0f 100644 --- a/src/redis/driver_impl.go +++ b/src/redis/driver_impl.go @@ -2,7 +2,8 @@ package redis import ( "crypto/tls" - "github.com/lyft/gostats" + + stats "github.com/lyft/gostats" "github.com/lyft/ratelimit/src/assert" "github.com/mediocregopher/radix.v2/pool" "github.com/mediocregopher/radix.v2/redis" @@ -86,13 +87,16 @@ func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int if err != nil { return nil, err } - if err = client.Cmd("AUTH", auth).Err; err != nil { - client.Close() - return nil, err + if auth != "" { + logger.Warnf("enabling authentication to redis on tls %s", url) + if err = client.Cmd("AUTH", auth).Err; err != nil { + client.Close() + return nil, err + } } return client, nil } - pool, err := pool.NewCustom("tcp", url, 10, df) + pool, err := pool.NewCustom("tcp", url, poolSize, df) checkError(err) return &poolImpl{ pool: pool, diff --git a/src/settings/settings.go b/src/settings/settings.go index b7b642cb..bdb74b3e 100644 --- a/src/settings/settings.go +++ b/src/settings/settings.go @@ -19,16 +19,16 @@ type Settings struct { RuntimeSubdirectory string `envconfig:"RUNTIME_SUBDIRECTORY"` RuntimeIgnoreDotFiles bool `envconfig:"RUNTIME_IGNOREDOTFILES" default:"false"` LogLevel string `envconfig:"LOG_LEVEL" default:"WARN"` - RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"tcp"` - RedisUrl string `envconfig:"REDIS_URL" default:"127.0.0.1:6379"` + RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"unix"` + RedisUrl string `envconfig:"REDIS_URL" default:"/var/run/nutcracker/ratelimit.sock"` RedisPoolSize int `envconfig:"REDIS_POOL_SIZE" default:"10"` - RedisAuth string `envconfig:"REDIS_AUTH"` + RedisAuth string `envconfig:"REDIS_AUTH default:""` RedisTls bool `envconfig:"REDIS_TLS" default:"false"` RedisPerSecond bool `envconfig:"REDIS_PERSECOND" default:"false"` RedisPerSecondSocketType string `envconfig:"REDIS_PERSECOND_SOCKET_TYPE" default:"unix"` RedisPerSecondUrl string `envconfig:"REDIS_PERSECOND_URL" default:"/var/run/nutcracker/ratelimitpersecond.sock"` RedisPerSecondPoolSize int `envconfig:"REDIS_PERSECOND_POOL_SIZE" default:"10"` - RedisPerSecondAuth string `envconfig:"REDIS_PERSECOND_AUTH"` + RedisPerSecondAuth string `envconfig:"REDIS_PERSECOND_AUTH default:""` RedisPerSecondTls bool `envconfig:"REDIS_PERSECOND_TLS" default:"false"` ExpirationJitterMaxSeconds int64 `envconfig:"EXPIRATION_JITTER_MAX_SECONDS" default:"300"` } diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index c48387f3..7756a297 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -45,8 +45,24 @@ func TestBasicConfig(t *testing.T) { t.Run("WithoutPerSecondRedis", testBasicConfig("8083", "false")) t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) } - -func testBasicConfig(grpcPort, perSecond string) func(*testing.T) { +func TestTLSConfig(t *testing.T) { + t.Run("WithoutPerSecondRedis", testBasicConfigAuthTLS("8083", "false")) + t.Run("WithPerSecondRedis", testBasicConfigAuthTLS("8085", "true")) +} +func testBasicConfigAuthTLS(grpcPort, perSecond) func(*testing.T) { + os.Setenv("REDIS_PERSECOND_URL", "localhost:16382") + os.Setenv("REDIS_URL", "localhost:16381") + os.Setenv("REDIS_TLS", "true") + os.Setenv("REDIS_AUTH", "password123") + return testBasicConfig(grpcPort, perSecond) +} +func testBasicConfig(grpcPort, perSecond) func(*testing.T) { + os.Setenv("REDIS_PERSECOND_URL", "localhost:6380") + os.Setenv("REDIS_URL", "localhost:6379") + os.Setenv("REDIS_TLS", "false") + return testBasicBaseConfig(grpcPort, perSecond) +} +func testBasicBaseConfig(grpcPort, perSecond) func(*testing.T) { return func(t *testing.T) { os.Setenv("REDIS_PERSECOND", perSecond) os.Setenv("PORT", "8082") @@ -55,9 +71,7 @@ func testBasicConfig(grpcPort, perSecond string) func(*testing.T) { os.Setenv("RUNTIME_ROOT", "runtime/current") os.Setenv("RUNTIME_SUBDIRECTORY", "ratelimit") os.Setenv("REDIS_PERSECOND_SOCKET_TYPE", "tcp") - os.Setenv("REDIS_PERSECOND_URL", "localhost:6380") os.Setenv("REDIS_SOCKET_TYPE", "tcp") - os.Setenv("REDIS_URL", "localhost:6379") go func() { runner.Run() From 0563d2ec59f5c004fa997c26ccaf37e8026c5d4a Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Tue, 3 Sep 2019 17:34:09 -0600 Subject: [PATCH 4/9] add sudo in travis.yml --- .travis.yml | 11 +++++++---- Makefile | 26 +++++++++++++------------- test/integration/integration_test.go | 10 +++++----- test/redis/cache_impl_test.go | 7 ++++--- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index e4508c9e..ea43ffb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,10 @@ sudo: required language: go go: "1.11" services: redis-server -before_install: apt-get update -y && apt-get install stunnel4 -y -install: make bootstrap -before_script: redis-server --port 6380 &;redis-server --port 6381 --requirepass passowrd123 &;redis-server --port 6382 --requirepass passowrd123 & -script: make check_format tests +before_install: sudo apt-get update -y && sudo apt-get install stunnel4 -y +install: make bootstrap bootstrap_redis_tls +before_script: +- redis-server --port 6380 & +- redis-server --port 6381 --requirepass password123 & +- redis-server --port 6382 --requirepass password123 & +script: make check_format tests diff --git a/Makefile b/Makefile index 81e37e0e..888f116d 100644 --- a/Makefile +++ b/Makefile @@ -14,36 +14,36 @@ bootstrap: bootstrap_tests: cd ./vendor/github.com/golang/mock/mockgen && go install define REDIS_STUNNEL -cert = /etc/stunnel/private.pem +cert = private.pem pid = /var/run/stunnel.pid [redis] accept = 127.0.0.1:16381 connect = 127.0.0.1:6381 endef define REDIS_PER_SECOND_STUNNEL -cert = /etc/stunnel/private.pem -pid = /var/run/stunnel.pid +cert = private.pem +pid = /var/run/stunnel-2.pid [redis] accept = 127.0.0.1:16382 connect = 127.0.0.1:6382 endef export REDIS_STUNNEL export REDIS_PER_SECOND_STUNNEL -/etc/stunnel/redis.conf: +redis.conf: echo "$$REDIS_STUNNEL" >> $@ -/etc/stunnel/redis-per-second.conf: +redis-per-second.conf: echo "$$REDIS_PER_SECOND_STUNNEL" >> $@ .PHONY: bootstrap_redis_tls -bootstrap_redis_tls: /etc/stunnel/redis.conf /etc/stunnel/redis-per-second.conf +bootstrap_redis_tls: redis.conf redis-per-second.conf openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \ - -keyout /etc/stunnel/key.pem -out /etc/stunnel/cert.pem - cat /etc/stunnel/key.pem /etc/stunnel/cert.pem > /etc/stunnel/private.pem - cp /etc/stunnel/cert.pem /usr/local/share/ca-certificates/redis-stunnel.crt - chmod 640 /etc/stunnel/key.pem /etc/stunnel/cert.pem /etc/stunnel/private.pem - update-ca-certificates - stunnel /etc/stunnel/redis.conf - stunnel /etc/stunnel/redis-per-second.conf + -keyout key.pem -out cert.pem + cat key.pem cert.pem > private.pem + sudo cp cert.pem /usr/local/share/ca-certificates/redis-stunnel.crt + chmod 640 key.pem cert.pem private.pem + sudo update-ca-certificates + sudo stunnel redis.conf + sudo stunnel redis-per-second.conf .PHONY: docs_format docs_format: script/docs_check_format diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index 7756a297..b2aba726 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -46,23 +46,23 @@ func TestBasicConfig(t *testing.T) { t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) } func TestTLSConfig(t *testing.T) { - t.Run("WithoutPerSecondRedis", testBasicConfigAuthTLS("8083", "false")) - t.Run("WithPerSecondRedis", testBasicConfigAuthTLS("8085", "true")) + t.Run("WithoutPerSecondRedisTLS", testBasicConfigAuthTLS("8087", "false")) + t.Run("WithPerSecondRedisTLS", testBasicConfigAuthTLS("8089", "true")) } -func testBasicConfigAuthTLS(grpcPort, perSecond) func(*testing.T) { +func testBasicConfigAuthTLS(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:16382") os.Setenv("REDIS_URL", "localhost:16381") os.Setenv("REDIS_TLS", "true") os.Setenv("REDIS_AUTH", "password123") return testBasicConfig(grpcPort, perSecond) } -func testBasicConfig(grpcPort, perSecond) func(*testing.T) { +func testBasicConfig(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:6380") os.Setenv("REDIS_URL", "localhost:6379") os.Setenv("REDIS_TLS", "false") return testBasicBaseConfig(grpcPort, perSecond) } -func testBasicBaseConfig(grpcPort, perSecond) func(*testing.T) { +func testBasicBaseConfig(grpcPort, perSecond string) func(*testing.T) { return func(t *testing.T) { os.Setenv("REDIS_PERSECOND", perSecond) os.Setenv("PORT", "8082") diff --git a/test/redis/cache_impl_test.go b/test/redis/cache_impl_test.go index e6a9c0f6..8eb48d18 100644 --- a/test/redis/cache_impl_test.go +++ b/test/redis/cache_impl_test.go @@ -4,15 +4,16 @@ import ( "testing" pb "github.com/envoyproxy/go-control-plane/envoy/service/ratelimit/v2" - "github.com/lyft/gostats" + stats "github.com/lyft/gostats" "github.com/lyft/ratelimit/src/config" "github.com/lyft/ratelimit/src/redis" + "math/rand" + "github.com/golang/mock/gomock" "github.com/lyft/ratelimit/test/common" - "github.com/lyft/ratelimit/test/mocks/redis" + mock_redis "github.com/lyft/ratelimit/test/mocks/redis" "github.com/stretchr/testify/assert" - "math/rand" ) func TestRedis(t *testing.T) { From 34a745df00944c34aaf7fc7df9a7337fffc0338e Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Wed, 4 Sep 2019 07:56:55 -0600 Subject: [PATCH 5/9] update README --- Makefile | 2 +- README.md | 5 +++++ src/redis/driver_impl.go | 5 +++-- test/integration/integration_test.go | 19 +++++++++++++------ 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 888f116d..2110f107 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ redis-per-second.conf: .PHONY: bootstrap_redis_tls bootstrap_redis_tls: redis.conf redis-per-second.conf openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ - -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \ + -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost" \ -keyout key.pem -out cert.pem cat key.pem cert.pem > private.pem sudo cp cert.pem /usr/local/share/ca-certificates/redis-stunnel.crt diff --git a/README.md b/README.md index 4b263195..5e1f3e16 100644 --- a/README.md +++ b/README.md @@ -380,6 +380,11 @@ Ratelimit uses Redis as its caching layer. Ratelimit supports two operation mode 1. One Redis server for all limits. 1. Two Redis instances: one for per second limits and another one for all other limits. +As well Ratelimit supports TLS connections and authentication over TLS connections. These can be configured using the following environment variables: + +1. `REDIS_TLS` & `REDIS_PERSECOND_TLS`: set to `"true"` to enable a TLS connection for the specific connection type. +1. `REDIS_AUTH` & `REDIS_PERSECOND_AUTH`: set to `"password"` to enable authentication to the redis host. This requires TLS to be enabled as well for the specific connection. + ## One Redis Instance To configure one Redis instance use the following environment variables: diff --git a/src/redis/driver_impl.go b/src/redis/driver_impl.go index 15c56f0f..eb878b8a 100644 --- a/src/redis/driver_impl.go +++ b/src/redis/driver_impl.go @@ -77,6 +77,7 @@ func NewPoolImpl(scope stats.Scope, socketType string, url string, poolSize int) func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int) Pool { logger.Warnf("connecting to redis on tls %s with pool size %d", url, poolSize) + localAuth := auth df := func(network, addr string) (*redis.Client, error) { conn, err := tls.Dial("tcp", addr, &tls.Config{}) if err != nil { @@ -87,9 +88,9 @@ func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int if err != nil { return nil, err } - if auth != "" { + if localAuth != "" { logger.Warnf("enabling authentication to redis on tls %s", url) - if err = client.Cmd("AUTH", auth).Err; err != nil { + if err = client.Cmd("AUTH", localAuth).Err; err != nil { client.Close() return nil, err } diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index b2aba726..28c6af0e 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -42,24 +42,27 @@ func newDescriptorStatusLegacy( } func TestBasicConfig(t *testing.T) { - t.Run("WithoutPerSecondRedis", testBasicConfig("8083", "false")) - t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) -} -func TestTLSConfig(t *testing.T) { + //t.Run("WithoutPerSecondRedis", testBasicConfig("8083", "false")) + //t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) + t.Run("WithoutPerSecondRedisTLS", testBasicConfigAuthTLS("8087", "false")) t.Run("WithPerSecondRedisTLS", testBasicConfigAuthTLS("8089", "true")) } + func testBasicConfigAuthTLS(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:16382") os.Setenv("REDIS_URL", "localhost:16381") os.Setenv("REDIS_TLS", "true") + os.Setenv("REDIS_PERSECOND_TLS", "true") os.Setenv("REDIS_AUTH", "password123") - return testBasicConfig(grpcPort, perSecond) + os.Setenv("REDIS_PERSECOND_AUTH", "password123") + return testBasicBaseConfig(grpcPort, perSecond) } func testBasicConfig(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:6380") os.Setenv("REDIS_URL", "localhost:6379") os.Setenv("REDIS_TLS", "false") + os.Setenv("REDIS_PERSECOND_TLS", "false") return testBasicBaseConfig(grpcPort, perSecond) } func testBasicBaseConfig(grpcPort, perSecond string) func(*testing.T) { @@ -78,7 +81,7 @@ func testBasicBaseConfig(grpcPort, perSecond string) func(*testing.T) { }() // HACK: Wait for the server to come up. Make a hook that we can wait on. - time.Sleep(100 * time.Millisecond) + time.Sleep(100 * time.Second) assert := assert.New(t) conn, err := grpc.Dial(fmt.Sprintf("localhost:%s", grpcPort), grpc.WithInsecure()) @@ -170,6 +173,10 @@ func TestBasicConfigLegacy(t *testing.T) { os.Setenv("RUNTIME_ROOT", "runtime/current") os.Setenv("RUNTIME_SUBDIRECTORY", "ratelimit") + os.Setenv("REDIS_PERSECOND_URL", "localhost:6380") + os.Setenv("REDIS_URL", "localhost:6379") + os.Setenv("REDIS_TLS", "false") + os.Setenv("REDIS_PERSECOND_TLS", "false") go func() { runner.Run() }() From c93d0c5b2f5489f78dced8d12b9cb16757ad732b Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Wed, 4 Sep 2019 10:09:39 -0600 Subject: [PATCH 6/9] fix env name in settings --- src/settings/settings.go | 4 ++-- test/integration/integration_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/settings/settings.go b/src/settings/settings.go index bdb74b3e..2028c622 100644 --- a/src/settings/settings.go +++ b/src/settings/settings.go @@ -22,13 +22,13 @@ type Settings struct { RedisSocketType string `envconfig:"REDIS_SOCKET_TYPE" default:"unix"` RedisUrl string `envconfig:"REDIS_URL" default:"/var/run/nutcracker/ratelimit.sock"` RedisPoolSize int `envconfig:"REDIS_POOL_SIZE" default:"10"` - RedisAuth string `envconfig:"REDIS_AUTH default:""` + RedisAuth string `envconfig:"REDIS_AUTH" default:""` RedisTls bool `envconfig:"REDIS_TLS" default:"false"` RedisPerSecond bool `envconfig:"REDIS_PERSECOND" default:"false"` RedisPerSecondSocketType string `envconfig:"REDIS_PERSECOND_SOCKET_TYPE" default:"unix"` RedisPerSecondUrl string `envconfig:"REDIS_PERSECOND_URL" default:"/var/run/nutcracker/ratelimitpersecond.sock"` RedisPerSecondPoolSize int `envconfig:"REDIS_PERSECOND_POOL_SIZE" default:"10"` - RedisPerSecondAuth string `envconfig:"REDIS_PERSECOND_AUTH default:""` + RedisPerSecondAuth string `envconfig:"REDIS_PERSECOND_AUTH" default:""` RedisPerSecondTls bool `envconfig:"REDIS_PERSECOND_TLS" default:"false"` ExpirationJitterMaxSeconds int64 `envconfig:"EXPIRATION_JITTER_MAX_SECONDS" default:"300"` } diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index 28c6af0e..bc39da76 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -42,13 +42,13 @@ func newDescriptorStatusLegacy( } func TestBasicConfig(t *testing.T) { - //t.Run("WithoutPerSecondRedis", testBasicConfig("8083", "false")) - //t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) - + t.Run("WithoutPerSecondRedis", testBasicConfig("8083", "false")) + t.Run("WithPerSecondRedis", testBasicConfig("8085", "true")) +} +func TestBasicTLSConfig(t *testing.T) { t.Run("WithoutPerSecondRedisTLS", testBasicConfigAuthTLS("8087", "false")) t.Run("WithPerSecondRedisTLS", testBasicConfigAuthTLS("8089", "true")) } - func testBasicConfigAuthTLS(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:16382") os.Setenv("REDIS_URL", "localhost:16381") From 13719c9dfcc6a5678e060215df771b477c475436 Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Wed, 4 Sep 2019 10:32:32 -0600 Subject: [PATCH 7/9] remove format changes to cache test --- src/redis/driver_impl.go | 5 ++--- test/redis/cache_impl_test.go | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/redis/driver_impl.go b/src/redis/driver_impl.go index eb878b8a..15c56f0f 100644 --- a/src/redis/driver_impl.go +++ b/src/redis/driver_impl.go @@ -77,7 +77,6 @@ func NewPoolImpl(scope stats.Scope, socketType string, url string, poolSize int) func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int) Pool { logger.Warnf("connecting to redis on tls %s with pool size %d", url, poolSize) - localAuth := auth df := func(network, addr string) (*redis.Client, error) { conn, err := tls.Dial("tcp", addr, &tls.Config{}) if err != nil { @@ -88,9 +87,9 @@ func NewAuthTLSPoolImpl(scope stats.Scope, auth string, url string, poolSize int if err != nil { return nil, err } - if localAuth != "" { + if auth != "" { logger.Warnf("enabling authentication to redis on tls %s", url) - if err = client.Cmd("AUTH", localAuth).Err; err != nil { + if err = client.Cmd("AUTH", auth).Err; err != nil { client.Close() return nil, err } diff --git a/test/redis/cache_impl_test.go b/test/redis/cache_impl_test.go index 8eb48d18..e6a9c0f6 100644 --- a/test/redis/cache_impl_test.go +++ b/test/redis/cache_impl_test.go @@ -4,16 +4,15 @@ import ( "testing" pb "github.com/envoyproxy/go-control-plane/envoy/service/ratelimit/v2" - stats "github.com/lyft/gostats" + "github.com/lyft/gostats" "github.com/lyft/ratelimit/src/config" "github.com/lyft/ratelimit/src/redis" - "math/rand" - "github.com/golang/mock/gomock" "github.com/lyft/ratelimit/test/common" - mock_redis "github.com/lyft/ratelimit/test/mocks/redis" + "github.com/lyft/ratelimit/test/mocks/redis" "github.com/stretchr/testify/assert" + "math/rand" ) func TestRedis(t *testing.T) { From 8fe25086daee0f7f271d81cbe2ebbc204fd630a1 Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Thu, 17 Oct 2019 07:14:40 -0600 Subject: [PATCH 8/9] enable tls by default if auth is set --- src/service_cmd/runner/runner.go | 6 +++--- test/integration/integration_test.go | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/service_cmd/runner/runner.go b/src/service_cmd/runner/runner.go index 699b7b90..c5af584f 100644 --- a/src/service_cmd/runner/runner.go +++ b/src/service_cmd/runner/runner.go @@ -12,7 +12,7 @@ import ( "github.com/lyft/ratelimit/src/config" "github.com/lyft/ratelimit/src/redis" "github.com/lyft/ratelimit/src/server" - "github.com/lyft/ratelimit/src/service" + ratelimit "github.com/lyft/ratelimit/src/service" "github.com/lyft/ratelimit/src/settings" logger "github.com/sirupsen/logrus" ) @@ -31,7 +31,7 @@ func Run() { var perSecondPool redis.Pool if s.RedisPerSecond { - if s.RedisPerSecondTls { + if s.RedisPerSecondAuth != "" || s.RedisPerSecondTls { perSecondPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisPerSecondAuth, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) } else { perSecondPool = redis.NewPoolImpl(srv.Scope().Scope("redis_per_second_pool"), s.RedisSocketType, s.RedisPerSecondUrl, s.RedisPerSecondPoolSize) @@ -39,7 +39,7 @@ func Run() { } var otherPool redis.Pool - if s.RedisTls { + if s.RedisAuth != "" || s.RedisTls { otherPool = redis.NewAuthTLSPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisAuth, s.RedisUrl, s.RedisPoolSize) } else { otherPool = redis.NewPoolImpl(srv.Scope().Scope("redis_pool"), s.RedisSocketType, s.RedisUrl, s.RedisPoolSize) diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index bc39da76..3fa8e0ed 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -52,8 +52,6 @@ func TestBasicTLSConfig(t *testing.T) { func testBasicConfigAuthTLS(grpcPort, perSecond string) func(*testing.T) { os.Setenv("REDIS_PERSECOND_URL", "localhost:16382") os.Setenv("REDIS_URL", "localhost:16381") - os.Setenv("REDIS_TLS", "true") - os.Setenv("REDIS_PERSECOND_TLS", "true") os.Setenv("REDIS_AUTH", "password123") os.Setenv("REDIS_PERSECOND_AUTH", "password123") return testBasicBaseConfig(grpcPort, perSecond) @@ -81,7 +79,7 @@ func testBasicBaseConfig(grpcPort, perSecond string) func(*testing.T) { }() // HACK: Wait for the server to come up. Make a hook that we can wait on. - time.Sleep(100 * time.Second) + time.Sleep(100 * time.Millisecond) assert := assert.New(t) conn, err := grpc.Dial(fmt.Sprintf("localhost:%s", grpcPort), grpc.WithInsecure()) From 318e99ff8177f8012ba4964e323b85debbb59c1e Mon Sep 17 00:00:00 2001 From: repl-david-winiarski Date: Thu, 17 Oct 2019 07:20:47 -0600 Subject: [PATCH 9/9] increase wait time for redis servers to be ready --- test/integration/integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go index 3fa8e0ed..e1aeff79 100644 --- a/test/integration/integration_test.go +++ b/test/integration/integration_test.go @@ -79,7 +79,7 @@ func testBasicBaseConfig(grpcPort, perSecond string) func(*testing.T) { }() // HACK: Wait for the server to come up. Make a hook that we can wait on. - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) assert := assert.New(t) conn, err := grpc.Dial(fmt.Sprintf("localhost:%s", grpcPort), grpc.WithInsecure())