【Redis原始碼】Redis 6 ACL原始碼詳解

LZH984294471發表於2020-11-24

簡介

本文主要是講解Redis 6的ACL的實現原理。基本使用詳見:Redis 6.0新特性——ACLs,以及Redis啟動過程分析

啟動初始化

初始化預設使用者

ACL子模組在Redis啟動過程中初始化,下面程式碼主要是初始化ACL的結構:

/* 
 * 初始化ACL子系統
 * */
void ACLInit(void) {
    Users = raxNew(); // 初始化使用者資訊
    UsersToLoad = listCreate();
    ACLLog = listCreate();
    ACLInitDefaultUser();
    server.requirepass = NULL; /* Only used for backward compatibility. */
}

ACLInitDefaultUser函式主要是初始化預設使用者,在Redis 6當中預設使用者的許可權就相當於作業系統的管理員一樣,擁有很大的許可權,要限制遠端使用預設使用者連線。

/* 初始化預設使用者 */
void ACLInitDefaultUser(void) {
    DefaultUser = ACLCreateUser("default",7);
    ACLSetUser(DefaultUser,"+@all",-1); // 預設使用者賦予所有命令的許可權
    ACLSetUser(DefaultUser,"~*",-1);// 可以操作任何key
    ACLSetUser(DefaultUser,"on",-1);// 預設開啟
    ACLSetUser(DefaultUser,"nopass",-1); // 預設不需要密碼
}

載入ACL使用者資訊

ACL資料結構初始化完成之後,通過函式 ACLLoadUsersAtStartup載入Redis配置裡面的ACL使用者資訊。Redis ACL配置資訊主要有兩種方式:

  • 在redis.conf檔案中通過user 配置項配置的ACL資訊。比如:user worker +@list +@connection ~jobs:* on >ffa9203c493aa99
  • redis.conf中配置aclfile所配置的檔案中。格式如下圖所示:

圖片

通過user方式

通過載入redis.conf配置檔案中讀取user配置項載入ACL資訊。

int ACLLoadConfiguredUsers(void) {
    listIter li;
    listNode *ln;
    listRewind(UsersToLoad,&li);
    while ((ln = listNext(&li)) != NULL) {
        sds *aclrules = listNodeValue(ln);
        sds username = aclrules[0];

        // 檢查ACL使用者名稱當中是否存在空格
        if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
            serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
            return C_ERR;
        }
        // 建立ACL使用者
        user *u = ACLCreateUser(username,sdslen(username));
        if (!u) {
            u = ACLGetUserByName(username,sdslen(username));
            serverAssert(u != NULL);
            ACLSetUser(u,"reset",-1);
        }

        /* Load every rule defined for this user. */
        for (int j = 1; aclrules[j]; j++) {
            // 新增當前使用者的所有屬性
            if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
                char *errmsg = ACLSetUserStringError();
                serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
                                     "the user named '%s': %s",
                          aclrules[j],aclrules[0],errmsg);
                return C_ERR;
            }
        }

        /* Having a disabled user in the configuration may be an error,
         * warn about it without returning any error to the caller.
         * 使用者沒有開啟的時候列印到日誌裡面
         * */
        if (u->flags & USER_FLAG_DISABLED) {
            serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
                                 "'on' modifier in the user description). Make "
                                 "sure this is not a configuration error.",
                      aclrules[0]);
        }
    }
    return C_OK;
}

通過檔案方式

ACLLoadFromFile函式就是從redis.conf配置的 aclfile所在的檔案當中讀取ACL配置資訊。

ACL 控制

ACL控制主要是在從命令表中獲取命令之後判斷當前登入的使用者是否對當前執行的命令是否有許可權。判斷的函式為:

int ACLCheckCommandPerm(client *c, int *keyidxptr) 

具體判斷是否存在許可權的函式為ACLGetUserCommandBit,主要實現如程式碼,其中id表示當前命令所對應的id。

int ACLGetUserCommandBit(user *u, unsigned long id) {
    uint64_t word, bit;
    // 計算命令在allowed_commands當中對應的bit位
    if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
    return (u->allowed_commands[word] & bit) != 0;
}

標 題:《【Redis原始碼】Redis 6 ACL原始碼詳解
作 者:zeekling
提 示:轉載請註明文章轉載自個人部落格:小令童鞋

相關文章