Redis 6.0 访问控制列表ACL说明

背景

      在Redis6.0之前的版本中,登陆Redis Server只需要输入密码(前提配置了密码 requirepass )即可,不需要输入用户名,而且密码也是明文配置到配置文件中,安全性不高。并且应用连接也使用该密码,导致应用有所有权限处理数据,风险也极高。在Redis6.0有了ACL之后,终于解决了这些不安全的因素,可以按照不同的需求设置相关的用户和权限。本文来介绍下Redis 6.0 ACL相关的配置和使用。具体的说明可以查看官方文档:ACL 

说明

       Redis ACL 是向后兼容的,即默认情况下用户为default,使用的是requirepass配置的密码。要是不使用ACL功能,对旧版客户端来说完全一样。Redis Auth可以有2种方式进行工作:

1:旧版本的使用方式,默认用户。兼容旧版本Redis的支持
AUTH <password>
2:新方式,还需要验证用户名
AUTH <username> <password>

因为需要验证用户名了,所以客户端的认证方式也多了参数:

  --user <username>  验证用户名
  --pass <password>  验证密码,是参数-a的别名;配合--user使用
  --askpass          强制用户输入带有STDIN掩码的密码

现在开始来说明如何在Redis中根据ACL来定制需要的用户权限。首先看ACL的help,了解大致的使用方法:ACL help

> ACL help
 1) ACL <subcommand> arg arg ... arg. Subcommands are:
 2) LOAD                             -- 从ACL文件中重新载入用户信息.
 3) SAVE                             -- 保存当前的用户配置信息到ACL文件.
 4) LIST                             -- 以配置文件格式显示用户详细信息.
 5) USERS                            -- 列出所有注册的用户名.
 6) SETUSER <username> [attribs ...] -- 创建或则修改一个用户.
 7) GETUSER <username>               -- 得到一个用户的详细信息.
 8) DELUSER <username> [...]         -- 删除列表中的用户.
 9) CAT                              -- 列出可用的类别.
10) CAT <category>                   -- 列出指定类别中的命令.
11) GENPASS [<bits>]                 -- 生成一个安全的用户密码.
12) WHOAMI                           -- 返回当前的连接用户.
13) LOG [<count> | RESET]            -- 显示ACL日志条目.

具体使用方法:

在创建用户之前,先说明下ACL的规则,首先看下一个完整的用户权限的格式:

> ACL LIST  --显示用户信息
1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"

格式说明

参 数
说明
user 用户
default   表示默认用户名,或则自己定义的用户名
on 表示是否启用该用户,默认为off(禁用)
#… 表示用户密码,nopass表示不需要密码
~* 表示可以访问的Key(正则匹配)
+@ 表示用户的权限,+/-表示授权还是销权; @为权限类。+@all 表示所有权限

