1. Redis-访问控制(ACL)

认证访问控制 是实现网络安全的重要措施,Redis 6 引入了ACLAccess Control List访问控制列表 功能,允许限制连接可以执行的命令和可以访问的键。

其工作原理如下:

  • 客户端连接后,使用用户名和有效的密码进行身份验证
  • 身份验证成功,访问会受到该用户所拥有的权限限制

Redis 引入 ACL 能够很好地服务于以下两个主要目标:

  • 通过限制对命令和键的访问来提高安全性,不受信任的客户端无法访问,而受信任的客户端只能以最低访问级别访问,以执行所需的工作。例如,某些客户端可能只能执行只读命令。
  • 提高操作安全性,以便访问 Redis 的进程或人员,不会因软件错误或手动错误而误删数据或配置。例如,从 Redis 中获取队列数据的用户,没有理由能够调用 FLUSHALL 命令。

Redis 支持以下方式配置 ACL 规则:

  • 使用命令:ACL 命令及其 ACL SETUSER 子命令
  • 使用文件:
    • redis.conf
    • 外部 ACL 文件

2. 默认用户

为了兼容旧版本, Redis 提供一个默认用户 defalut , 当使用 requirepass 配置密码时,实际是为默认用户设置密码。使用AUTH <password> 命令时,实际是使用默认用户进行认证。

Redis 6 之前的版本,只实现了简单的密码认证,即通过 requirepass 配置一个密码,然后使用该密码访问 Redis 实例。

使用 AUTH 命令进行认证:

AUTH <password>

Redis 6 扩展了 AUTH 命令:

AUTH <username> <password>

3. ACL 规则

ACL使用特定领域语言(DSL)来定义,描述了给定用户可以执行的操作。这样的规则总是从左到右、从第一条到最后一条执行,因为有时规则的顺序对于理解用户实际能够做什么很重要。

ACL 规则是一个列表,由多个部分组成,每个部分由单词、字符串前缀组成。示例:

 on nopass ~* &* +@all

3.1 用户管理

onoff 用于设置用户的状态:

  • on:活跃状态,可以正常进行认证登录
  • off:非活跃状态,禁用用户无法进行身份登录。如果是已认证并建立连接,然后再禁用,之前的连接不受影响。

密码管理相关:

  • nopass:无密码,可以使用任何密码认证该用户,此外还会重置用户配置的所有密码。
  • >password:给用户设置一个密码,注意用户可以设置多个密码。例如,>mypass 会为用户新增一个 mypass 密码。
  • <password:移除某个密码,如果当前密码不存在会报错。
  • #<hashedpassword>:给用户设置一个哈希密码,哈希密码是使用 SHA256 进行哈希处理并转换的一个十六进制字符串。
  • !<hashedpassword>:移除哈希密码。

其他:

  • reset:重置用户的所有权限和属性,使其回到默认状态。
  • (<rule list>):创建选择器
  • clearselectors:清除选择器

3.2 命令规则

设置用户可以访问的命令:

  • +<command>:将命令添加到用户可以调用的命令列表中。可以使用 | 设置允许的子命令,例如 +config|get
  • -<command>:从用户可以调用的命令列表中移除命令。也可以使用 | 设置禁用的子命令,例如 -config|get
  • +@<category>:将此分类中的所有命令添加到用户可以调用的列表中。类似于权限分组,例如 @all@admin@set@sortedset等。
  • -@<category>:移除分类。
  • +<command>|first-arg:添加允许执行带一个特定参数的已被禁用命令(此功能已被弃用)。
  • allcommands+@all的别名,允许执行所有命令。

3.3 键规则

设置用户可以访问的键:

  • ~<pattern>:将指定的键模式添加到用户可访问的键模式列表中,键模式是指符合 Glob 风格模式(快速匹配字符串的正则表达式)的键。用户具有匹配该模式的键的读写权限,示例:~objects:*
  • %R~<pattern>:类似于常规键模式,但仅授予读取的权限。
  • %W~<pattern>:类似于常规键模式,但仅授予写入的权限。
  • %RW~<pattern>~<pattern>的别名。
  • allkeys~*的别名,允许用户访问所有键。
  • resetkeys:移除所有键模式。

3.4 通道规则

设置用户可以访问的 Pub/Sub (发布订阅)通道:

  • &<pattern>:添加一个全局样式的 Pub/Sub 通道模式(可以指定多个),该用户可以访问这些通道。
  • allchannels&*的别名,允许用户访问所有 Pub/Sub 通道。
  • resetchannels:刷新允许的通道模式列表,并断开用户的 Pub/Sub 客户端连接。

3.5 选择器

Redis 7.0 开始,ACL 规则还可以被分组到多个不同的规则集中,这些规则集被称为选择器selectors)。与用户的根权限不同,选择器在添加后不能被修改,需要使用 clearselectors 关键字来移除所有已添加的选择器。

选择器使用括号表示,例如:

(+SET ~key2)

上面的选择器,表示这个用户可以执行 key2 键的 SET 命令。

3.6 命令分组

Redis 包含了很多个命令,如果是一个个的设置这些命令规则,是非常繁琐的,所以 Redis支持命令分组,类似于权限分组,拥有该组的权限,则拥有该组下所有的命令权限。

包含了分组如下:

  • admin:管理命令,普通应用程序永远不会需要使用这些命令。包括REPLICAOFCONFIGDEBUGSAVEMONITORACLSHUTDOWN等。
  • dangerous:可能危险的命令(每个命令都因为各种原因需要谨慎考虑)。这包括FLUSHALLMIGRATERESTORESORTKEYS、CLIENTDEBUGINFOCONFIGSAVEREPLICAOF等。
  • connection: 影响连接或其他连接的命令。这包括AUTHSELECTCOMMANDCLIENTECHOPING等。
  • blocking:可能会阻塞连接,直到被另一个命令释放。
  • fast: 快速O(1)命令。可能会根据参数数量进行循环,但不会根据键中的元素数量进行循环。
  • bitmap:与位图相关的命令
  • list :与列表相关的命令。
  • set :与集合相关的命令。
  • sortedset:与有序集合相关的命令。
  • stream :与流相关的命令。
  • string:与字符串相关的命令。
  • geo:与地理空间索引相关的命令。
  • hash :与哈希相关的命令。
  • hyperloglog : 与 HyperLogLog 相关的命令。
  • pubsub: 与发布/订阅相关的命令。
  • transaction : 与WATCH/MULTI/EXEC相关的命令。
  • scripting :与脚本相关的命令。
  • slow :所有不是快速命令的命令。
  • write: 向键(值或元数据)写入。
  • read : 从键(值或元数据)读取。请注意,不与键交互的命令既不属于读取也不属于写入类别。
  • keyspace: 以类型无关的方式对键、数据库或它们的元数据进行写入或读取。包括DELRESTOREDUMPRENAMEEXISTSDBSIZEKEYSEXPIRE、TTLFLUSHALL等。可能会修改键空间、键或元数据的命令也将具有写入(write)类别。仅读取键空间、键或元数据的命令将具有读取(read)类别。

4. ACL 命令

4.1 ACL LIST

查看当前激活的 ACL(访问控制列表)规则,返回值为数组,每一行定义了一个不同的用户。

示例:

localhost:0>ACL LIST
1) "user default on nopass ~* &* +@all"

每一行都是由 user 加上用户名 作为开头,后面是具体的 ACL 规则:

  • on:活动状态
  • nopass:没有配置密码
  • ~*:可以访问所有的键
  • &*:可以访问所有的 Pub/Sub 通道
  • +@all:可以调用所有命令

4.2 ACL SETUSER

创建一个具有指定 ACL 规则的用户,或修改现有用户的 ACL规则。如果用户名不存在,该命令将创建该用户名,并从左到右读取提供的所有规则,并设置用户的 ACL 规则。如果用户已存在,则新增或者修改已有的规则。

语法格式:

ACL SETUSER username [rule [rule ...]]

示例,创建了一个名为 virginia 的用户,该用户处于活动状态(on),可以访问任何键(allkeys),并且可以调用 set 命令(+set):

ACL SETUSER virginia on allkeys +set

可以再次调用来修改用户规则,例如,下面给 virginia 新增一个 GET 命令规则:

ACL SETUSER virginia +get

查看 ACL

localhost:0>ACL LIST
 1)  "user default on sanitize-payload #8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 ~* &* +@all"
 3)  "user virginia on sanitize-payload ~* resetchannels -@all +set +get"

示例,清除所有其他现有的规则:

ACL SETUSER antirez reset  

4.3 ACL GETUSER

返回现有 ACL 用户定义的所有规则。

语法格式:

ACL GETUSER username

示例:

localhost:0>ACL GETUSER virginia
 1)  "flags"
 2)    1)   "on"
  2)   "sanitize-payload"

 3)  "passwords"
 4)  
 5)  "commands"
 6)  "-@all +set +get"
 7)  "keys"
 8)  "~*"
 9)  "channels"
 10)  ""
 11)  "selectors"
 12)  

4.4 ACL CAT

查看所有的命令分组。

语法格式:

ACL CAT [category]

示例:

 > ACL CAT
 1) "keyspace"
 2) "read"
 3) "write"
 4) "set"
 5) "sortedset"
 6) "list"
 7) "hash"
 8) "string"
 9) "bitmap"
10) "hyperloglog"
11) "geo"
12) "stream"
13) "pubsub"
14) "admin"
15) "fast"
16) "slow"
17) "blocking"
18) "dangerous"
19) "connection"
20) "transaction"
21) "scripting"

4.5 ACL SAVE

使用命令创建的 ACL 规则默认不会进行持久化,重启时会丢失。需要在 redis.conf 中开启使用外部 ACL 文件,并调用 ACL SAVE 命令进行保存。

5. ACL 持久化

Redis 配置中持久化 ACL 有两种方式:

  • 直接在 redis.conf 文件中指定
  • 指定一个外部 ACL 文件

它们之间互不兼容,一般使用外部 ACL 文件的方式,并且直接热加载。

5.1 redis.conf

可以直接在 redis.conf 中配置 ACL 用户及规则,但是这种方式需要重启 Redis ,示例:

# 设置 ACL 用户及规则
user newuser ~* &* +@all

5.2 外部 ACL 文件

可以在 redis.conf 中指定一个 ACL 文件:

# 使用外部ACL文件
aclfile /etc/redis/users.acl

ACL 文件中使用的格式和命令方式是完全相同的,示例:

user worker +@list +@connection ~jobs:* on >ffa9203c493aa99

当修改了 ACL 文件后,可以使用 ACL LOAD 命令进行热加载。