Databases

Secure Redis and Valkey with cnspec

Scan Redis and Valkey servers against security and compliance best practices with cnspec.

Scan your Redis and Valkey servers to find security risks before they become incidents. cnspec evaluates the network and authentication posture (protected mode, bound interfaces, password, TLS and client certificates), the access-control users and the command and key patterns that govern them, and the durability configuration.

cnspec connects and inventories the server through read-only commands (INFO, CONFIG GET, and the ACL commands). It never reads your keys.

Redis and Valkey are both supported by one provider and detected automatically. redisdb.instance.isValkey reports which one, and valkeyVersion carries the Valkey version where applicable.

If you're new to cnspec, start with the Quickstart. For an overview of every database cnspec can scan, see the database scanning overview.

Prerequisites

To scan Redis or Valkey with cnspec, you must have:

Authenticate

cnspec authenticates with a password (legacy requirepass) or an ACL user and password on Redis 6 and later:

cnspec shell redisdb redis.contoso.com --ask-pass

For a TLS connection, add the TLS flags:

cnspec shell redisdb redis.contoso.com --user auditor --ask-pass --tls --tls-ca ca.pem

Valkey is queried exactly the same way:

cnspec shell redisdb valkey.contoso.com --ask-pass

The auditing credential needs to run INFO and CONFIG GET, which is the common case for a requirepass-authenticated connection or the default user. Listing access-control users additionally needs +acl. Without it, redisdb.instance.users returns empty rather than failing the scan, so confirm it's populated before trusting a passing user check.

Connection options

OptionDescription
--hostServer hostname or IP address (also accepted as the positional argument)
--portServer port (default 6379)
--user, -uACL user to authenticate as; omit for legacy password authentication
--password, -pPassword, or --ask-pass to be prompted
--databaseLogical database index to select (default 0)
--tlsConnect over TLS
--tls-caPath to a CA certificate to verify the server
--tls-insecureSkip TLS certificate verification (testing only)

Verify with a quick Redis check

cnspec shell redisdb redis.contoso.com --ask-pass
cnspec> redisdb.instance { version isValkey mode protectedMode bindsAllInterfaces requirepassSet tlsEnabled }
redisdb.instance: {
  version: "7.4.10"
  isValkey: false
  mode: "standalone"
  protectedMode: true
  bindsAllInterfaces: true
  requirepassSet: true
  tlsEnabled: false
}

If cnspec connects and shows the version, you're ready to scan.

Scan Redis

cnspec scan redisdb redis.contoso.com --ask-pass

When a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.

Mondoo doesn't yet ship an out-of-the-box Redis policy, so use the checks below as a starting point and create your own policies to meet your specific requirements.

Explore and test checks interactively

cnspec shell redisdb redis.contoso.com --ask-pass

List access-control users

cnspec> redisdb.instance.users { name isDefault enabled nopass passwordCount commandRules keyPatterns }
redisdb.instance.users: [
  0: {
    name: "auditor"
    isDefault: false
    enabled: true
    nopass: false
    commandRules: ["-@all", "+@read", "+@connection"]
    keyPatterns: ["app:*"]
  }
]

Read the network posture

cnspec> redisdb.instance { bind bindsAllInterfaces port tlsPort tlsEnabled tlsAuthClients }

Read the durability configuration

cnspec> redisdb.instance.config { rdbEnabled save appendOnly appendFsync maxmemory maxmemoryPolicy }

Example security checks

Ensure a password is configured

Without requirepass or an ACL password, reaching the port is the whole authentication story:

cnspec> redisdb.instance.requirepassSet == true
[ok] value: true

Ensure protected mode is on

cnspec> redisdb.instance.protectedMode == true
[ok] value: true

Ensure the server is not listening on every interface

cnspec> redisdb.instance.bindsAllInterfaces == false
[ok] value: true

Ensure TLS is enabled

cnspec> redisdb.instance.tlsEnabled == true
[ok] value: true

Ensure the plaintext listener is disabled

A port of 0 turns off the unencrypted listener, leaving only TLS:

cnspec> redisdb.instance.port == 0
[ok] value: true

Ensure TLS clients present a certificate

cnspec> redisdb.instance.tlsAuthClients == "yes"
[ok] value: true

Ensure no user authenticates without a password

nopass means anyone who names the user is authenticated as it:

cnspec> redisdb.instance.users.none(nopass == true)
[ok] value: true

Ensure the default user does not hold every command

The default user is what an unauthenticated connection becomes, so +@all there is the whole server:

cnspec> redisdb.instance.users.where(isDefault).none(enabled == true && commandRules.contains("+@all"))
[ok] value: true

Ensure no non-default user holds every command

cnspec> redisdb.instance.users.where(isDefault == false).none(commandRules.contains("+@all"))
[ok] value: true

Ensure persistence is enabled

With neither RDB snapshotting nor the append-only file, a restart loses everything held in memory:

cnspec> redisdb.instance.config.rdbEnabled == true || redisdb.instance.config.appendOnly == true
[ok] value: true

Ensure a memory limit is set

Without maxmemory the server grows until the host runs out of memory:

cnspec> redisdb.instance.config.maxmemory > 0
[ok] value: true

Review users that can reach every key

A * key pattern lets the user read and write everything in the database:

cnspec> redisdb.instance.users.where(keyPatterns.contains("*")) { name enabled commandRules }

Learn more

rename-command remaps are a startup-only directive that CONFIG GET does not return, so they aren't readable over a connection and the provider doesn't report them.

On this page