rename-command 是老办法:把危险命令改成别人猜不到的名字,或者直接禁用。ACL 出现之后,还该不该用它?这篇实测它的行为、跟 ACL 的可观测性差异,以及一个更要命的地方:改名之后复制和 AOF 是怎么处理的。
FLUSHALL → ERR unknown command 'FLUSHALL' KEYS * → ERR unknown command 'KEYS', with args beginning with: '*' CONFIG GET dir → ERR unknown command 'CONFIG', with args beginning with: 'GET' 'dir' CFG_a83f GET maxmemory → ['maxmemory', '0'] DBSIZE → 1
写在配置文件里的 rename-command 原名 新名,新名为空串就是禁用。之后原名报 unknown command,改名后的名字才能用。
COMMAND COUNT = 299 COMMAND LIST 里是否含: {'flushall': False, 'keys': False, 'config|get': True, 'cfg_a83f': False, 'cfg_a83f|get': False, 'config': True}
COMMAND INFO flushall / cfg_a83f / config → ['(nil)', 'config', '(nil)']
INFO commandstats 里与之相关的行: ['cmdstat_config|get']
运行时 CFG_a83f SET rename-command → ERR Unknown option or number of arguments for CONFIG SET - 'rename-command'
CFG_a83f REWRITE 之后 redis.conf 里的 rename-command 行: ['rename-command FLUSHALL ""', 'rename-command KEYS ""', 'rename-command CONFIG CFG_a83f']改名后 COMMAND LIST 不再列出原名(也没有新名),但 config、config|get 这类名字还在;统计里仍记原名。CONFIG SET rename-command 不被支持,只能改配置文件后重启;CONFIG REWRITE 会保留这些行。
新连接直接 KEYS * → ERR unknown command 'KEYS', with args beginning wi
同一连接:K_ab7 * → []
同一连接:KEYS * → []
同一连接:DBSIZE → 0
同一连接:KEYS * → ERR unknown command 'KEYS', with args beginning wi
另一条连接:
K_ab7 * → []
KEYS a* → []
KEYS * → []
FLUSHALL → ERR unknown command 'FLUSHALL'
第三条连接(没用过新名字)直接 KEYS * → ERR unknown command 'KEYS', with args beginning wi同一连接上,紧跟在成功调用「新名字」之后的「原名字」也能执行;中间隔一条别的命令就又是 unknown command。新连接、以及被禁用为空串的命令都不受影响。这不能让不知道新名字的人得到什么,但说明 rename-command 不是一道严密的边界:别把它当唯一的防线,也别用「原名字报 unknown command」当审计依据。原因没有查源码,不做解释。
rename 节点(3 次 FLUSHALL): {'acl_cmd': 0, 'unexpected': 0, 'acl_log': 0, 'errorstats': ['errorstat_ERR']}
ACL 节点(3 次 FLUSHALL): {'acl_cmd': 3, 'unexpected': 0, 'acl_log': 1, 'errorstats': ['errorstat_NOPERM']}
两种失败的回复:rename → ERR unknown command 'FLUSHALL' | ACL → NOPERM User default has no permissions to run the 'flushall' commandACL 拒绝会被计入 acl_access_denied_cmd 并在 ACL LOG 里留下一条(第 125 篇);rename 后的 unknown command 只有一个通用的错误类型 ERR。要在被人试探时收到信号,ACL 更合适。另外 ACL 可以按用户区分,rename 是全局的。
主库、从库 DBSIZE: 20 20 主库执行 FA9x(改名后的 FLUSHALL) → OK 之后 主库、从库 DBSIZE: 0 20 从库 master_link_status = up 主库 AOF 里记录的清库命令名: ['FA9x'] 从库日志里与命令相关的行: ["s replica is sending an error to its master: 'unknown command 'FA9x'' after processing the command '<unknown>'"]
主库把 FLUSHALL 改名为 FA9x、从库没改:主库执行后 AOF 里记录的就是 FA9x,复制流里同样是它,从库不认识,只在日志里说 unknown command。结果是数据分叉,而 master_link_status 仍是 up。
主库、从库 DBSIZE: 20 20 主库执行 FLUSHALL → OK 之后 主库、从库 DBSIZE: 0 20 从库 master_link_status = up 从库日志里与命令相关的行: ["# == CRITICAL == This replica is sending an error to its master: 'unknown command 'FLUSHALL'' after processing the command '<unknown>'"] 再过 1.5 s:主库、从库 DBSIZE: 0 20 link = up 从库 master_repl_offset = 621 主库 = 621
反过来从库把 FLUSHALL 禁用也一样:主库清了,从库没清,日志里是 == CRITICAL == 一行。两种情形下复制偏移量主从相同——偏移量一致不能当作数据一致的证据。
-@dangerous 或按命令禁)。