redis.conf中使用requirepass不生效?
本文剖析下遇到的一个问题,即"设置requirepass不生效"这个小问题,本文目录如下:
requirepass字段介绍
requirepass字段是redis.conf中的一个字段,可以看下redis.conf中的注释
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatibility
1. layer on top of the new ACL system. The option effect will be just setting
1. the password for the default user. Clients will still authenticate using
1. AUTH as usually, or more explicitly with AUTH default
1. if they follow the new protocol: both will work.
1. 1. The requirepass is not compatable with aclfile option and the ACL LOAD
1. command, these will cause requirepass to be ignored.
1. 1. requirepass foobared
即这个字段是用来设置默认用户default的密码的,用户可以通过auth 或者auth default 来认证,同时说明了不能跟aclfile兼容,如果启动acl,则该字段会被忽略,会使用acl文件中的default用户,如果没有配置default用户,则会新建一个nopass的default用户并使用,哈哈,这就是为什么redis.conf配置了requirepass而不生效的原因,提前说了。
如何启用requirepass
- 启用redis.conf中的requirepass,改为自己的密码password,同时启用logfile,注意不要启用aclfile,否则会不生效
- 启动redis-server ./redis.conf
- redis-cli -h localhost -p 6379访问,发现需要进行认证,输入auth password或者auth default password即可进行访问了,默认登录用户就是default用户
- default用户的密码就是requirepass配置的密码,在initServer中会调用ACLUpdateDefaultUserPassword(server.requirepass)函数设置default用户的密码
/* Set the password for the "default" ACL user. This implements supports for
* requirepass config, so passing in NULL will set the user to be nopass. */
void ACLUpdateDefaultUserPassword(sds password) {
ACLSetUser(DefaultUser,"resetpass",-1);
if (password) {
sds aclop = sdscatlen(sdsnew(">"), password, sdslen(password));
ACLSetUser(DefaultUser,aclop,sdslen(aclop));
sdsfree(aclop);
} else {
ACLSetUser(DefaultUser,"nopass",-1);
}
}
至于为什么启用aclfile时会不生效,请继续看
启用requirepass时requirepass不生效?
现象
requirepass是default用户的密码,配置密码后,aclfile也启用时,修改redis.conf配置后重启redis后,redis-cli -h localhost -p port 无需认证仍然可以访问,即没有生效
看下redis.conf中注释可以知道跟aclfile是不兼容的,启用aclfile时,会忽略requirepass
原因
redis.conf中同时启用requirepass和aclfile,redis在加载配置时,会读取aclfile,重新新建全局Users对象,调用ACLInitDefaultUser函数重新新建nopass的default用户,先前已加载的defaultUser对象(密码从requirepass来)不会被用到,即default用户是nopass的,但是如果acl文件中配置了default用户以及配置了密码,则还是需要认证的
sds ACLLoadFromFile(const char *filename) {
...
/* The default user pointer is referenced in different places: instead
* of replacing such occurrences it is much simpler to copy the new
* default user configuration in the old one. */
user *new_default = ACLGetUserByName("default",7);
if (!new_default) {
new_default = ACLCreateDefaultUser(); // nopass的default用户
}
ACLCopyUser(DefaultUser,new_default);
ACLFreeUser(new_default);
raxInsert(Users,(unsigned char*)"default",7,DefaultUser,NULL);
raxRemove(old_users,(unsigned char*)"default",7,NULL);
ACLFreeUsersSet(old_users);
sdsfree(errors);
return NULL;
...
}
解决方法
- 不启用aclfile,只使用requirepass,即只有default用户了
- 启用aclfile,redis-cli登录后,用config set requirepass xxx,会生效,然后重新redis-cli登录访问即可,如果需要重启redis也生效,则进行acl save(会写default的user规则到aclfile中)
注意点:config set requirepass xxx会调用updateRequirePass函数,该函数会继续调用ACLUpdateDefaultUserPassword更新default用户的密码(nopass变为有密码状态),注意redis最新版本(7.0以上)只会在更新的内容发生变化时才会调用到updateRequirePass函数,如下面的sdsConfigSet函数,在内容有变化时才返回1
configSetCommand -> performInterfaceSet -> sdsConfigSet函数
performInterfaceSet会将sdsConfigSet函数返回值作为自己的返回值,
configSetCommand函数判断performInterfaceSet返回值,如果为1,则
会调用到updateRequirePass函数
- 使用上还是直接使用aclfile即可,将requirepass注释掉,登录后新增用户,然后acl save
总结
本文主要介绍了如何启用requirepass,以及启用requirepass为什么不会生效,从代码层面分析了不生效的原因,是因为同时启用了aclfile导致requirepass中的密码不会被用到,最后介绍了解决方法,建议使用上直接使用aclfile即可。