·QueueHub Team·11 min read

BullMQ Redis Security Hardening: A Production Checklist

BullMQRedisSecurityDevOpsMonitoringComplianceKubernetes

If you're running BullMQ in production, Redis is the most critical piece of infrastructure your queues depend on. It stores job data, manages worker state, and coordinates retries and scheduling. But here's the uncomfortable truth: Redis was designed for trusted networks, and the default configuration is wide open.

The FLUSHALL ransomware that wiped a startup's entire queue system in minutes — the Redis instance exposed on a misconfigured security group — the auditor who flagged your Redis ACLs as a compliance gap. These aren't hypothetical. Shodan regularly indexes over 750,000 exposed Redis instances, and automated scanning tools find new targets every day.

This guide is the infrastructure companion to our previous post on application-layer Redis security. While that post covered passwords, ACLs, TLS, and encryption in transit, this one takes a DevOps-centric approach: a hardened production checklist you can run before promoting any BullMQ-backed service to production.


Network-Level Security: Defense in Depth

Redis has no built-in encryption or authentication enabled by default (before Redis 6). Your first line of defense isn't a Redis config — it's the network.

Three-Layer Network Model

The gold standard for Redis network security follows three layers:

Layer 1 — VPC / Network Isolation: Place Redis inside its own subnet with no public IP address. It should be reachable only from the application subnets that run BullMQ workers.

Layer 2 — Security Groups / Firewall Rules: Restrict inbound traffic to known sources only. For cloud deployments, security groups are the idiomatic approach.

Layer 3 — Host-Level Firewall: Even inside the VPC, run iptables or nftables as a last line of defense. A misconfigured security group can allow intra-VPC traffic from unintended sources.

AWS Security Group with CDK

const redisSecurityGroup = new ec2.SecurityGroup(this, 'RedisSG', {
  vpc,
  description: 'Security group for BullMQ Redis',
  allowAllOutbound: true,
});

redisSecurityGroup.addIngressRule(
  ec2.Peer.securityGroupId(appServerSecurityGroup.securityGroupId),
  ec2.Port.tcp(6379),
  'Allow BullMQ app servers to connect to Redis'
);

// Security groups are deny-by-default for inbound — no explicit deny needed

Host-Level Firewall with iptables

# Allow Redis traffic only from the app-server subnet
iptables -A INPUT -p tcp --dport 6379 -s 10.0.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP

# Persist rules (Debian/Ubuntu)
apt-get install iptables-persistent
iptables-save > /etc/iptables/rules.v4

Kubernetes NetworkPolicy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: redis-ingress
  namespace: bullmq
spec:
  podSelector:
    matchLabels:
      app: redis
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: bullmq-worker
      ports:
        - protocol: TCP
          port: 6379

Redis Configuration Hardening

Beyond the network, Redis itself has several configuration knobs that tighten security.

Enable Protected Mode

Redis 3.2+ ships with protected-mode enabled by default, but it's worth explicitly setting:

# redis.conf
protected-mode yes
bind 127.0.0.1 10.0.1.10

Protected mode blocks external connections when Redis is bound to a public IP without a password set.

Disable Dangerous Commands with rename-command

BullMQ does not depend on dangerous commands like FLUSHALL, FLUSHDB, CONFIG, DEBUG, SHUTDOWN, or KEYS. You can safely disable or rename them:

# redis.conf — rename dangerous commands
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command DEBUG ""
rename-command SHUTDOWN ""
rename-command KEYS ""
rename-command SCRIPT ""
rename-command EVAL ""   # ⚠️ Only if you don't use Lua scripts with BullMQ

Important: BullMQ uses EVAL internally for some queue operations. If you disable EVAL, test thoroughly. Most deployments can safely disable SCRIPT (script management) while keeping EVAL (script execution).

What BullMQ Actually Needs from Redis

Understanding BullMQ's Redis command usage helps tailor your hardening:

Redis Command Used by BullMQ Secure to Disable?
SET / GET Yes (job data) No
RPUSH / LPOP / BRPOP Yes (queue lists) No
ZADD / ZRANGE / ZREM Yes (delayed/priority) No
EVAL Yes (Lua scripts) No
FLUSHALL No Yes
CONFIG No Yes
DEBUG No Yes
KEYS No (uses SCAN) Yes
SHUTDOWN No Yes

Secrets Management for Redis Credentials

Hardcoding Redis passwords in application code or config files is one of the most common — and most dangerous — practices. If a developer commits a .env file with REDIS_PASSWORD=letmein to GitHub, your attack surface explodes.

