Redis ACL 实现多账号权限隔离

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 后自动生效。

  • 热加载 (无需重启):

    bash 复制代码
    redis-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

应能看到 defaultdb2_userdb3_user 三条规则。

5. 注意事项与最佳实践

5.1 数据库隔离的局限性

  • Redis 的 ACL 无法真正限制用户只能看到某个数据库中的键 。因为 ~* 允许访问所有键,用户虽然不能 SELECT 到其他数据库,但若登录时未指定 -n 参数,会默认进入数据库 0。此时用户可以在数据库 0 中执行命令(因为 ~* 生效)。
  • 解决方案
    1. 强制客户端连接时必须使用 -n <db_num> 参数。
    2. 升级至 Redis 7.2+,在 ACL 规则中添加 default 2 NOSELECT,直接锁定用户的默认数据库且禁止 SELECT
    3. db0 不被应用使用即可。

5.2 密码安全

  • 避免在命令行直接使用 -a--pass,会暴露密码(进程列表可见)。推荐使用 REDISCLI_AUTH 环境变量或交互式 AUTH
  • 生产环境应使用强密码,并定期更换。

5.3 命令权限收紧

示例中使用了 +@all,实际可根据需要限制,例如:

acl 复制代码
user db2_user on >pass2 ~* +@read +@write -@dangerous -SELECT +SELECT|2

这样禁止了 FLUSHALLCONFIG 等危险命令,更安全。

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,但通过客户端强制参数和运维规范,足以满足大多数业务场景。

对于严格的多租户隔离,建议采用多实例部署,每个实例单独一个数据库。但若资源有限,本文方案提供了轻量级且实用的替代方案。

相关推荐
Kurisu5751 小时前
深度解析:Go 语言 GMP 调度器模型与内核线程探测
java·数据库·golang
Lao A(zhou liang)的菜园1 小时前
作为Oracle DBA,如何快速处理HANG类故障?
数据库·oracle·dba
Lao A(zhou liang)的菜园1 小时前
作为DBA,如何快速处理Oracle连接类故障?
数据库·oracle·dba
效能革命笔记1 小时前
Gitee Team:以数据驱动与精细化管理,支撑关键领域 DevSecOps 落地
数据库·gitee
Gauss松鼠会1 小时前
GaussDB(DWS) SQL性能问题案例集
java·数据库·经验分享·spring boot·后端·sql·gaussdb
六月雨滴1 小时前
Oracle Data Guard 完全解析及与 RMAN 的核心区别
数据库·oracle·dba
程序猿乐锅1 小时前
【MySQL | 第二篇】: 函数、约束、多表查询和事务
android·数据库·mysql
treesforest2 小时前
如何查IP归属地?IP地址归属地查询的三种方式与选型指南
网络·数据库·网络协议·tcp/ip
NiceCloud喜云2 小时前
Anthropic 发布 Project Glasswing:未公开模型 Mythos 已挖出 10000+ 漏洞,含 OpenBSD 27 年老 bug
android·java·数据库·c++·python·docker·bug