Redis 6 Deployment with TLS Authentication on CentOS 7
By: Tutu Godfrey Oritseshutieyimi
Tags: Deployment, DevOps, Tls, Redis, Centos

Redis is a popular in-memory data structure store, that can be used as a database, cache, and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglog, geospatial indexes with radius queries, and streams. Redis has built-in replication, Lua scripting, LRU eviction transaction, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster. There is so much that you can do with Redis. In this post, I will go through a step by step process on how to install and configure Redis securely with TLS authentication on a CentOS machine. Let begin.

Please note this demonstration is done on a fresh installation of a virtual machine with limited packages available. Your system might be different depending on what you might have installed and configured in the past. Also, I’m using a root account. If you are not using root account, you would have to use and account with a root privilege and add sudo to the beginning of the commands

We begin by updating the CentOS package repository

[root@redis-host ~]# yum update -y

Next, we need to install a couple of packages that are needed to compile and install Redis from source.

[root@redis-host ~]# yum install wget -y [root@redis-host ~]# yum install tcl -y [root@redis-host ~]# yum install gcc -y [root@redis-host ~]# yum install centos-release-scl -y [root@redis-host ~]# yum install devtoolset-9-gcc devtooset-g-gcc-c++ devtoolset-9-binutils -y [root@redis-host ~]# yum install openssl-devel* -y

Run the following command to update GCC

[root@redis-host ~]# scl enable devtoolset-9 bash [root@redis-host ~]# echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile

Next, we create a Redis user, create directories used by Redis, and set necessary permissions on them. Execute the following command.

[root@redis-host ~]# useradd --system redis [root@redis-host ~]# mkdir /var/lib/redis [root@redis-host ~]# chown redis:redis /var/lib/redis [root@redis-host ~]# mkdir /var/log/redis [root@redis-host ~]# touch /var/log/redis/redis.log [root@redis-host ~]# chmod 660 /var/log/redis [root@redis-host ~]# chmod 640 /var/log/redis/redis.log [root@redis-host ~]# mkdir /etc/redis # we'll store redis.conf file here [root@redis-host ~]# chown -R redis:redis /etc/redis

Now that we have installed the packages and set up directories and files for Redis, let’s download and install Redis. We will be doing the installation in the /tmp/redis directory

[root@redis-host ~]# cd /tmp/ [root@redis-host tmp]# mkdir redis [root@redis-host tmp]# cd redis/ [root@redis-host redis]# wget http://download.redis.io/releases/redis-6.0.5.tar.gz [root@redis-host redis]# ls redis-6.0.5.tar.gz [root@redis-host redis]# sha256sum redis-6.0.5.tar.gz # view/confirm the shasum of the downloaded file. 42cf86a114d2a451b898fcda96acd4d01062a7dbaaad2801d9164a36f898f596 redis-6.0.5.tar.gz [root@redis-host redis]# tar -xzvf redis-6.0.5.tar.gz # untar the downloaded file [root@redis-host redis]# cd redis-6.0.5 [root@redis-host redis-6.0.5]# make BUILD_TLS=yes install

Note: incase you get an error related to memory during the compilation, you may want to use this command instead. make BUILD_TLS=yes MALLOC=libc install We are using BUILD_TLS=yes to enable Redis to compile with TLS support.

If the installation is successful, we should have the redis.conf file in the current working directory. We need to move it to the /etc/redis/

sudo cp redis.conf /etc/redis

[root@redis-host redis-6.0.5]# cp redis.conf /etc/redis/ [root@redis-host redis-6.0.5]# chown redis:redis /etc/redis/redis.conf [root@redis-host redis-6.0.5]# chmod 640 /etc/redis/redis.conf

Now, the installation is complete. We should be able to start our Redis server and test the installation. Any of the following commands will enable you to start the Redis server.

