Redis在6.0版本中正式引入了ACL(Access Control List,访问控制列表)机制,这标志着Redis从单一的密码鉴权模式迈向了多用户、细粒度权限管理的阶段。在旧版本中,所有客户端连接后只需通过requirepass配置的同一个密码即可获得实例的完整操作权限,这种模型在多人协作或多业务共用实例的场景下存在严重的安全隐患。ACL新特性允许管理员创建多个用户,为每个用户单独设置密码、启停状态、可执行的命令范围以及可匹配的键名模式,从而把权限控制下沉到用户级别。

在传统模式下,如果某个内部服务只需要读取缓存数据,但由于共用密码,该服务的代码一旦被注入或出错,就可能调用FLUSHALL清空整个实例。ACL通过把用户和权限解耦,让我们可以给报表服务分配一个只能执行GET、MGET且只能访问report:*键前缀的账号。这样即使凭证泄露,攻击面也被严格限制。理解ACL的核心对象——用户(user)、规则(rule)、命令权限(command permission)和键模式(key pattern),是后续配置的基础。
从底层实现来看,Redis将ACL规则存储在内存中,并可通过ACL SAVE命令持久化到配置指定的文件中。每个用户由一系列规则片段组成,例如on表示启用,>password表示设置密码,+@read表示允许读命令类别,~cache:*表示可访问以cache:开头的键。这些规则在命令执行前由Redis内核的ACL模块进行校验,校验失败则直接返回NOPERM错误,不会进入具体命令处理逻辑。这种前置拦截机制保证了权限控制的性能和可靠性。
ACL用户创建与基础命令权限配置
创建一个新的ACL用户最基本的方式是使用ACL SETUSER命令。假设我们需要为一个只做缓存写入的消费者服务创建账号,可以执行如下指令:先定义用户为开启状态,设置密码,然后只允许写入类命令并限定键前缀。与旧版不同,ACL中的命令权限使用+和-符号来授予或回收,同时支持按命令类别(如@read、@write、@dangerous)批量管理,这极大简化了权限模型的设计。
下面是一段在redis-cli中创建受限用户的示例。我们创建一个名为app_writer的用户,密码为secret123,仅允许执行SET和DEL命令,且只能操作session:*开头的键。注意~后面是键模式,支持通配符*和?,而&可用于匹配所有键但一般不推荐随意使用。
# 创建并配置写入专用用户 ACL SETUSER app_writer on >secret123 +set +del ~session:* # 查看该用户详细规则 ACL GETUSER app_writer
配置完成后,使用该账号连接Redis并执行GET session:1会被拒绝,因为未授予+get。如果尝试SET other:1 v也会失败,因为键不匹配session:*。这种显式白名单机制比旧版的“全有或全无”更安全。在实际生产中,建议为每个业务线建立独立用户,并遵循最小权限原则,即只加必需命令和键模式,不用+@all这种宽泛授权。
除了命令行临时设置,Redis还支持在redis.conf或独立的aclfile中声明用户。使用aclfile /etc/redis/users.acl配置后,可以通过ACL LOAD重新加载文件,适合配置管理工具批量下发。需要特别留意,命令行创建的用户重启后丢失,除非执行了ACL SAVE或写在文件中,这也是很多初学者容易踩的坑。
键空间限制与命令类别高级用法
ACL最实用的能力之一是对键空间的模式匹配限制。在微服务架构里,不同服务可能共用一个Redis集群以降低基础设施成本,此时键前缀隔离就非常关键。通过~规则,我们可以让订单服务只能碰order:*,库存服务只能碰stock:*,从逻辑层面避免跨业务数据污染。键模式支持多个,如~order:* ~order_tmp:*可授权两组前缀。
命令类别是另一项提升效率的特性。Redis内置了如@read、@write、@set、@list、@admin、@dangerous等分类。例如+@read等价于授权所有读相关命令,而不用逐个写+get、+hget。对于需要只读账号的场景,可组合+@read与-@write,并补充-flushdb等危险命令回收。下面的代码展示了如何为一个数据分析账号设置只读且禁止危险命令:
# 创建只读分析账号,禁止管理类和危险类 ACL SETUSER analyst on >analyst_pass +@read -@dangerous -@admin ~analytics:*
在复杂权限需求下,还可以用ACL WHOAMI让连接自查当前用户,用ACL LIST遍历所有用户规则以审计。当某个用户行为异常,可立刻用ACL SETUSER username off临时禁用,而不用改密码影响其他用户。这种细粒度开关在应急止血时非常有用。此外,键模式匹配是基于命令执行时的首个键参数,因此像SCAN这类不直接带键的命令需要额外注意其授权边界。
一个常见误区是认为设置了~prefix:*就能限制所有相关命令的键。实际上如果命令支持多个键(如MSET),ACL会检查每一个键是否匹配,只要有一个不匹配就拒绝整条命令。因此在给批量操作命令授权时,要确保业务传入的键都符合模式,否则会出现部分环境报错难以排查的问题。建议在测试环境用该账号跑一遍核心流程再上线。
ACL与传统防护方案对比及迁移建议
在ACL出现之前,运维人员常通过rename-command把FLUSHALL重命名为随机字符串,或依靠防火墙限制来源IP,甚至把Redis绑定到内网不设置密码。这些方法要么影响命令可用性,要么无法解决内部越权。ACL从协议层提供了原生的用户隔离,不仅更规范,也能和哨兵、集群模式良好兼容。下面的表格简要对比了几种方案差异:
| 方案 | 隔离粒度 | 维护成本 | 内部越权防护 |
|---|---|---|---|
| 单密码共用 | 实例级 | 低 | 无 |
| rename-command | 命令级 | 中 | 弱 |
| 网络隔离 | 网络级 | 高 | 依赖拓扑 |
| Redis ACL | 用户级 | 中 | 强 |
迁移到ACL并不需要一次性重构所有客户端。可以先将原有requirepass对应的默认用户(default)设为仅读或禁用,再为旧应用创建等价权限的用户,逐步替换连接配置。Redis的default用户本身也是一个ACL用户,可以用ACL SETUSER default off直接关闭匿名或旧密码登录,然后给特定IP的应用发放独立账号。
对于使用连接池的中间件,需注意ACL用户密码是独立于原来requirepass的,若代码里写死旧密码会连不上。推荐在配置中心增加redis.username字段,并在客户端升级到支持ACL的版本(如Lettuce 6+、Jedis 4+)后灰度切换。迁移期间可通过ACL LOG查看被拒绝的权限请求,快速定位哪些命令或键模式遗漏授权,避免上线后功能异常。
最后,ACL不是替代操作系统权限和网络安全的银弹。它解决了“谁能做什么”的问题,但密码本身仍需通过TLS或SSH隧道保护,避免明文传输被嗅探。将ACL规则纳入配置版本库,定期用ACL LIST做差异审计,才能让Redis在多租户场景下既灵活又可控。