HashiCorp Vault (Static Secrets)

import { VaultClient } from './vault-client';

async function getRedisConfig() {
  const vault = new VaultClient();
  
  // Fetch Redis credentials from Vault KV store
  const secret = await vault.read('secret/data/bullmq/production/redis');
  
  return {
    host: secret.data.host,
    port: secret.data.port,
    password: secret.data.password,
    tls: {},
  };
}

// Use with BullMQ
const connection = await getRedisConfig();
const queue = new Queue('orders', { connection });

Kubernetes Secrets

apiVersion: v1
kind: Secret
metadata:
  name: redis-credentials
  namespace: bullmq
type: Opaque
stringData:
  REDIS_HOST: redis.internal
  REDIS_PORT: "6379"
  REDIS_PASSWORD: "<your-strong-password>"

Mount as environment variables in your BullMQ worker deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bullmq-worker
spec:
  template:
    spec:
      containers:
        - name: worker
          env:
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: redis-credentials
                  key: REDIS_PASSWORD

Environment Variable Hygiene

Use a validation helper to catch misconfigurations early:

function requireRedisConfig(): RedisConnectionConfig {
  const host = process.env.REDIS_HOST;
  const port = parseInt(process.env.REDIS_PORT || '6379', 10);
  const password = process.env.REDIS_PASSWORD;
  
  if (!host) throw new Error('REDIS_HOST is required');
  if (!password) throw new Error('REDIS_PASSWORD is required');
  
  return { host, port, password, tls: {} };
}

Security Monitoring and Auditing

Even with all the right controls in place, you need visibility. Redis provides several tools for security monitoring.

Track Failed Authentication Attempts

Redis logs failed AUTH attempts to its log file. Parse these to detect brute force attempts:

# Check for failed auth attempts in Redis log
grep "AUTH FAILED" /var/log/redis/redis-server.log | tail -20

For real-time alerting, use a log aggregator (Loki, ELK, Datadog):

# Prometheus-style metric via a log stream processor
# This example uses promtail + Loki
scrape_configs:
  - job_name: redis-security
    static_configs:
      - targets: [localhost]
    pipeline_stages:
      - regex:
          expression: '.*AUTH FAILED.*client: (?P<client_ip>\S+)'
      - metrics:
          redis_auth_failures_total:
            type: Counter
            description: 'Total Redis auth failures'
            prefix: 'redis_'
            source: client_ip
            config:
              action: inc

Redis SLOWLOG for Suspicious Operations

The slowlog can reveal attackers probing your Redis instance:

# Check for dangerous commands in slowlog
redis-cli SLOWLOG GET 10 | grep -E "FLUSHALL|FLUSHDB|CONFIG|KEYS"

Set a low threshold to catch probing: slowlog-log-slower-than 1000 (1ms) in redis.conf.

AOF-Based Audit Trails

When Redis persistence is enabled with AOF (Append-Only File), every write command is logged. This creates an excellent audit trail:

# Check AOF for dangerous commands
grep -c "FLUSHALL" /var/lib/redis/appendonly.aof
grep -c "CONFIG" /var/lib/redis/appendonly.aof

# If you see entries here with rename-command enabled, someone gained admin access

Encrypted Backups and Persistence

If an attacker gains access to your Redis data files on disk, encryption is your last line of defense.

Filesystem-Level Encryption (LUKS)

# Create an encrypted volume for Redis data
cryptsetup luksFormat /dev/xvdf
cryptsetup open /dev/xvdf redis-encrypted
mkfs.ext4 /dev/mapper/redis-encrypted
mount /dev/mapper/redis-encrypted /var/lib/redis

Encrypted RDB Backups

# Encrypt RDB backup before sending to S3
gpg --symmetric --cipher-algo AES256 \
  --output /backups/dump-$(date +%Y%m%d).rdb.gpg \
  /var/lib/redis/dump.rdb

# Upload to S3 with server-side encryption
aws s3 cp /backups/dump-$(date +%Y%m%d).rdb.gpg \
  s3://my-bucket/redis-backups/ \
  --sse aws:kms \
  --sse-kms-key-id alias/redis-backup-key

Queue Hub Security Model

Queue Hub is designed to integrate securely with your existing infrastructure. Here's how we handle security — and where your DevOps hardening takes over.

Credential Handling

Queue Hub never stores raw Redis passwords. Connection strings are encrypted at rest using a per-tenant encryption key. When you configure a Redis backend in Queue Hub, the connection details are transmitted over TLS and stored using envelope encryption.

