bigywater.tech
Redis · 125

Redis ACL LOG

用户权限配好了,谁在撞墙?ACL LOG 记录每一次被 ACL 拒绝的操作。这篇把它每个字段的含义、合并规则、上限都在本机触发一遍,并回答一个实际问题:暴力猜密码时它能告诉你什么。

合并
同用户、同原因、同对象的重复失败合成一条,count 递增(200 次 → 1 条)
8980/s
本机上错误 AUTH 的尝试速率(每次新连接);日志里只有 1 条 count 累加
128
acllog-max-len 默认值;超出后旧记录被挤掉

四种拒绝

实测 · 本机执行输出
> AUTH app pw
"OK"
> DEL app:1
(error) NOPERM User app has no permissions to run the 'del' command
> GET other:1
(error) NOPERM No permissions to access a key
> PUBLISH secret x
(error) NOPERM User app has no permissions to run the 'publish' command
> AUTH app wrongpw
(error) WRONGPASS invalid username-password pair or user is disabled.
  ACL LOG 共 4 条(新的在前)
  reason=auth     context=toplevel object=AUTH     username=app      count=1 age=0.001
  reason=command  context=toplevel object=publish  username=app      count=1 age=0.001
  reason=key      context=toplevel object=other:1  username=app      count=1 age=0.001
  reason=command  context=toplevel object=del      username=app      count=1 age=0.001
  一条完整记录的字段: count reason context object username age-seconds client-info entry-id timestamp-created timestamp-last-updated
  client-info 示例: id=7 addr=127.0.0.1:60726 laddr=127.0.0.1:9126 fd=11 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=36 qbuf-free=

reason 有 command(命令没权限)、key(key 没权限)、auth(认证失败),还有 channel(频道没权限,本文这一轮没有触发,没有验证)。PUBLISH 被记成 command,因为这个用户根本没有 +publish,判定停在命令那一层。client-info 是 CLIENT LIST 同样格式的一行,能看出是哪个连接(地址、name、库、最后命令)。

合并规则

实测 · 本机执行输出
  200 次 GET other:1 被拒后,条数 1,count=200,timestamp-created→last-updated 相差 14 ms
  换一个 key 名 → 是另一条(object 不同):
  条数变为 2

200 次相同的失败只有 1 条记录,count 是 200。所以 ACL LOG 是「什么类型的拒绝、多少次」的摘要,不是逐条流水。要逐条审计需要另外的手段(这里没有验证)。

暴力猜密码

实测 · 本机执行输出
  用时 0.06 s,ACL LOG 1 条:reason=auth object=AUTH username=app count=500

500 次错误 AUTH 用了 0.06 s。Redis 对认证失败没有任何限速或锁定(本次实测中没有观察到),ACL LOG 只是把它们累加进一条 reason=auth 记录。所以:密码必须足够长且随机,并且不要把端口暴露给不可信网络(第 128、129 篇)。监控 count 的增长速度可以当告警信号。

context:MULTI 与 Lua

实测 · 本机执行输出
> MULTI
"OK"
> DEL app:1
(error) NOPERM User app has no permissions to run the 'del' command
> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
> EVAL "return redis.call('DEL','app:9')" 0
(error) ERR ACL failure in script: User app has no permissions to run the 'del' command script: fab23d6dc04df4c1558e045e620940bbd0c2d064, on @user_script:1.
  reason=command  context=lua       object=del
  reason=command  context=multi     object=del

MULTI 里被拒的命令让整个事务 EXECABORT;Lua 里被拒则整个脚本报错。ACL LOG 用 context 字段告诉你这是从哪里来的。

容量与清理

实测 · 本机执行输出
> CONFIG SET acllog-max-len 5
"OK"
  制造 12 条不同的 key 拒绝后,日志里剩 5 条,保留的 object: ['z11', 'z10', 'z9', 'z8', 'z7']
  ACL LOG 2 只取最新 2 条: 2 条
> ACL LOG RESET
"OK"
  RESET 后: 0 条

日志有条数上限,超过 acllog-max-len 就挤掉最旧的。想长期留存要定期拉取(ACL LOG)并写到外部。

分步演示:ACL LOG

ACL LOG
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。500 次 AUTH 是本机回环、每次新建连接,速率取决于机器,只作数量级参考
    • 没有验证:reason=channel 的记录、长期运行下的合并窗口(文档说的时间窗口本文没有测)、并发多个连接的合并、ACL LOG 内存占用
    京ICP备2026067502号-1京公网安备11010502063487号