[root@redis-host redis-6.0.5]# redis-server [root@redis-host redis-6.0.5]# redis-server /etc/redis/redis.conf [root@redis-host redis-6.0.5]# /usr/local/bin/redis-server /etc/redis/redis.conf sudo runuser -u redis /usr/local/bin/redis-server /etc/redis/redis.conf

You can append & to the command to run the redis-server in the background if you do not have access to another terminal.

run redis-cli to start the Redis command-line client. You should be presented with a prompt from which you can communicate with the Redis server.

[root@redis-host redis-6.0.5]# redis-cli 127.0.0.1:6379> ping PONG 127.0.0.1:6379> ping hello "hello" 127.0.0.1:6379> 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> set name "John doe" OK 127.0.0.1:6379> set email johndoe@example.com OK 127.0.0.1:6379> get email "johndoe@example.com"

Our Redis server is now functional. How about having the server started automatically each time the system reboots? Let create a systemd unit to take care of that for us.

User-defined systemd units are placed in /etc/systemd/system/ with the .service extension for service units and that is what we are going to do here. Open the create the file by /etc/systemd/system/redis.service and add the following configuration.

sudo vi /etc/systemd/system/redis.service open the file

[Unit] Description=The Redis Server After=network.target [Service] PIDFile=/run/redis.pid ExecStartPre=/usr/bin/rm -f /run/redis.pid ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf Restart=on-failure RestartUSec=100m KillSignal=SIGQUIT TimeoutStopSec=5 KillMode=process PrivateTmp=true [Install] WantedBy=multi-user.target

The following commands will restart the systemd daemon, enable and start the Redis service.

[root@redis-host redis-6.0.5]# systemctl daemon-reload [root@redis-host redis-6.0.5]# systemctl enable --now redis.service Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /etc/systemd/system/redis.service. [root@redis-host redis-6.0.5]# systemctl status redis.service # check the status of the service ● redis.service - The Redis Server Loaded: loaded (/etc/systemd/system/redis.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2020-12-09 11:51:38 UTC; 18s ago Process: 13526 ExecStartPre=/usr/bin/rm -f /run/redis.pid (code=exited, status=0/SUCCESS) Main PID: 13527 (redis-server) CGroup: /system.slice/redis.service └─13527 /usr/local/bin/redis-server 127.0.0.1:6379

The next time the system reboots, the Redis service will automatically be started. Well, we can start the service right away, run the following command.

In systemd you can enable a system by running systemctl enable redis.service and start the service with systemctl start redis.service . You can combine both operations in one command as we’ve done above systemctl enable --now redis.service

Great, our Redis server can now run as a systemd unit. This is just a simple demonstration of how to create a systemd unit to run your services.

Let’s now connect with the Redis server using the redis-cli issue the command in your terminal.

[root@redis-host redis-6.0.5]# redis-cli 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> set name godfrey OK 127.0.0.1:6379> get name "godfrey"

We have successfully installed and configure Redis to run automatically on boot.

Redis 6 provides the capability to secure network communication to Redis using TLS. In the remaining part of the article, we will be configuring TLS in our Redis deployment

We will now demonstrate how to set up an SSL/TLS authentication to maximize the security of our Redis server and prevent the service from attacks. Let’s begin by creating a self-signed certificate.

We will perform the task of generating the keys and certificates in the /tmp/certs directory. Thereafter we move them to the appropriate locations, create the directory.

[root@redis-host redis-6.0.5]# mkdir /tmp/certs && cd /tmp/certs

In the following commands, we are generating an issuing certificate signing private keys. With the private key generated we are creating the issuing certificate with output save to ca.crt .

[root@redis-host certs]# openssl genrsa -out ca.key 4096 [root@redis-host certs]# openssl req -x509 -new -nodes -sha256 -key ca.key -days 365 -subj '/O=Redislabs/CN=Redis Prod CA' -out ca.crt

In the next two commands, we are generating the server private key. We use the server private key and the issuing certificate and certificate signing key to generate the server certificate.

[root@redis-host certs]# openssl genrsa -out redis.key 2048 [root@redis-host certs]# mkdir /etc/ssl/private [root@redis-host certs]# openssl req -new -sha256 -nodes -key redis.key -subj '/O=Redislabs/CN=Production Redis' | openssl x509 -req -sha256 -CA ca.crt -CAkey ca.key -CAserial /etc/ssl/private/ca.txt -CAcreateserial -days 365 -out redis.crt

[Output]

Signature ok subject=/O=Redislabs/CN=Production Redis Getting CA Private Key

Next, we move the files to the appropriate locations and set necessary permissions on them.

[root@redis-host certs]# mkdir /usr/local/share/ca-certificates [root@redis-host certs]# cp ca.crt /usr/local/share/ca-certificates/ [root@redis-host certs]# cp ca.key /etc/ssl/private/ [root@redis-host certs]# cp redis.key /etc/ssl/private/ [root@redis-host certs]# cp redis.crt /etc/ssl/ [root@redis-host certs]# chown redis:redis /usr/local/share/ca-certificates/ca.crt [root@redis-host certs]# chmod 644 /usr/local/share/ca-certificates/ca.crt [root@redis-host certs]# chown redis:redis /etc/ssl/private/ca.key [root@redis-host certs]# chmod 400 /etc/ssl/private/ca.key [root@redis-host certs]# chown redis:redis /etc/ssl/private/redis.key [root@redis-host certs]# chmod 400 /etc/ssl/private/redis.key [root@redis-host certs]# chown redis:redis /etc/ssl/redis.crt [root@redis-host certs]# chmod 644 /etc/ssl/redis.crt

Now we need to update our redis.conf file with the server certificate information. open the file /etc/redis/redis.conf

vi /etc/redis/redis.conf or use your preferred editor. You need to locate the lines shown below and make the appropriate changes

# port 0 port 0 # tls-port 6379 tls-port 6379

# tls-cert-file redis.crt # tls-key-file redis.key tls-cert-file /etc/ssl/redis.crt tls-key-file /etc/ssl/private/redis.key

# tls-ca-cert-file ca.crt tls-ca-cert-file /usr/local/share/ca-certificates/ca.crt # tls-ca-cert-dir /etc/ssl/certs # tls-auth-clients no tls-auth-clients no

# tls-protocols "TLSv1.2 TLSv1.3" tls-protocols "TLSv1.2 TLSv1.3"

# tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256 tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256

# tls-prefer-server-ciphers yes tls-prefer-server-ciphers no

With the configurations in place, we are ready to restart the Redis service.

[root@redis-host certs]# systemctl restart redis [root@redis-host certs]# systemctl status redis [OUTPUT] ● redis.service - The Redis Server Loaded: loaded (/etc/systemd/system/redis.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2020-12-09 12:38:34 UTC; 3s ago Process: 14318 ExecStartPre=/usr/bin/rm -f /run/redis.pid (code=exited, status=0/SUCCESS) Main PID: 14319 (redis-server) CGroup: /system.slice/redis.service └─14319 /usr/local/bin/redis-server 127.0.0.1:6379

To test the configuration, we first connect to the Redis server with redis-cli without providing the TLS credentials.

[root@redis-host certs]# redis-cli 127.0.0.1:6379> get name Error: Connection reset by peer [root@redis-host certs]#

As you can see, the connection is closed by the server. We can’t transmit packets to the server with been properly authenticated. Now let’s try the connection again, this time providing the required TLS credentials.

[root@redis-host certs]# redis-cli --tls --cacert /usr/local/share/ca-certificates/ca.crt 127.0.0.1:6379> get name "godfrey" 127.0.0.1:6379> get email (nil) 127.0.0.1:6379> set email godfrey@example.com OK 127.0.0.1:6379> get email "godfrey@example.com" 127.0.0.1:6379>

Now, nobody can send or receive packets from our Redis server without being properly authenticated.

As a final part of the authentication process, we would like the Redis client to authenticate itself before connecting to the Redis server with client authentication. So, we need to enable client authentication in our redis.conf . With client authentication enabled in the Redis server configuration, clients wanting to connect to the server must present a certificate issued by a trusted certificate authority. We will use our previously generated issuing certificate along with a new client private key which we will generate to generate the client certificate that the Redis server can trust to allow connections.

cd /tmp/cert/ change working directory

In the following commands, we will generate the client private key, then use the key along with the issuing certificate key and certificate to generate the client certificate.

[root@redis-host certs]# openssl genrsa -out client.key 2048

openssl genrsa -out client.key 2048 generate the client private key.

Next, we use the private key along with the issuing certificate to generate the client certificate.

[root@redis-host certs]# openssl req -new -sha256 -key client.key -subj '/O=Redislabs/CN=Redis Client' | openssl x509 -req -sha256 -CA ca.crt -CAkey ca.key -CAserial /etc/ssl/private/ca.txt -CAcreateserial -days 365 -out client.crt [Output] Signature ok subject=/O=Redislabs/CN=Redis Client Getting CA Private Key

Next, we move the client key and certificate to the appropriate locations and set permission on them. Run the following commands.

[root@redis-host certs]# mkdir /etc/ssl/client [root@redis-host certs]# cp client.key /etc/ssl/client/ [root@redis-host certs]# cp client.crt /etc/ssl/client/ [root@redis-host certs]# chmod 400 /etc/ssl/client/client.{key,crt}

Note: I’ve skip a step that might be necessary here depending on you need. you might want to create a Linux user to that you can use for making client connection to the redis server. Say for example the application that can connect to the server. In that case you would want to make sure that only the application have read access to the client credentials. You should run the command chown app:app /etc/ssl/client/client.{key,crt} assuming your application user is app .

Now we can enable client authentication, open the redis.conf file

vi /etc/redis/redis.conf Search for and set tls-auth-clients to yes

# # tls-auth-clients no tls-auth-clients yes

Restart the Redis service for this change to take effect.

[root@redis-host certs]# systemctl restart redis.service [root@redis-host certs]# systemctl status redis ● redis.service - The Redis Server Loaded: loaded (/etc/systemd/system/redis.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2020-12-09 13:05:35 UTC; 3s ago Process: 14717 ExecStartPre=/usr/bin/rm -f /run/redis.pid (code=exited, status=0/SUCCESS) Main PID: 14718 (redis-server) CGroup: /system.slice/redis.service └─14718 /usr/local/bin/redis-server 127.0.0.1:6379

Let test the new configuration with a client connection to the server.

[[root@redis-host certs]# redis-cli --tls --cacert /usr/local/share/ca-certificates/ca.crt --cert /etc/ssl/client/client.crt --key /etc/ssl/client/client.key 127.0.0.1:6379> get name "godfrey" 127.0.0.1:6379> get email "godfrey@example.com" 127.0.0.1:6379> ping PONG 127.0.0.1:6379> ping hello "hello" 127.0.0.1:6379>

The configuration is working. What happens if you don’t provide the client credential on connecting to the server? Well, let’s try that out. Close the current connection and make a new connection. This time without providing the client certification and key.

[root@redis-host certs]# redis-cli --tls --cacert /usr/local/share/ca-certificates/ca.crt Could not connect to Redis at 127.0.0.1:6379: SSL_connect failed: sslv3 alert handshake failure not connected>

You see that! We must be properly authenticated to be able to connect to the Redis server.

In this demo, we have used a self-signed certificate, in production, you will have a certificate authority issue the certificate for you.

What have we done so far? We created directories and files required for our Redis installation, set ownership and permission on the files, download, extract, and compile Redis. Then we created a systemd unit to manage the Redis server as a service, that way the service will always be life when the system reboots. Finally, we generated private keys and self-signed certificates for configuring TLS in our Redis deployment. I hope this article proves helpful to you in the secure deployment of your Redis server. Leave you likes, claps, and comments. Thanks for reading!