Skip to content

Commit

Permalink
feat: enhance TLS support by taking path to CA file for redis conn (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
bhepburn authored Oct 25, 2021
1 parent 1294867 commit f62e248
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ bootstrap_redis_tls: redis.conf redis-per-second.conf
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 update-ca-certificates - not needed with the RedisTlsCACerts feature
sudo stunnel redis.conf
sudo stunnel redis-per-second.conf
.PHONY: docs_format
Expand Down
10 changes: 10 additions & 0 deletions src/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/tls"
"time"

"github.com/envoyproxy/ratelimit/src/utils"
"github.com/kelseyhightower/envconfig"
"google.golang.org/grpc"
)
Expand Down Expand Up @@ -58,6 +59,8 @@ type Settings struct {
RedisTls bool `envconfig:"REDIS_TLS" default:"false"`
// TODO: Make this setting configurable out of the box instead of having to provide it through code.
RedisTlsConfig *tls.Config
// Custom logic to allow CA Certs to be specified
RedisTlsCACerts string `envconfig:"REDIS_TLS_CA_CERTS" default:""`

// RedisPipelineWindow sets the duration after which internal pipelines will be flushed.
// If window is zero then implicit pipelining will be disabled. Radix use 150us for the
Expand Down Expand Up @@ -102,6 +105,13 @@ func NewSettings() Settings {
panic(err)
}

if s.RedisTlsCACerts != "" {
s.RedisTlsConfig, err = utils.GenerateTlsConfig(s.RedisTlsCACerts)
if err != nil {
panic(err)
}
}

return s
}

Expand Down
29 changes: 29 additions & 0 deletions src/utils/utilities.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package utils

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"

pb "github.com/envoyproxy/go-control-plane/envoy/service/ratelimit/v3"
"github.com/golang/protobuf/ptypes/duration"
logger "github.com/sirupsen/logrus"
)

// Interface for a time source.
Expand Down Expand Up @@ -41,3 +46,27 @@ func Max(a uint32, b uint32) uint32 {
}
return b
}

func GenerateTlsConfig(redisTlsCACerts string) (*tls.Config, error) {
// Get the SystemCertPool, continue with an empty pool on error
rootCAs, _ := x509.SystemCertPool()
if rootCAs == nil {
rootCAs = x509.NewCertPool()
}

// Read in the cert file
certs, err := ioutil.ReadFile(redisTlsCACerts)
if err != nil {
return nil, err
}

// Append our cert to the system pool
if ok := rootCAs.AppendCertsFromPEM(certs); !ok {
logger.Warnf("No certs appended, using system certs only")
}

// Trust the augmented cert pool in our client
return &tls.Config{
RootCAs: rootCAs,
}, nil
}
29 changes: 28 additions & 1 deletion test/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/envoyproxy/ratelimit/src/memcached"
"github.com/envoyproxy/ratelimit/src/service_cmd/runner"
"github.com/envoyproxy/ratelimit/src/settings"
"github.com/envoyproxy/ratelimit/src/utils"
"github.com/envoyproxy/ratelimit/test/common"
"github.com/golang/protobuf/ptypes/duration"
"github.com/kelseyhightower/envconfig"
Expand Down Expand Up @@ -233,9 +234,35 @@ func TestMultiNodeMemcache(t *testing.T) {
})
}

func TestTlsConfigFailure(t *testing.T) {
s := makeSimpleRedisSettings(16381, 16382, false, 0)
s.RedisTlsConfig = nil
s.RedisAuth = "password123"
s.RedisTls = true
s.RedisPerSecondAuth = "password123"
s.RedisPerSecondTls = true

enable_local_cache := s.LocalCacheSizeInBytes > 0

// HACK: Wait for the server to come up. Make a hook that we can wait on
common.WaitForTcpPort(context.Background(), s.GrpcPort, 1*time.Second)

assert := assert.New(t)
conn, err := grpc.Dial(fmt.Sprintf("localhost:%v", s.GrpcPort), grpc.WithInsecure())
assert.NoError(err)
defer conn.Close()
c := pb.NewRateLimitServiceClient(conn)

// Assert this fails because of missing TLS CA Config Definition and the test Redis certs are self-signed
_, err = c.ShouldRateLimit(
context.Background(),
common.NewRateLimitRequest("reload", [][][2]string{{{getCacheKey("block", enable_local_cache), "foo"}}}, 1))
assert.EqualError(err, "rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial tcp 127.0.0.1:8083: connect: connection refused\"")
}

func testBasicConfigAuthTLS(perSecond bool, local_cache_size int) func(*testing.T) {
s := makeSimpleRedisSettings(16381, 16382, perSecond, local_cache_size)
s.RedisTlsConfig = nil
s.RedisTlsConfig, _ = utils.GenerateTlsConfig("/usr/local/share/ca-certificates/redis-stunnel.crt")
s.RedisAuth = "password123"
s.RedisTls = true
s.RedisPerSecondAuth = "password123"
Expand Down

0 comments on commit f62e248

Please sign in to comment.