本(ben)文(wen)剖(pou)析下遇到的一個問題,即"設置requirepass不生效"這個小問題,本(ben)文(wen)目錄如下:

requirepass字段(duan)介(jie)紹
requirepass字段是redis.conf中的(de)一個字段,可以看下redis.conf中的(de)注(zhu)釋
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatibility
# layer on top of the new ACL system. The option effect will be just setting
# the password for the default user. Clients will still authenticate using
# AUTH <password> as usually, or more explicitly with AUTH default <password>
# if they follow the new protocol: both will work.
#
# The requirepass is not compatable with aclfile option and the ACL LOAD
# command, these will cause requirepass to be ignored.
#
# requirepass foobared
即這個字段是用來(lai)設置(zhi)默認(ren)(ren)用戶default的密碼的,用戶可以通過auth <password>或者auth default <password>來(lai)認(ren)(ren)證,同時說明了不能跟aclfile兼容(rong),如果啟(qi)動(dong)acl,則(ze)(ze)該字(zi)段會(hui)被忽(hu)略,會(hui)使(shi)(shi)用(yong)acl文(wen)件中的default用(yong)戶(hu)(hu),如果沒有配置(zhi)default用(yong)戶(hu)(hu),則(ze)(ze)會(hui)新建一(yi)個nopass的default用(yong)戶(hu)(hu)并使(shi)(shi)用(yong),哈哈,這(zhe)就(jiu)是(shi)為什(shen)么redis.conf配置(zhi)了requirepass而不生效的原(yuan)因,提前說(shuo)了。
如何啟(qi)用requirepass
- 啟(qi)(qi)用(yong)(yong)redis.conf中(zhong)的requirepass,改為(wei)自己的密碼(ma)password,同時(shi)啟(qi)(qi)用(yong)(yong)logfile,注意不要啟(qi)(qi)用(yong)(yong)aclfile,否則(ze)會不生效
- 啟動redis-server ./redis.conf
- redis-cli -h localhost -p 6379訪(fang)問,發現需要進(jin)行認證,輸入auth password或者auth default password即可進(jin)行訪(fang)問了,默認登(deng)錄用(yong)戶就是default用(yong)戶
- default用(yong)戶的(de)密(mi)碼(ma)(ma)就是requirepass配(pei)置(zhi)的(de)密(mi)碼(ma)(ma),在initServer中會調用(yong)ACLUpdateDefaultUserPassword(server.requirepass)函數設置(zhi)default用(yong)戶的(de)密(mi)碼(ma)(ma)
/* 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);
}
}
至于為什么啟(qi)用aclfile時會不(bu)生(sheng)效,請繼續看(kan)
啟用requirepass時requirepass不生效?
現象
requirepass是default用(yong)戶的密(mi)碼(ma),配置密(mi)碼(ma)后,aclfile也啟(qi)用(yong)時,修改redis.conf配置后重啟(qi)redis后,redis-cli -h localhost -p port 無(wu)需認證(zheng)仍然可以訪(fang)問(wen),即沒有生效
看(kan)下redis.conf中注釋可以知道跟aclfile是不兼(jian)容的,啟用(yong)aclfile時,會忽略(lve)requirepass

原(yuan)因(yin)
redis.conf中同時(shi)(shi)啟用requirepass和aclfile,redis在(zai)加(jia)載配置時(shi)(shi),會讀取aclfile,重新(xin)新(xin)建全局Users對象,調用ACLInitDefaultUser函數(shu)重(zhong)新新建nopass的default用戶,先(xian)前已加載的defaultUser對象(密碼從requirepass來)不會被用到,即default用戶(hu)是(shi)(shi)nopass的(de),但是(shi)(shi)如果acl文(wen)件中配置了default用戶(hu)以及配置了密(mi)碼,則(ze)還是(shi)(shi)需要認證的(de)
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;
...
}
解決方法(fa)
- 不啟用(yong)aclfile,只(zhi)使用(yong)requirepass,即只(zhi)有default用(yong)戶了
- 啟用(yong)aclfile,redis-cli登錄后(hou)(hou),用(yong)config set requirepass xxx,會生效(xiao),然后(hou)(hou)重(zhong)新redis-cli登錄訪問即可,如果需要重(zhong)啟redis也生效(xiao),則進行acl save(會寫default的user規則到aclfile中)
注意點:config set requirepass xxx會(hui)(hui)調用(yong)(yong)updateRequirePass函(han)數(shu),該函(han)數(shu)會(hui)(hui)繼(ji)續調用(yong)(yong)ACLUpdateDefaultUserPassword更(geng)新(xin)(xin)default用(yong)(yong)戶的(de)(de)密碼(nopass變(bian)(bian)(bian)為有密碼狀態),注意redis最新(xin)(xin)版本(7.0以上)只會(hui)(hui)在(zai)更(geng)新(xin)(xin)的(de)(de)內容(rong)發生(sheng)變(bian)(bian)(bian)化時(shi)才會(hui)(hui)調用(yong)(yong)到(dao)updateRequirePass函(han)數(shu),如下面的(de)(de)sdsConfigSet函(han)數(shu),在(zai)內容(rong)有變(bian)(bian)(bian)化時(shi)才返回1

configSetCommand -> performInterfaceSet -> sdsConfigSet函數
performInterfaceSet會將sdsConfigSet函數(shu)返回(hui)值作為自己的返回(hui)值,
configSetCommand函數判斷performInterfaceSet返回值,如果為1,則
會調(diao)用(yong)到updateRequirePass函數
- 使用(yong)上還是直(zhi)接使用(yong)aclfile即可,將requirepass注(zhu)釋(shi)掉,登錄后(hou)新增用(yong)戶(hu),然后(hou)acl save
總結
本文主(zhu)要介紹了如何啟用(yong)requirepass,以及啟用(yong)requirepass為什么不(bu)會生效,從代碼層面分析了不(bu)生效的(de)原(yuan)因,是因為同(tong)時啟用(yong)了aclfile導致(zhi)requirepass中(zhong)的(de)密碼不(bu)會被用(yong)到,最后(hou)介紹了解決方法,建(jian)議使(shi)用(yong)上直接使(shi)用(yong)aclfile即(ji)可。