登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis ACL 怎样限制客户端只能访问指定命令

来源:17golang原创

时间:2026-11-03 16:01:57 255浏览 收藏

Redis ACL 的关键不是只给客户端设置一个密码,而是同时限制“能执行哪些命令”和“这些命令能作用于哪些键”。如果一个缓存客户端只需要读取 cache: 前缀下的数据,可以创建一个新用户,给它 +get +mget,再给它 ~cache:*;这样它既不能执行 SET,也不能读取其他业务前缀。

官方地址:https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/

最稳妥的做法是从新用户的零权限状态开始,先写清楚命令集合,再写键模式,最后用 ACL GETUSER 和一组允许/拒绝请求复查。命令权限正确但键模式过宽,仍然不是最小权限。

先把命令权限和键权限分开

Redis ACL 的规则按从左到右应用,但不同规则解决的是不同问题:

规则限制对象示例
+get允许一个命令只允许读取字符串值
+@read允许一个命令类别允许读类命令集合
~cache:*允许访问的键模式只匹配 cache: 前缀
resetchannels清空 Pub/Sub 通道模式不让账号默认访问频道

因此,+get 不等于“可以读取所有键”,~cache:* 也不等于“可以执行读写命令”。两者需要一起出现,才能表达“只能用 GET 读取某个范围”。

Redis 客户端经过 AUTH、用户规则、命令权限和键模式检查后得到允许或 NOPERM 结果的静态结构图
图1:Redis ACL 请求过滤说明图,展示命令权限与键模式是两道独立判断,不是运行截图。

从零创建一个只读缓存用户

新建用户默认是关闭状态、没有密码、没有可执行命令,也没有键模式。可以利用这个安全起点明确写入完整规则。下面的示例给业务账号开放 GET 与 MGET,只允许访问 cache: 前缀。

# 使用管理员身份创建最小权限用户;密码占位符要替换为密钥管理系统提供的值
redis-cli --user admin --pass 'admin-password' ACL SETUSER cache_reader reset on >ReplaceWithLongSecret resetchannels ~cache:* +get +mget

# 查看用户最终的 flags、commands、keys 和 channels
redis-cli --user admin --pass 'admin-password' ACL GETUSER cache_reader

reset 会清掉旧密码、键模式、通道和命令授权,并把用户恢复到关闭且无权限的初始状态;随后再用 on、密码、键模式和命令规则逐项打开能力。这里显式加入 resetchannels,是为了避免把 Pub/Sub 访问范围和键访问混在一起。

生产环境不要把真实密码写进脚本或文章。示例中的 ReplaceWithLongSecret 只是占位符;创建用户后应通过安全的凭据分发方式让客户端使用双参数认证:

# 以明确的用户名认证,而不是继续依赖权限过大的 default 用户
redis-cli --user cache_reader --pass 'ReplaceWithLongSecret' GET cache:1234

精确命令和命令类别怎么选

如果业务调用面很小,精确列出命令最容易审查。例如只读一个字符串缓存时用 +get,批量读取再加上 +mget。如果业务会使用一组稳定的读命令,可以用 +@read,但它的范围比两个命令更大,升级或模块变化时需要重新检查。

# 先查看当前 Redis 实例中的命令类别,避免凭记忆猜类别内容
redis-cli --user admin --pass 'admin-password' ACL CAT read

# 精确授权:只允许 GET 和 MGET,适合调用面固定的缓存读取器
redis-cli --user admin --pass 'admin-password' ACL SETUSER cache_reader +get +mget

# 类别授权:适合读命令集合明确、可以接受更宽命令面的服务
redis-cli --user admin --pass 'admin-password' ACL SETUSER report_reader reset on >ReplaceWithLongSecret ~report:* +@read

不建议把 +@all -@dangerous 当作默认的“只读”方案。官方文档明确指出,+@all 还会包含模块加载的命令,而命令类别本身通常不包含模块命令;用“先全部允许再排除少量危险命令”的写法,很容易遗漏未来出现的能力。要限制一个业务账号,优先用精确命令或小范围类别。

Redis ACL 精确命令、命令类别和排除危险命令三种策略以及 cache 键范围的静态对比图
图2:权限策略对比说明图,展示命令集合大小与维护成本的取舍,不是 Redis 控制台截图。

键模式决定“能读哪里”

命令授权通过后,Redis 还会检查命令参数里涉及的键是否匹配用户的键模式。~cache:* 允许匹配 cache: 开头的键,不能把它误写成 ~*,后者会覆盖整个键空间。

# 为同一个用户增加第二个业务前缀;每个模式都应有明确的业务用途
redis-cli --user admin --pass 'admin-password' ACL SETUSER cache_reader ~session:*

# 如果决定完全替换旧的键范围,先清理再写入新模式
redis-cli --user admin --pass 'admin-password' ACL SETUSER cache_reader resetkeys ~cache:*

Redis 7 及以后还提供只读和只写键模式,例如 %R~cache:* 与 %W~cache:*。如果应用只需要读,可以把命令集合和键权限都收窄;不过最终仍要以目标 Redis 版本的命令参考和实际客户端调用面为准。

用 ACL GETUSER 和 NOPERM 复查结果

ACL GETUSER 返回 flags、密码摘要、commands、keys、channels 和 selectors 等字段。检查时至少确认四点:用户是 on、命令列表没有意外的 +@all、键模式没有无意的 ~*、通道权限符合业务需要。

# 读取机器可解析的用户描述;重点关注 commands、keys 和 channels
redis-cli --user admin --pass 'admin-password' ACL GETUSER cache_reader

# 允许的命令和键应成功,未授权的命令或键应返回 NOPERM
redis-cli --user cache_reader --pass 'ReplaceWithLongSecret' GET cache:1234
redis-cli --user cache_reader --pass 'ReplaceWithLongSecret' SET cache:1234 changed
redis-cli --user cache_reader --pass 'ReplaceWithLongSecret' GET other:1234

预期是第一条读取请求可以执行,后两条分别因没有 set 命令权限、键不匹配 cache:* 而返回 NOPERM。这组复查不会证明所有业务路径都覆盖到了,但可以快速发现最常见的“命令放宽”或“键范围放宽”。

增量修改时最容易踩的坑

多次调用 ACL SETUSER 不会自动重置已有用户,而是把新规则增量应用到当前用户。比如先加 +set,再加 +get,最后会同时拥有两个命令。需要重做权限时显式使用 reset,需要扩展权限时则把变更记录成可审查的最小差异。

另外,命令类别可能重叠,一个命令可以属于多个类别;不要只看类别名称推断最终集合,应该用 ACL CAT 列出当前实例的实际内容。对管理账号、迁移脚本和运维工具,更应该单独建立用户,避免把 CONFIG、FLUSHALL、DEBUG 等管理能力交给普通业务连接。

结论:按业务调用面给权限

业务场景命令策略键策略
只读缓存+get +mget~cache:*
报表读取经审查的 +@read~report:*
读写单一业务前缀精确列出读写命令~order:* 或更细的读写模式
运维管理独立账号,单独审批不要复用业务账号的键模式

相关问题

只写键模式能阻止客户端执行 SET 吗?

不能。键模式只限定键范围,仍然需要用命令规则控制 SET 或其他写命令。

+@read 是不是等于只读?

它表示允许当前实例定义的读类命令,不等于只允许某一两个命令;还要结合键模式,并检查命令类别实际内容。

为什么 ACL SETUSER 之后旧连接权限没有立刻符合预期?

ACL 规则修改的是用户权限,已有连接的认证状态和客户端调用仍要单独观察。先用新连接按用户名认证复查,再检查连接池是否复用了旧连接。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>