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

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

相关推荐
ThanksGive10 小时前
Go 服务里的 Redis 锁惊群问题:一次本地合流优化实践
redis
炘爚10 小时前
MySQL——事务和隔离级别
数据库·mysql
DeboPXK10 小时前
NSK VH25EM 高防尘法兰型导轨技术手册
服务器·网络·数据库·经验分享·规格说明书
小挪号底迪滴10 小时前
Redis 和 MySQL 数据不一致怎么办?缓存更新策略实战
redis·mysql·缓存
翼龙云_cloud10 小时前
阿里云国际代理商:如何使用RDS MySQL 构建网站数据库?
数据库·mysql·阿里云
程序猿乐锅10 小时前
【 苍穹外卖day03 | 菜品管理 】
java·开发语言·数据库·mysql
hughnz11 小时前
贝克休斯WellLink Assurance vs 帕特森-UTI REX:钻井报警系统的两条技术路线之争
大数据·数据库·人工智能
闪电悠米11 小时前
黑马点评-Redis ZSet-实现关注 Feed 流
服务器·网络·数据库·redis·缓存·junit·lua
天疆说11 小时前
在 Ubuntu 24.04 上安装 MATLAB R2021b
数据库·ubuntu·matlab
码云数智-大飞11 小时前
Go Channel 详解:并发通信的正确姿势
前端·数据库·git