Agent Tunneling Security

For private Redis instances behind a firewall, Queue Hub uses an outbound-only agent tunnel. The agent never listens on a port — it establishes a reverse tunnel to Queue Hub's relay service. This means:

  • No inbound firewall rules are needed
  • The Redis instance remains on your private network
  • The tunnel is authenticated with a short-lived token (rotated every 24 hours)
  • All tunnel traffic is encrypted with mTLS

What Queue Hub Does vs. What You Do

Security Concern Queue Hub Handles Your Responsibility
Connection encryption (TLS) Supports TLS to Redis Configure Redis with TLS certs
Credential storage Encrypted at rest Secure vault for keys
Authentication Session-based, MFA-ready Redis password/ACL strength
Network access Outbound-only tunnel VPC isolation, security groups
Audit logging Connection events, errors Redis slowlog, AOF audit, OS logs
Backup security N/A (dashboard data) Encrypted RDB/AOF persistence

Incident Response: Redis Compromise Playbook

If you suspect your Redis instance has been compromised, follow this PICERL playbook:

1. Preparation

Before an incident, document your Redis topology:

# Document all Redis instances and their purpose
redis-cli -h redis-001.internal INFO SERVER | grep -E "redis_version|uptime_in_seconds"
redis-cli -h redis-001.internal CLIENT LIST | wc -l
redis-cli -h redis-001.internal DBSIZE

2. Identification

# Check for unauthorized commands in AOF
grep -i "FLUSHALL\|FLUSHDB\|CONFIG SET\|DEBUG SEGFAULT" /var/lib/redis/appendonly.aof

# Check for unexpected keys
redis-cli --scan --pattern '*' | head -50

# Check connected clients
redis-cli CLIENT LIST | grep -v "addr=127.0.0.1"

3. Containment

# Immediately isolate the Redis instance
iptables -A INPUT -p tcp --dport 6379 -j DROP

# Or for Kubernetes
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: redis-quarantine
  namespace: bullmq
spec:
  podSelector:
    matchLabels:
      app: redis
  policyTypes:
    - Ingress
    - Egress
  ingress: []  # Deny all inbound
  egress: []   # Deny all outbound
EOF

4. Eradication

# Rotate credentials immediately
redis-cli CONFIG SET requirefs "<new-strong-password>"

# Restore from the most recent uncorrupted backup
systemctl stop redis
cp /backups/dump-20260701.rdb /var/lib/redis/dump.rdb
systemctl start redis

# Enable protected mode
redis-cli CONFIG SET protected-mode yes

5. Recovery

Restore BullMQ queue state from your last known-good backup. Queue Hub's job detail view can help identify any lost or corrupted jobs.

6. Lessons Learned

Review which controls failed. Was it an exposed port? A weak password? A misconfigured security group? Update your infrastructure-as-code to prevent recurrence.


Production Security Checklist

Before deploying BullMQ to production, run through this checklist:

  • Redis is in a private subnet with no public IP
  • Security group allows inbound only from BullMQ app servers
  • Host-level firewall (iptables/nftables) restricts Redis access
  • protected-mode yes in redis.conf
  • bind is set to specific interface(s), not 0.0.0.0
  • rename-command disables FLUSHALL, CONFIG, DEBUG, SHUTDOWN, KEYS
  • Redis password is a high-entropy string (not password123)
  • Credentials are stored in a vault (Vault, AWS Secrets Manager, Kubernetes Secrets)
  • Environment validation catches missing Redis config
  • Failed AUTH attempts are monitored and alerted
  • SLOWLOG thresholds are configured
  • AOF is enabled for audit trail (at least appendfsync everysec)
  • RDB/AOF backups are encrypted on disk
  • Backup files are encrypted before leaving the server
  • Redis runs as a non-root user
  • Container runs as a non-root user with read-only root filesystem
  • Incident response playbook is documented and tested

Secure Your BullMQ Queues Today

Hardening Redis for BullMQ doesn't have to be overwhelming. Start with the network layer — isolate Redis to a private subnet — then work through the checklist one step at a time. Every control you add raises the bar for attackers.

Queue Hub helps you monitor and manage your BullMQ queues across multiple environments, all from a single dashboard. With support for TLS Redis, agent tunneling to private networks, and detailed job-level visibility, Queue Hub complements your security posture by giving you the observability you need. Try Queue Hub today and see your queues through a security-first lens.

Related Articles