其中需要注意的有:

  • 密码相关
    ① 配置密码:一个用户可以设置不同的密码,即一个用户可以有多个密码。
    -- 添加密码 
    ## >开头: >password,明文密码;
    > ACL SETUSER zhoujy on >abc
    OK
    
    # 获取哈希值密码 echo -n "cba" | shasum -a 256
    6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d
    
    ## #开头: #hash,SHA-256哈希值
    > ACL SETUSER zhoujy on #6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d
    OK
    
    ## 查看
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
    3) "passwords"
    4) 1) "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
       2) "6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d"
    5) "commands"
    6) "-@all"
    7) "keys"
    8) (empty array)
    
    ## 认证密码
    > AUTH zhoujy abc
    OK
    > AUTH zhoujy cba
    OK
    
    
    -- 移除密码
    ## <开头: <password ,明文密码
    > ACL SETUSER zhoujy <abc
    OK
    
    ## 用!开头: !hash,SHA-256哈希值
    > ACL SETUSER zhoujy on !6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d
    OK
    
    ## 查看
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
    3) "passwords"
    4) (empty array)
    5) "commands"
    6) "-@all"
    7) "keys"
    8) (empty array)
    
    ## 认证密码
    > AUTH zhoujy abc
    (error) WRONGPASS invalid username-password pair

    ② 清理/删除密码:通过nopass清理用户的密码,但是该用户连接还是需要AUTH,只是密码可以是任意值

    -- 清理/删除密码,可以用任意密码登陆
    ## 查看
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
       2) "allkeys"
       3) "allcommands"
    3) "passwords"
    4) 1) "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
       2) "6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d"
    5) "commands"
    6) "+@all"
    7) "keys"
    8) 1) "*"
    
    ## 删除、清理用户密码
    > ACL SETUSER zhoujy nopass
    OK
    
    ## 查看
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
       2) "allkeys"
       3) "allcommands"
       4) "nopass"
    3) "passwords"
    4) (empty array)
    5) "commands"
    6) "+@all"
    7) "keys"
    8) 1) "*"
    
    ## 验证
    > AUTH zhoujy  --需要AUTH
    (error) WRONGPASS invalid username-password pair
    
    > AUTH zhoujy ''  --可以输入任何密码
    OK
    
    
    -- 清理/删除密码,不能登陆,需要设置密码后才能登陆
    ## 查看
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
       2) "allkeys"
       3) "allcommands"
    3) "passwords"
    4) 1) "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
       2) "6d970874d0db767a7058798973f22cf6589601edab57996312f2ef7b56e5584d"
    5) "commands"
    6) "+@all"
    7) "keys"
    8) 1) "*"
    
    ## 删除、清理用户密码
    > ACL SETUSER zhoujy resetpass
    OK
    > ACL GETUSER zhoujy
    1) "flags"
    2) 1) "on"
       2) "allkeys"
       3) "allcommands"
    3) "passwords"
    4) (empty array)
    5) "commands"
    6) "+@all"
    7) "keys"
    8) 1) "*"
    
    ## 验证,被resetpass重置密码之后,不能登陆,只能设置密码或则设置nopass才能登陆
    > AUTH zhoujy
    (error) WRONGPASS invalid username-password pair
    
    > AUTH zhoujy ''
    (error) WRONGPASS invalid username-password pair

    ③ 重置用户和密码:实际上是执行 resetpass,resetkeys,off,-@all

    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    
    ## 重置用户
    > ACL SETUSER zhoujy reset
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy off -@all"

    ④ 获取随机密码:

    -- 生成随机密码
    > ACL GENPASS
    "7a3288b05577cb6fea9b1a9a8bcfe10d9589e64be74e8a0e16c131ba896c7bde"
  • 键模式:~<pattern>,通配符模式。比如: ~*表示允许访问所有key,也可以用 allkeys来表示~*resetkeys 表示清空它之前所有的键模式,之后的键模式不影响。
    -- 可以操作foo开头和bar:开头的所有key
    > ACL SETUSER zhoujy on >abc ~foo* ~bar:*+@all
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~foo* ~bar:*+@all"
    
    --  只能操作ob:开头的key,前面的key模式被resetkeys清空了
    > ACL SETUSER zhoujy on >abc ~foo* ~bar:* resetkeys ~ob:*+@all
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~ob:*+@all"
    
    -- 操作所有key,allkeys 和 ~* 一样
    > ACL SETUSER zhoujy allkeys +@all
    OK
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    
    ## 查看
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~*+@all"
  • 权限相关:权限这块涉及到的比较多:权限的类别、类别里包含的命令,以及子权限。
    注意:-@all表示没有任何权限;+@all表示有所有权限;
    -- 返回权限的类别
    > 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"
    
    -- 返回指定类别中的命令,下面hash是上面返回的一个结果
    > ACL CAT hash
     1) "hsetnx"
     2) "hset"
     3) "hlen"
     4) "hmget"
     5) "hincrbyfloat"
     6) "hgetall"
     7) "hvals"
     8) "hscan"
     9) "hkeys"
    10) "hstrlen"
    11) "hget"
    12) "hdel"
    13) "hexists"
    14) "hincrby"
    15) "hmset" 

    从上面的权限列表里看到:权限对key的类型和命令的类型进行了分类,如有对类型进行分类:string、hash、list、set、sortedset,和对命令类型进行分类:connection、admin、dangerous。 以及对每个分类的方法进行说明,如上面查看hash类型key的一些方法。
    授权方法是:

    +<command>:将命令添加到用户可以调用的命令列表中,如+@hash
    -<command>: 将命令从用户可以调用的命令列表中移除
    +@<category>: 添加一类命令,如:@admin, @set, @hash ... 可以ACL CAT 查看具体的操作指令。特殊类别@all表示所有命令,包括当前在服务器中存在的命令,以及将来将通过模块加载的命令
    -@<category>: 类似+@<category>,从客户端可以调用的命令列表中删除命令
    +<command>|subcommand: 允许否则禁用特定子命令。注意,这种形式不允许像-DEBUG | SEGFAULT那样,而只能以“ +”开头
    allcommands:+@all的别名,允许所有命令操作执行。注意,这意味着可以执行将来通过模块系统加载的所有命令。
    nocommands:-@all的别名,不允许所有命令操作执行。

    ① 添加指定类型的权限:+@hash

    -- 添加hash类型key的所有权限
    > ACL SETUSER zhoujy +@hash
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* -@all +@hash" 

    说明:用户zhoujy只有对hash类型的key有权限。

    ② 删除指定类型的权限:-@hash

    -- 删除hash类型key的所有权限
    > ACL SETUSER zhoujy -@hash +@string
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad -@all +@string"

    说明:用户zhoujy移除对hash类型的key有权限。
    ③ 指定特定key的权限:如sortedset:~z*,z开头的key

    -- 访问指定key的正则
    > ACL SETUSER zhoujy ~z* +@sortedset -@string
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~z* -@all +@sortedset"

    说明:用户zhoujy只有对z开头的key有权限。

    ④ 授权只读/只写的权限:+@read、+@write

    -- 授权所有key的只读权限
    > ACL SETUSER zhoujy ~* +@read
    OK
    
    ##查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* -@all +@read +@hash +@bitmap +@geo -georadiusbymember -hsetnx -setbit -hset -geoadd -bitop -hincrbyfloat -hdel -bitfield -hincrby -hmset -georadius"
    
    -- 授权所有key的只写权限
    > ACL SETUSER zhoujy +@write
    OK
    
    ##查看
    192.168.163.134:8379> ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* -@all +@write +@list +@string +@stream +@fast +@blocking -dbsize -getrange -scard -xrevrange -zrank -llen -xread -ttl -get -ping -watch -publish -hlen -xrange -stralgo -zcount -getbit -lastsave -readonly -hmget -hello -zcard -discard -hstrlen -xinfo -hget -exists -bitfield_ro -select -role -zlexcount -zrevrank -lolwut -hexists -touch -lindex -unwatch -sismember -strlen -xlen -asking -type -mget -time -xpending -echo -multi -auth -readwrite -lrange -pttl -zscore -substr"

    说明:用户zhoujy对所有key有只读或则只写的权限,如果下个这对指定key,则替换 ~* 即可。
    ⑤ 授权管理权限:@admin

    -- 授权管理权限
    > ACL SETUSER zhoujy on >abc ~* +@admin
    OK
    
    ## 查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* -@all +@admin +@dangerous -flushall -flushdb -swapdb -keys -role -sort -migrate -restore-asking -restore -info"

    说明:用户zhoujy有管理权限,包含了危险操作的类型,但排除了开头命令的权限。

    ⑥ 允许特定类型key的子命令权限:

    -- 设置子命令。
    > ACL SETUSER zhoujy on >abc ~* -client +client|getname +client|setname
    OK
    
    ##查看
    > ACL LIST
    1) "user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all"
    2) "user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* -@all +client|getname +client|setname"

    说明:开始删除CLIENT命令,然后添加了两个允许的子命令。请注意,不能相反,即不能+在前面,只能添加而不是排除子命令,因为将来可能会添加新的子命令。注意子命令匹配可能会增加一些性能损失。
    ⑦:特定用途的账号权限:Sentinel 和 Replicas

    -- Sentinel:允许用户在主和副本实例中都有以下命令权限
    > ACL SETUSER sentinel-user >somepassword +client +subscribe +publish +ping +info +multi +slaveof +config +client +exec on
    OK
    
    -- Replicas:副本需要在主实例上有以下命令权限
    > ACL SETUSER replica-user >somepassword +psync +replconf +ping on
    OK
  • 保存、加载相关:save、load
    通过ACL创建的用户是保存在内存里的,如果Redis Server重启则ACL创建的用户会丢失,所以在创建完用户后需要用save保存,在重启之后需要用load加载。有两种方式进行保存和加载:
    1,使用ACL命令:ACL SAVE、ACL LOAD
    2,使用Redis配置,用户被定义,然后重启服务器并生效。 或者使用外部ACL文件,使用ACL LOAD 来导入ACL信息

    注意:ACL的配合文件需要事先手动touch,否则实例启动会失败。在redis.conf里配置和acl文件里配置的方法互不兼容,Redis会要求使用其中一种。 否则实例启动报错:

    -- 报错信息
    #Configuring Redis with users defined in redis.conf and at the same setting an ACL file path is invalid. This setup is very likely to lead to configuration errors and security holes, please define either an ACL file or declare users directly in your redis.conf, but not both.

    在redis.conf中指定用户是一种非常简单的方法,适用于简单的用例。 当有多个用户要定义时,在复杂的环境中,强烈建议使用ACL文件。该2个文件里的配置内容是一致的,可以相互进行配置,如格式如下:在redis.conf和users.acl里的格式

    -- 配置文件
    user default on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all
    user zhoujy on #ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad ~* +@all

    ① 保存ACL规则

    -- 保存ACL规则
    > ACL SAVE
    OK

    ② 加载ACL规则

    -- 加载ACL规则
    > ACL LOAD
    OK

    说明:在使用ACL配置文件之后,如果设置了默认用户(default)规则的话,需要看配置文件中aclfile和requirepass参数的先后顺序,密码以最后出现的为准。

  • 日志相关:显示最近的ACL安全事件列表
    通过ACL LOG  [<count> | RESET]  返回ACL的日志信息,可以指定条目显示,也可以进行重置:
    -- 显示日志信息
    > ACL LOG 1
    1)  1) "count"
        2) (integer) 1
        3) "reason"
        4) "auth"
        5) "context"
        6) "toplevel"
        7) "object"
        8) "AUTH"
        9) "username"
       10) "zhoujy"
       11) "age-seconds"
       12) "282.90499999999997"
       13) "client-info"
       14) "id=5 addr=192.168.163.134:35246 fd=7 name= age=403 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=36 qbuf-free=32732 obl=0 oll=0 omem=0 events=r cmd=auth user=zhoujy"
    
    -- 重置日志,类似slow
    > acl log reset
    OK

