redis的安全配置相关内容在redis.conf的 SECURITY 项里;
redis6.0版本之前的 SECURITY 里大概只有设置一个密码和命令重命名的配置,redis6.0之后的SECURITY里出现了一个叫ACL的东西(Access Control List),用来代替之前的安全设置,并提供更加细化的权限控制;之前的requirepass配置只能为一个默认用户设置一个密码,并且无法做到详细的权限设置,也无法为多个用户进行不同的配置;
redis6.0之后新增了ACL设置,为了兼容性也保留了requirepass设置,但是requirepass命令相当于ACL里为一个叫“default”的默认用户设置密码(类似语法糖),另外AUTH认证命令也做了调整,增加了用户名语法:AUTH <username> <password>,同时也保留了旧的语法:AUTH <password>,旧语法相当于使用“default”用户进行认证;
ACL可以做到很细粒度的权限控制,可以为多个用户设置不同的权限,可以为一个用户设置多个密码,可以对命令、通道、key设置权限;
redis.conf里的 SECURITY 项的配置:(redis版本v7.0.2)
- user <username> ... acl rules ...:为用户设置acl权限;
- acllog-max-len 128:设置acl日志的最大条数,acl日志是存在内存里的,用于记录跟acl相关的命令失败和认证事件,可以用ACL LOG RESET命令清空日志;
- aclfile /etc/redis/users.acl:指定外部acl文件,格式跟redis.conf里配置的一样,但两者不能同时使用,否则redis会启动失败;
- requirepass 123456:相当于用acl给“default”用户指定密码,与aclfile项和ACL LOAD命令不兼容,该项会被忽略;
- acl-pubsub-default resetchannels:设置默认的订阅发布通道权限(redis6.2开始支持通道设定),设置为allchannels则接开启所有通道访问,设置为resetchannels则禁用全部通道访问;(redis7.0开始默认是resetchannels)
- rename-command CONFIG xxxxxxxxxx:命令重命名(弃用,推荐使用acl控制),重命名为空字符串可以禁用命令,恢复命令只需再设置为原命令名称即可;(重命名命令可能会在记录aof文件或者同步到从服务器时出现问题)
配置acl的方式:
- 直接在redis.conf文件里配置acl规则;
- 使用外部acl文件并在redis.conf里配置aclfile指定;
- 使用客户端连接redis并使用ACL SETUSER设置用户的acl规则;
配置acl的语法:
user <username> ... acl rules ...
第一个单词user固定,第二个单词为自定义的用户名,后面为配置的具体的各种acl规则;acl规则的顺序为从左到右依次设置,即后面的规则可以改写和覆盖前面的设置(具有包含关系的规则(+@all和-get)或者同一规则(+get和-get)),所以设置acl规则的顺序很重要,但对于不同类别的没有任何关联的规则没有顺序要求,例如:on >pass +get +set ~aaaa ~bbbb &CH1没有包含关系的规则顺序可以随便写;
默认的“default”用户的默认规则是:user default on nopass ~* &* +@all,默认的default用户是不需要密码的,直接就可以连接redis,并可以访问所有命令所有键和通道;所以设置acl的时候不要忘了default用户设置,虽然默认protected-mode是yes,对于无密码用户只能127.0.0.1本地访问;(另外设置了requirepass同时使用acl设置了“default”用户时,requirepass会失效,需要在acl里重新设置密码)
acl规则:
开启和禁用用户
- on:启用用户,可以进行身份验证;
- off:禁用用户,不能进行身份验证,但之前已经验证通过的用户仍可以工作;(如果默认用户off,新连接当启用未认证,需要发送AUTH或者HELLO进行认证)
允许和禁用命令
- +<command>:将该命令添加到用户的可调用命令列表里,可以使用“|”指定允许的子命令(例如+config|get);
- -<command>:将该命令从用户可调用命令列表里移除,Redis7.0开始可以使用“|”阻止子命令(例如-config|set);
- +@<category>:将该类别的全部命令添加到用户的可调用命令列表里,类别可以使用ACL CAT查询,@all类别包括全部命令,包括未来从模块加载的命令;
- -@<category>:将该类别的全部命令从用户可调用命令列表里移除;
- +<command>|first-arg:允许禁用的命令的第一个特定参数(需要先禁用该命令再允许第一个参数),只对没有子命令的命令有效,并且只能以“+”设置,不支持“-”;(已被弃用)
- allcommands:是+@all的别名,意味着支持未来加载的模块命令;
- nocommands:是-@all的别名,禁用所有命令;
允许和禁用键和键权限
- ~<pattern>:将一个键模式添加到命令可以使用的键列表里,~*将允许命令使用所有键(该模式类似KEYS的全局键模式),可以设定多个键模式;
- %R~<pattern>:(Redis7.0开始支持)添加只读键模式;
- %W~<pattern>:(Redis7.0开始支持)添加只写键模式;
- %RW~<pattern>:(Redis7.0开始支持)~<pattern>的别名;
- allkeys:~*的别名;
- resetkeys:清空之前的键模式列表;
允许和禁用订阅发布通道
- &<pattern>:(Redis6.2开始支持)为用户添加一个订阅发布的通道模式,可以设定多个通道模式;(注意,这种模式匹配只对PUBLISH和SUBSCRIBE起作用,如果要使用PSUBSCRIBE,则需要psubscribe订阅的批量通道跟&配置的通道完全相同才行)
- allchannels:&*的别名,允许全部通道;
- resetchannels:清空之前的通道模式,如果客户端不能继续访问这些通道或匹配通道模式,那么订阅发布的客户端将被断开;(即resetchannels作为通道设置的最后一个,或者后面添加的新通道模式没有包括客户端已经订阅的通道,那么订阅通道的客户端会被断开)
为用户配置有效密码
<password>:将该密码添加到用户的有效密码列表里,该操作会清除nopass状态,用户可以拥有任意数量的密码;
- <<password>:从有效密码列表里删除该密码,删除一个不存在的密码会报错;
- #<hash>:将这个SHA-256哈希值添加到用户的有效密码列表里,此值将与用户输入的密码的哈希值进行比较认证,这样配置文件里就可以不使用明文密码了;(只支持SHA-256哈希值,所以密码必须是64个字符,并且必须是小写的十六进制字符)
- !<hash>:从用户有效密码表里移除该哈希值;(当不知道用户密码又想要删除密码的时候很有效)
- nopass:删除用户的所有密码,用户被设定为不需要密码,意味着使用任何密码都会通过认证(仍需要认证才能正常使用命令);(如果默认用户被设置为nopass,则不需要认证就可以使用各种命令了,另外resetpass会清空该状态)
- resetpass:清空用户密码表和清空nopass状态;如果resetpass之后不设置新密码或者设置nopass用户就无法使用;(没有有效密码也没有nopass的用户是没有进行登录入口的)
为用户配置选择器
- (<rule list>):(Redis7.0开始支持)添加选择器,用于支持多组规则,都是独立计算;通过括号将一组规则括起来,根规则或任何选择器都需要匹配命令,先检查根规则再按添加顺序检查选择器;(选择器添加后无法修改,但可以使用clearselectors清除)
- clearselectors:(Redis7.0开始支持)清除全部选择器;(但不会清除根规则,即只清空括号内的)
重置用户
- reset:重置用户,会执行以下操作:resetpass, resetkeys, resetchannels, off, -@all;使用户回到刚创建时的状态;
命令类别category:(目前有21种,可通过ACL CAT命令查询)
- admin:管理命令,普通应用程序永远用不到的命令;包括:REPLICAOF, CONFIG, DEBUG, SAVE, MONITOR, ACL, SHUTDOWN等;
- bitmap:数据类型,与bitmap相关;
- blocking:可能阻塞连接的命令;(直到其他命令释放占用)
- connection:影响连接或其他连接的命令;包括:AUTH, SELECT, COMMAND, CLIENT, ECHO, PING等;
- dangerous:有潜在危险的命令;(应该仔细考虑里面的每个命令)包括:FLUSHALL, MIGRATE, RESTORE, SORT, KEYS, CLIENT, DEBUG, INFO, CONFIG, SAVE, REPLICAOF等;
- geo:数据类型,与地理空间索引相关;
- hash:数据类型,与hash相关;
- hyperloglog:数据类型,与hyperloglog相关;
- fast:时间复杂度O(1)的命令;
- keyspace:以类型无关的方式从键、数据库或元数据读写的命令;包括:DEL, RESTORE, DUMP, RENAME, EXISTS, DBSIZE, KEYS, EXPIRE, TTL, FLUSHALL等;(可以修改键空间、键、元数据的命令也属于write类别,只读取键空间、键、元数据的命令也属于read类别)
- list:数据类型,跟list相关;
- pubsub:订阅发布相关的命令;
- read:从键(值、元数据)中读取的命令;(不与键交互的命令既不属于write类别也不属于read类别)
- scripting:脚本相关的命令;
- set:数据类型,与set相关;
- sortedset:数据类型,与sortedset相关;
- slow:所有不属于fast类别的命令;
- stream:数据类型,与stream相关;
- string:数据类型,与string相关;
- transaction:与WATCH、MULTI、EXEC相关命令;
- write:写入键(值、元数据)的命令;
注意:同一个命令有可能属于多个不同的类别,多个类别可以相互组合取交集或者差集;有些添加数据的命令在写入数据后还可能涉及读取并返回结果,需要读写权限;
如果使用外部的acl文件,可以修改acl文件后使用ACL LOAD命令重新加载acl文件配置(新配置需要正确无误,否则报错并依旧保持旧配置),也可以使用ACL SAVE命令将当前redis里的配置保存到acl文件中;
如果使用redis.conf配置acl,可以使用CONFIG REWRITE命令将当前redis里的配置保存到conf文件中;(CONFIG REWRITE不会触发ACL SAVE)
对于给哨兵使用的用户,需要配置允许在master和replica实例中执行以下命令:AUTH, CLIENT, SUBSCRIBE, SCRIPT, PUBLISH, PING, INFO, MULTI, SLAVEOF, CONFIG, CLIENT, EXEC,哨兵不需要访问任何键,但使用了发布订阅机制,哨兵也不需要AUTH认证,总是被允许访问,哨兵的acl规则如下:
ACL SETUSER sentinel-user on >somepassword allchannels +multi +slaveof +ping +exec +subscribe +config|rewrite +role +publish +info +client|setname +client|kill +script|kill
对于副本,需要允许在master上执行以下命令:PSYNC, REPLCONF, PING,副本也不需要访问任何键,规则如下:
ACL setuser replica-user on >somepassword +psync +replconf +ping
注意,不需要配置副本允许master执行任何命令,从副本角度看,master总是使用root用户进行认证;
ACL命令:
可以使用ACL HELP命令查看帮助信息;
语法:ACL <subcommand> [<arg> [value] [opt] ...]
ACL子命令:
- CAT [<category>]:不指定category则列出所有category,指定了category则列出该类别里所有的命令列表;
- DELUSER <username> [<username> ...]:删除一批用户;
- DRYRUN <username> <command> [<arg> ...]:查询该用户是否有权限执行该命令;(不需要真实执行该命令)
- GETUSER <username>:用来返回指定用户的acl配置信息;(列表的形式)
- GENPASS [<bits>]:生成一个256位的密码,也可指定bits位数;
- LIST:以acl配置格式返回用户列表;
- LOAD:重新加载acl文件;
- LOG [<count> | RESET]:返回acl日志,可以指定count条数,也可以使用RESET清空acl日志;
- SAVE:将当前redis的acl配置保存到acl文件中;
- SETUSER <username> <attribute> [<attribute> ...]:创建或修改用户的acl规则;
- USERS:列出所有注册用户名;
- WHOAMI:返回当前连接的用户名;
- HELP:显示帮助信息;
小实验: