Module P-12·18 min read

Redis ACL rules for per-user command and key restrictions, TLS configuration for in-transit encryption, bind address and protected mode, requirepass and its limitations, and the most common Redis security misconfigurations.

P-12 — Security: ACLs, TLS, and Network Hardening

Who this module is for: You have a Redis instance in production but its security posture is "it's on a private network, nobody can reach it." That is not enough. Redis has had critical vulnerabilities exploited via misconfigured network access. This module covers the full security model: ACLs, TLS, bind configuration, and the most common Redis security mistakes that lead to data breaches and server compromise.


The Security Threat Model

Redis was designed to be deployed on trusted networks — not exposed to the internet. Its original security model was simple: strong network perimeter, single shared password. As Redis has moved into cloud environments and microservices architectures, the threat model has evolved:

  1. Unauthenticated access — Redis exposed publicly or on a poorly segmented internal network
  2. Overprivileged clients — a compromised microservice can run FLUSHALL or CONFIG SET dir
  3. In-transit data exposure — traffic between app and Redis is unencrypted and interceptable
  4. Lateral movement — a compromised Redis instance can be used to write files to disk (via CONFIG SET dir + CONFIG SET dbfilename + BGSAVE), achieving code execution on the server

A correctly secured Redis deployment mitigates all four.


Network Hardening

Bind to Specific Addresses

By default in Redis 3.2+, Redis binds to 127.0.0.1 only — not publicly accessible. Explicitly configure the bind addresses:

# redis.conf
bind 127.0.0.1 10.0.1.50   → bind to localhost AND a specific private IP
# Never: bind 0.0.0.0      → binds to all interfaces, including public ones

Protected Mode

protected-mode yes   → default

With protected-mode yes, if Redis is not bound to a specific address and has no authentication configured, it rejects all connections from non-loopback addresses. This is a safety net against accidentally exposing an unauthenticated Redis to the network.

Firewall Rules

At the infrastructure level, restrict Redis port (6379) to only your application servers:

bash
# Example: iptables iptables -A INPUT -p tcp --dport 6379 -s 10.0.1.0/24 -j ACCEPT # allow app subnet iptables -A INPUT -p tcp --dport 6379 -j DROP # deny everything else

On cloud providers, use security groups (AWS), firewall rules (GCP), or network security groups (Azure) to achieve the same.

Rename or Disable Dangerous Commands

Commands like FLUSHALL, FLUSHDB, CONFIG, DEBUG, SHUTDOWN, and SLAVEOF can cause catastrophic damage if abused. You can rename them to unpredictable strings or disable them entirely:

# redis.conf
rename-command FLUSHALL "do-not-use-flush-all-98fj2k3j"
rename-command CONFIG ""    → empty string = disable the command
rename-command DEBUG  ""
rename-command SHUTDOWN ""

Limitation: rename-command applies to all clients. With ACLs (below), you can restrict commands per user more granularly.


Authentication: requirepass

requirepass your-strong-password-here

Or at runtime:

CONFIG SET requirepass "your-strong-password-here"

With requirepass set, clients must authenticate before issuing commands:

AUTH your-strong-password-here

In ioredis:

typescript
const redis = new Redis({ password: process.env.REDIS_PASSWORD, });

Limitations of requirepass:

  • It is a single shared password for all clients
  • There is no per-user access control
  • A compromised password gives full access to all commands
  • Use ACLs for multi-user or fine-grained access control

ACLs: Access Control Lists

Introduced in Redis 6.0, ACLs let you define per-user command and key restrictions. Each user has a username, password, a set of allowed commands, and a set of allowed key patterns.

Viewing the Default User

ACL WHOAMI         → "default"
ACL LIST           → list all users and their rules
ACL GETUSER default → show rules for the default user

The default user has full access (all commands, all keys) when requirepass is not set. With ACLs, you should disable or restrict the default user.

ACL Rule Syntax

ACL SETUSER username [rules...]

# Rules:
on                  → enable the user (off = disabled)
off                 → disable the user
>password           → set password (> prefix)
nopass              → allow login without password (dangerous)
~pattern            → allow access to keys matching glob pattern
%R~pattern          → read-only access to pattern (Redis 7.0+)
%W~pattern          → write-only access to pattern (Redis 7.0+)
+command            → allow a specific command
-command            → disallow a specific command
+@category          → allow all commands in a category
-@category          → disallow all commands in a category
+@all               → allow all commands
-@all               → disallow all commands
nocommands          → disallow all commands (same as -@all)
allcommands         → allow all commands (same as +@all)
allkeys             → allow all keys (same as ~*)
resetkeys           → remove all key patterns
reset               → reset to default (disabled, no password, no commands, no keys)

Command Categories

ACL CAT             → list all categories
ACL CAT read        → list commands in the 'read' category

Common categories: read, write, string, hash, list, set, sortedset, generic, server, admin, dangerous.

Practical ACL Examples

Read-only cache user (application only reads from Redis):

ACL SETUSER cache-reader on >cache-reader-pass ~cache:* +@read -@admin

This user can:

  • Authenticate with password cache-reader-pass
  • Access only keys matching cache:*
  • Run read commands (GET, HGET, LRANGE, etc.)
  • Cannot run admin commands (CONFIG, FLUSHALL, DEBUG, etc.)

Cache writer (application reads and writes cache):

ACL SETUSER cache-writer on >cache-writer-pass ~cache:* +@read +@write +expire +del -@admin

Queue worker (only accesses queue keys):

ACL SETUSER queue-worker on >worker-pass ~queue:* ~job:* +lpush +rpush +lpop +rpop +blpop +lrange +llen +set +get +del +expire -@admin

Admin user (for operations, full access):

ACL SETUSER admin on >admin-pass ~* +@all

Disable the default user:

ACL SETUSER default off nopass -@all

This forces all clients to use named users with passwords. Any client not providing a username will be rejected.

ACL in redis.conf

# redis.conf
aclfile /etc/redis/users.acl

users.acl file format (each line is one user rule):

user default off -@all
user cache-reader on >cache-reader-pass ~cache:* +@read
user cache-writer on >cache-writer-pass ~cache:* +@read +@write +expire +del
user admin on >admin-pass ~* +@all

ACL in ioredis

typescript
const redis = new Redis({ username: 'cache-writer', // ACL username (Redis 6.0+) password: 'cache-writer-pass', });

ACL Logging

ACL LOG         → show recent ACL violations
ACL LOG RESET   → clear the log

CONFIG SET acllog-max-len 128   → keep last 128 violations

When a client attempts a denied command, the attempt is logged:

1) 1) "count"
   2) (integer) 3
   3) "reason"
   4) "command"
   5) "context"
   6) "toplevel"
   7) "object"
   8) "flushall"         → the denied command
   9) "username"
   10) "cache-writer"    → the user who tried it

TLS Encryption

Redis 6.0+ supports TLS for in-transit encryption. Without TLS, all data (including passwords, session tokens, cached values) travels in plaintext over the network.

Generating Certificates

For production, use certificates from a trusted CA (Let's Encrypt, your PKI). For testing:

bash
# Generate CA key and certificate openssl genrsa -out ca.key 4096 openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=Redis CA" # Generate Redis server key and certificate openssl genrsa -out redis.key 2048 openssl req -new -key redis.key -out redis.csr -subj "/CN=redis.internal" openssl x509 -req -days 365 -in redis.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out redis.crt

Redis TLS Configuration

# redis.conf
tls-port 6380                     → TLS port (keep 6379 for trusted internal, or disable it)
port 0                            → disable plain-text port when using TLS exclusively
tls-cert-file /etc/redis/redis.crt
tls-key-file  /etc/redis/redis.key
tls-ca-cert-file /etc/redis/ca.crt
tls-auth-clients yes              → require client certificates (mutual TLS)
tls-protocols "TLSv1.2 TLSv1.3"
tls-prefer-server-ciphers yes

TLS in ioredis

typescript
import fs from 'fs'; const redis = new Redis({ host: 'redis.internal', port: 6380, tls: { ca: fs.readFileSync('/etc/ssl/redis/ca.crt'), cert: fs.readFileSync('/etc/ssl/redis/client.crt'), // for mTLS key: fs.readFileSync('/etc/ssl/redis/client.key'), // for mTLS checkServerIdentity: () => undefined, // skip hostname verification if using IP }, password: process.env.REDIS_PASSWORD, });

Common Redis Security Misconfigurations

1. Redis Bound to 0.0.0.0 Without Authentication

The most common breach vector. An unprotected Redis instance on 0.0.0.0 is globally accessible. Shodan reports tens of thousands of such instances at any given time.

Fix: bind 127.0.0.1 <private-ip> + firewall rules + requirepass or ACLs.

2. CONFIG SET dir + CONFIG SET dbfilename = Remote Code Execution

A client with access to CONFIG can change the RDB save directory and filename, then trigger BGSAVE to write arbitrary content to arbitrary paths on the server's filesystem. This has been used to write SSH keys to ~/.ssh/authorized_keys, achieving server access.

Fix: Disable CONFIG via ACL (-@admin) for all non-admin users, or via rename-command CONFIG "".

3. Default User with Full Access

Leaving the default user enabled with nopass (the default before Redis 6.0 required passwords) means any client can connect without authentication.

Fix: Set requirepass or use ACLs to disable/restrict the default user.

4. Sensitive Data in Plain-Text Redis Values

Session tokens, API keys, passwords, and PII stored in Redis without encryption. If Redis is compromised, all cached data is exposed.

Fix: Encrypt sensitive values before storing in Redis. Use TLS for in-transit encryption. Apply principle of minimal data — do not cache data that does not need to be cached.


Summary

  • Bind to specific IPs — never 0.0.0.0 in production; use private IP + firewall rules
  • Protected mode (yes by default) prevents unauthenticated access from non-loopback addresses
  • ACLs (Redis 6.0+) — per-user command and key restrictions; disable or restrict the default user; use least-privilege users per application role
  • TLS (Redis 6.0+) — encrypt in-transit data; use mutual TLS for additional client authentication
  • Disable dangerous commandsCONFIG, DEBUG, FLUSHALL, SHUTDOWN via ACL -@admin or rename-command
  • Monitor ACL violations with ACL LOG — unauthorized command attempts are audit signals
  • The CONFIG SET dir + dbfilename + BGSAVE attack achieves arbitrary file write — restrict CONFIG access

Next: P-13 — Redis's Single-Threaded Event Loop: Speed, Limits, and Multithreading — how the event loop handles 100K+ RPS, what Redis 6+ multithreading parallelises, and the one failure mode that brings a Redis instance to its knees.

© 2026 Jatin Jain Saraf (JJS). All rights reserved.