到此,大致的权限介绍已经结束,后续会不定时更新相关内容。

场景说明

  1. 创建DBA管理账号
    > ACL SETUSER dba on #6d0ac515af9df81653ed0aa3ffa692663c3f556079791e2f00a4578990da66f3 allkeys +@all
    OK
  2. 创建读写账号
    > ACL SETUSER readwrite on >abc allkeys -@all +@read +@write
    OK
  3. 创建只读账号
    > ACL SETUSER readonly on >abc allkeys -@all +@read
    OK
  4. 创建只写账号
    > ACL SETUSER write_user on >abc allkeys -@all +@write
    OK
  5. 创建复制账号
    > ACL SETUSER replica-user >abc -@all +psync +replconf +ping on
    OK
  6. 创建哨兵账号
    > ACL SETUSER sentinel-user >abc -@all +client +subscribe +publish +ping +info +multi +slaveof +config +client +exec on
    OK
  7. 创建监控账号
    > ACL SETUSER monitor on >abc +monitor
    OK
  8. 创建指定key、有指定类型权限的账号
    -- 指定对h开头的hash类型的key有权限
    > ACL SETUSER ops_user on >abc ~h* +@hash
    OK

    其中key的模式是正则匹配,需要~开头,针对权限则是hash的类,其权限可以通过ACL CAT hash查看。

总结

      在默认配置中,Redis 6(第一个具有ACL的版本)的工作方式与Redis的旧版本完全相同,即每个新连接都能够调用每个可能的命令并访问每个键,因此ACL功能与旧版本向后兼容。同样,使用requirepass配置指令配置密码的旧方法仍然可以按预期工作(只是为默认用户设置密码)。关于ACL的操作指南可以看官方文档

PS:如果后续有补充会继续更新到文章中。

 

参考文档:

//redis.io/topics/acl

//redis.io/commands/acl-setuser