New to Kestra?
Use blueprints to kickstart your first workflows.
Find Redis ACL users with nopass, +@all or dangerous commands, every-key access or unknown names, alert Slack, fix with ACL SETUSER and verify.
Redis 6 added ACLs, and many deployments now have a dozen users, some of them risky:
nopass during a test;+@all that can FLUSHALL production;KEYS and DEBUG;default user still open to anyone who can reach the port.ACL LIST shows all of it, but nobody reads it.
This blueprint reads ACL LIST with redis-cli, checks every enabled user against a few rules, and alerts Slack. It can disable passwordless users and remove dangerous commands with ACL SETUSER, then read ACL LIST again to verify. Password hashes are stripped before anything is logged or sent.
This blueprint was created by zkasuran.
| Finding | Severity | Rule | Fix |
|---|---|---|---|
NOPASS |
High | Enabled user with nopass |
ACL SETUSER <user> off. Never applied to default: reported with the advice to set a password |
DANGEROUS_COMMANDS |
High | +@all, +@dangerous, +@admin, or an explicit FLUSHALL, CONFIG, KEYS, DEBUG, SHUTDOWN, ACL, MODULE... outside the admin users |
-@dangerous for +@all, otherwise removes each listed command |
ALL_KEYS |
Medium | ~* outside the admin users |
Report only |
UNKNOWN_USER |
Medium | Not in known_users or admin_users |
Report only |
Fixes only add rules to the user, so the rest of its ACL is kept.
acl_list (io.kestra.plugin.redis.cli.RedisCLI, read-only) runs ACL LIST.readable fails the run when no user line came back, for example a NOPERM reply. An audit that saw nothing must not read as clean.findings parses the users and applies the rules in one jq program, stored in vars.rules and reused for the verification. summary logs every finding.route (io.kestra.plugin.core.flow.If):alert posts to Slack.remediate_gate runs only when auto_remediate is true and dry_run is false.remediate (io.kestra.plugin.core.flow.Loop) runs one ACL SETUSER per fix, each in its own RedisCLI task.acl_relist and after apply the same rules to a fresh ACL LIST. verify_result fails if a fixed finding is still there.errors alerts Slack when the audit cannot run.ACL changes live in memory. The final log reminds you to run ACL SAVE when the server uses an aclfile, or to update its configuration.
ACL LIST.RedisCLI driving an audit and its fixes.ACL LIST answers the question for one instance at one moment. Kestra runs it on a schedule, keeps the list of known and admin users next to the flow, turns findings into a Slack alert, applies fixes only behind auto_remediate and dry_run, and keeps a history that shows when a risky user appeared and when it was fixed.
On Kestra 2.0.5 OSS against Redis 7, with a local HTTP sink standing in for Slack. Users seeded with ACL SETUSER:
app, restricted;cache-worker with nopass;legacy with +@all ~*;tmp-debug with +keys +debug;ops-admin (admin), and the open default user.| Run | Inputs | Result |
|---|---|---|
| 1 | defaults | 10 findings across cache-worker, default, legacy and tmp-debug. app and ops-admin not flagged. Alert sent |
| 2 | auto_remediate: true, dry_run: true |
Same report. ACL GETUSER cache-worker still on nopass |
| 3 | auto_remediate: true, dry_run: false |
cache-worker off, legacy -@dangerous, tmp-debug -keys -debug. Verified by the second ACL LIST. Then in Redis: AUTH cache-worker gets WRONGPASS, FLUSHALL as legacy and KEYS as tmp-debug get NOPERM, and app still reads and writes |
| 4 | a server where the connecting user cannot run ACL LIST |
Fails with the NOPERM reply instead of reporting 0 findings |
| 5 | a server with only a restricted default and a known app |
Only the 2 findings on default |
| 6 | unknown host | errors alert sent |
RedisCLI tasks start.acl|list, and acl|setuser for remediation.password: "{{ secret('REDIS_PASSWORD') }}" and username to each RedisCLI task.docker run -d --name redis -p 6379:6379 redis:7-alpine, then create users with ACL SETUSER.SLACK_WEBHOOK_URL: used by alert and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.| Input | Default | Purpose |
|---|---|---|
host / port |
localhost / 6379 |
Redis instance |
known_users |
[app, cache-worker] |
Expected application users |
admin_users |
[ops-admin] |
Users allowed every command and key |
network |
empty | Docker network for the redis-cli containers |
auto_remediate |
false |
Allow ACL SETUSER |
dry_run |
true |
Must be false for a change to apply |
SLACK_WEBHOOK_URL secret.host, known_users, admin_users and, if Redis runs in Docker, network.auto_remediate: true and dry_run: false, and save the ACLs.daily trigger, which always runs in safe mode.ACL SAVE after verify_result when your servers use an aclfile.&*).ACL LOG to report denied commands after a fix, so a broken client is found quickly.