Cheatsheet to setup Envoy to proxy Redis traffic using TLS and Redis AUTH
.
I’m writing this up since i found it really tricky to setup the envoy side of things…especially with both downstream and upstream AUTH
:
hope this helps you spend some hours on other things..
Setup a go redis client app to talk via TLS to envoy. Envoy will then proxy requests to Redis server.
Both client->envoy->redis
is secured by redis AUTH
client->envoy-->redis
uses mTLS end to end. client->redis
is on port :6000
while envoy->redis
is on port :6379
You can find the source here
Download the source files froe the git repo here. You should end up with:
git clonehttps://github.com/salrashid123/envoy_redis
basic.yaml
: Envoy config fileCA_crt.epm
: The CA Cert for mtlsserver.crt
, server.key
: Server certs envoy will useclient.crt
, client.key
: client side certs the go app will usemain.go
: Redis golang client that will connect to EnvoyFirst edit /etc/hosts
and add the following to make it easier for TLS handshake
127.0.0.1 server.domain.com
Once you donwload redis, edit redis.conf
and uncomment the following line to enable default user AUTH
:
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatiblity
# layer on top of the new ACL system. The option effect will be just setting
# the password for the default user. Clients will still authenticate using
# AUTH <password> as usually, or more explicitly with AUTH default <password>
# if they follow the new protocol: both will work.
#
requirepass foobared
Start Redis:
redis-server --tls-port 6379 --port 0 \
--tls-cert-file server.crt \
--tls-key-file server.key \
--tls-ca-cert-file CA_crt.pem
Start Envoy:
envoy -c basic.yaml -l debug
The whole reason for this article is because i found it hard to configure enovy…so here it is:
Some things to point out below:
tls_context
thatfoo
transport_socket
does thatfoobared
In enovy-speak, the client is downstream while redis is upstream as far as envoy is concerned.
static_resources:
listeners:
- name: redis_listener
address:
socket_address:
address: 0.0.0.0
port_value: 6000
filter_chains:
- filters:
- name: envoy.redis_proxy
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.redis_proxy.v2.RedisProxy
stat_prefix: egress_redis
settings:
op_timeout: 5s
prefix_routes:
catch_all_route:
cluster: redis_cluster
downstream_auth_password:
inline_string: "bar"
tls_context:
common_tls_context:
tls_certificates:
- certificate_chain:
filename: "server.crt"
private_key:
filename: "server.key"
validation_context:
trusted_ca:
filename: CA_crt.pem
clusters:
- name: redis_cluster
connect_timeout: 1s
type: strict_dns
load_assignment:
cluster_name: redis_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 6379
typed_extension_protocol_options:
envoy.filters.network.redis_proxy:
"@type": type.googleapis.com/google.protobuf.Struct
value:
auth_password:
inline_string: "foobared"
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
common_tls_context:
tls_certificates:
certificate_chain: { "filename": "client.crt" }
private_key: { "filename": "client.key" }
validation_context:
trusted_ca:
filename: CA_crt.pem
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
main.go
connects to envoy on port :6000
and presents a client certificate to it:
caCert, err := ioutil.ReadFile("CA_crt.pem")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cer, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
fmt.Printf("%v", err)
return
}
config := &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cer},
ServerName: "server.domain.com",
}
client := redis.NewClient(&redis.Options{
Addr: "localhost:6000", // envoy
Password: "bar", //envoy
//Addr: "localhost:6379", //direct
//Password: "foobared", // direct
DB: 0, // use default DB
TLSConfig: config,
})
pong, err := client.Ping().Result()
if err != nil {
fmt.Printf("Unable to ping %v\n", err)
return
}
fmt.Println(pong, err)
If you run the app now you’ll see a pong and the value you just saved:
$ go run main.go
PONG <nil>
key value
Note, you can switch the go client between going through enovy or directly to redis by commenting out the sections
client := redis.NewClient(&redis.Options{
Addr: "localhost:6000", // envoy
Password: "bar", //envoy
//Addr: "localhost:6379", //direct
//Password: "foobared", // direct
DB: 0, // use default DB
TLSConfig: config,
})
…yeah, thats it..
This site supports webmentions. Send me a mention via this form.