1. 背景与目标
在 Redis 多租户或微服务场景中,需要为不同业务模块或团队分配独立的访问账号,并限制其操作范围。本文档以 Redis 6.2+ 的 ACL(Access Control List)功能为基础,实现以下目标:
default账号:拥有最高权限,用于管理员运维。db2_user账号:只能操作 数据库 2,允许所有命令(除危险命令外,示例未禁但可自行调整),禁止切换其他数据库。db3_user账号:只能操作 数据库 3 ,规则与db2_user对称。
核心限制 :每个账号登录后仅能访问指定的单个数据库,无法通过
SELECT切换到其他数据库,从而实现数据隔离。
参考文档:https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/#use-an-external-acl-file
2. ACL 配置示例
配置文件路径:/etc/redis/users.acl
(需在 redis.conf 中指定 aclfile /etc/redis/users.acl)
acl
user default on >Redis123456 ~* &* +@all
user db2_user on >pass2 ~* +@all -SELECT +SELECT|2
user db3_user on >pass3 ~* +@all -SELECT +SELECT|3
管理员账号:拥有全部权限
数据库3专用账号:只能访问 db3
数据库2专用账号:只能访问 db2,可执行任意键操作

配置项解析
| 字段 | 含义 |
|---|---|
user <name> on |
定义用户,on 表示启用 |
>password |
明文密码,存储时自动转为 SHA256 哈希 |
~* |
允许访问所有键(* 通配符) |
&* |
允许访问所有 Pub/Sub 频道(仅 default 有) |
+@all |
允许执行所有命令类别 |
-SELECT |
禁止 SELECT 命令(全局) |
| `+SELECT | 2` |
3. 权限效果验证
3.1 db2_user 登录并操作
bash
# 登录并直接进入数据库 2(推荐方式)
redis-cli -h 127.0.0.1 -p 6379 --user db2_user --pass pass2 -n 2
# 或登录后手动切换
redis-cli -h 127.0.0.1 -p 6379 --user db2_user --pass pass2
> SELECT 2
OK
# 测试数据操作(成功)
> SET user:1001 "Alice"
OK
> GET user:1001
"Alice"
# 尝试切换到其他数据库(失败)
> SELECT 0
(error) NOPERM this user has no permissions to run the 'select' command or its subcommand
# 尝试切换到 db3(同样失败)
> SELECT 3
(error) NOPERM ...
3.2 db3_user 登录验证(对称)
bash
redis-cli -h 127.0.0.1 -p 6379 --user db3_user --pass pass3 -n 3
> SET order:999 "shipped"
OK
> SELECT 2
(error) NOPERM ...
3.3 管理员 default 账号
bash
redis-cli -h 127.0.0.1 -p 6379 -a Redis@2024!
> SELECT 2 # 允许切换
OK
> KEYS * # 可以查看所有键
> CONFIG SET ... # 拥有全部权限
4. 配置加载与持久化
4.1 加载方式
-
重启加载 :在
redis.conf中指定aclfile /etc/redis/users.acl,重启 Redis 后自动生效。 -
热加载 (无需重启):
bashredis-cli -h 127.0.0.1 -p 6379 -a Redis@2024! ACL LOAD
4.2 验证配置是否生效
bash
redis-cli -h 127.0.0.1 -p 6379 -a Redis@2024! ACL LIST
应能看到 default、db2_user、db3_user 三条规则。
5. 注意事项与最佳实践
5.1 数据库隔离的局限性
- Redis 的 ACL 无法真正限制用户只能看到某个数据库中的键 。因为
~*允许访问所有键,用户虽然不能SELECT到其他数据库,但若登录时未指定-n参数,会默认进入数据库 0。此时用户可以在数据库 0 中执行命令(因为~*生效)。 - 解决方案 :
- 强制客户端连接时必须使用
-n <db_num>参数。 - 升级至 Redis 7.2+,在 ACL 规则中添加
default 2 NOSELECT,直接锁定用户的默认数据库且禁止SELECT。 - db0 不被应用使用即可。
- 强制客户端连接时必须使用
5.2 密码安全
- 避免在命令行直接使用
-a或--pass,会暴露密码(进程列表可见)。推荐使用REDISCLI_AUTH环境变量或交互式AUTH。 - 生产环境应使用强密码,并定期更换。
5.3 命令权限收紧
示例中使用了 +@all,实际可根据需要限制,例如:
acl
user db2_user on >pass2 ~* +@read +@write -@dangerous -SELECT +SELECT|2
这样禁止了 FLUSHALL、CONFIG 等危险命令,更安全。
5.4 哨兵模式下的同步
ACL 规则不会在主从或哨兵之间自动同步。需手动将 /etc/redis/users.acl 复制到所有 Redis 节点(包括主、从、哨兵节点)。对于哨兵自身的 ACL,请参考哨兵文档配置 sentinel auth-user 等指令。
6. 故障排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
ACL LOAD 报错 |
ACL 文件格式错误,如注释未加 #,或 `+SELECT |
2` 语法不支持 |
| 用户登录后无法执行任何命令 | 用户状态为 off 或密码错误 |
检查 on/off 及密码哈希 |
SELECT 2 被拒绝但规则允许 |
规则顺序问题:-SELECT 应在前,`+SELECT |
2` 在后才能覆盖 |
| 切换数据库后仍能访问其他库数据 | 用户的键模式 ~* 允许所有键,且 SELECT 未被完全禁止 |
使用 -SELECT 并强制登录时 -n |
7. 总结
通过 Redis ACL 的 -SELECT + +SELECT|N 组合,可以有效限制用户只能访问指定的单个数据库 ,结合 ~* 键模式,实现数据库级别的初步隔离。虽然无法做到 100% 防止用户访问默认数据库 0,但通过客户端强制参数和运维规范,足以满足大多数业务场景。
对于严格的多租户隔离,建议采用多实例部署,每个实例单独一个数据库。但若资源有限,本文方案提供了轻量级且实用的替代方案。