主頁 > 軟體設計 > ?openGauss資料庫原始碼決議系列文章—— 安全管理原始碼決議?

?openGauss資料庫原始碼決議系列文章—— 安全管理原始碼決議?

2021-10-09 08:51:17 軟體設計

???大家好,我是Gauss松鼠會,歡迎進來學習啦~???

在前面介紹過“8.7 DeepSQL、8.8 小結”,本篇我們介紹第9章 安全管理原始碼決議中“9.1 安全管理整體架構和代碼概覽、9.2 安全認證”的相關精彩內容介紹,

openGauss作為新一代自治安全資料庫,提供了豐富的資料庫基礎安全能力,并逐步完善各類高階安全能力,這些安全能力涵蓋了訪問登錄認證、用戶權限管理、審計與追溯及資料安全隱私保護等,本章節將圍繞openGauss安全機制進行原始碼解讀,以幫助資料庫內核開發者在進行內核開發時正確地理解和使用安全功能介面,持續為產品提供安全保護能力,或基于當前安全能力進一步開發新的安全能力,

9.1 安全管理整體架構和代碼概覽

不同于資料庫其他業務模塊,安全管理模塊并非邏輯集中的,安全管理模塊中的安全能力是分散化的,在資料庫整個業務邏輯的不同階段提供對應的安全能力,從而構建資料庫整體縱深安全防御能力,一個完整的安全管理整體架構如圖9-1所示,
在這里插入圖片描述

圖9-1 openGauss安全機制體系

雖然整個安全機制是分散化的,但是每一個安全子模塊都獨立負責了一個完整的安全能力,如安全認證機制模塊主要解決用戶訪問控制、登錄通道安全問題;用戶角色管理模塊解決用戶創建及用戶權限管理問題,因此整體的安全管理體系架構的代碼解讀也將根據整個體系的劃分來進行描述,

1. 認證機制

認證機制子模塊在業務流程上主要包括認證組態檔管理、用戶身份識別、口令校驗等程序,其核心流程及介面定義如圖9-2所示,
在這里插入圖片描述

圖9-2 openGauss安全認證代碼介面

2. 用戶角色管理

用戶角色管理子模塊在業務流程上主要包括角色創建、修改、洗掉、授權和回收,由于openGauss并未嚴格區分用戶和角色,因此用戶的管理與角色管理共用一套介面,僅在部分屬性上進行區分,角色管理子模塊涉及的功能及其對應的介面如圖9-3所示,
在這里插入圖片描述

圖9-3 openGauss角色管理代碼介面

3. 物件訪問控制

物件訪問控制子模塊在業務流程上主要包括物件授權、物件權限回收以及實際物件操作時的物件權限檢查,其核心流程及介面定義如圖9-4所示,
在這里插入圖片描述

圖9-4 openGauss物件權限管理代碼介面

4. 審計機制

審計機制子模塊主要包括審計日志的創建和管理以及資料庫的各類管理活動和業務活動的審計追溯,審計日志管理包括新創建審計日志、審計日志輪轉、審計日志清理,審計日志追溯包括活動發生時的日志記錄以及審計資訊查詢介面,其核心流程及介面定義如圖9-5所示,
在這里插入圖片描述

圖9-5 openGauss審計執行緒(左)及審計日志記錄(右)介面

9.2 安全認證

安全認證是資料庫對外提供的第一道防線,資料庫訪問者只有完成身份識別、通過認證校驗機制,才可以建立訪問通道從事資料庫管理活動,在整個安全認證程序中,涉及用戶身份管理識別、用戶口令安全存盤以及完善的認證機制3大模塊,而對于系統內部的行程間通信(主備),則需要呼叫業界通用的Kerberos認證機制,下面將主要圍繞這4個子模塊進行涉及原理介紹和代碼決議,
9.2.1 身份認證
安全認證機制要解決的核心問題是誰可以訪問資料庫的問題,因此在定義身份時,除了描述訪問用戶,還要清晰定義整個程序中以何種方法訪問、從何處訪問、訪問哪個資料庫的問題,因此本小節重點介紹身份認證概念及原始碼,
身份認證是一個廣義的概念,實際上定義了資料庫系統的訪問規則,openGauss的訪問規則資訊主要被記錄在組態檔HBA(host-based authentication file,主機認證)中,HBA檔案中的每一行代表一個訪問規則,其書寫格式如下:

hostssl   DATABASE USER ADDRESS METHOD [OPTIONS]

其中第1個欄位代表套接字方法,第兩個欄位代表允許被訪問的資料庫,第3個欄位代表允許被訪問的用戶,第4個欄位代表允許訪問的IP地址,第5個欄位代表訪問的認證方式,第6個欄位則作為對第5個欄位認證資訊的補充,在定義訪問規則時,需要按照訪問的優先級來組織資訊,對于訪問需求高的規則建議寫在前面,
在openGauss原始碼中,定義了存盤訪問規則的關鍵資料結構HbaLine,核心元素代碼如下所示:

typedef struct HbaLine
{
    int linenumber;          /*  規則行號 */
    ConnType conntype;      /*  連接套接字方法 */
    List* databases;        /*  允許訪問的資料庫集合*/
    List* roles;             /*  允許訪問的用戶組 */
…
    char* hostname;         /*  允許訪問的IP地址 */
    UserAuth auth_method; /*  認證方法 */
…
} HbaLine;

其中欄位conntype、database、roles、hostname以及auth_method分別對應HBA組態檔中的套接字方法、允許被訪問的資料庫、允許被訪問的用戶、IP地址以及當前該規則的認證方法,
HBA檔案在系統管理員配置完后存放在資料庫服務側,當某個用戶通過資料庫用戶發起認證請求時,連接相關的資訊都存放在關鍵資料結構Port中,代碼如下所示:

typedef struct Port {
…
SockAddr laddr;             /*  本地行程IP(internet protocol,互聯網協議)地址資訊 */
SockAddr raddr;             /*  遠端客戶端行程IP地址資訊  */
char* remote_host;         /*  遠端host(主機)名稱字串或IP地址*/
char* remote_hostname;    /*  可選項,遠程host名稱字串或IP地址*/
    …
    /*  發送給backend(后端)的資料包資訊,包括訪問的資料庫名稱、用戶名、配置引數*/
char* database_name;
char* user_name;
char* cmdline_options;
List* guc_options;
    
/*  認證相關的配置資訊*/
HbaLine* hba;
…
    /*  SSL(secure sockets layer,安全套接層,作業于套接字層的安全協議,)認證資訊*/
#ifdef USE_SSL
    SSL* ssl;
    X509* peer;
    char* peer_cn;
    unsigned long count;
#endif
…
    /*  Kerberos認證資料結構資訊*/
#ifdef ENABLE_GSS
    char* krbsrvname;           /*  Kerberos服務行程名稱*/
    gss_ctx_id_t gss_ctx;         /*  GSS(generic security service,通用安全服務)資料內容*/
    gss_cred_id_t gss_cred;       /*  憑證資訊*/
    gss_name_t gss_name;        
    gss_buffer_desc gss_outbuf;    /*  GSS token資訊*/
#endif
} Port;

其中Port結構中的user_name、database_name、raddr以及對應的HBA等欄位就是認證相關的用戶資訊、訪問資料庫資訊以及IP地址資訊,與此同時Port結構中還包含了SSL認證相關的資訊以及節點間做Kerberos認證相關的資訊,有了Port資訊,后臺服務執行緒會根據前端傳入的資訊與HbaLine中記錄的資訊逐一比較,完成對應的身份識別,完整的身份認證程序見check_hba函式,其核心邏輯代碼如下所示:

/**掃描HBA檔案,尋找匹配連接請求的規則項 */
static void check_hba(hbaPort* port)
{
    ……
    /*  獲取當前連接用戶的id  */
    roleid = get_role_oid(port->user_name, true);

    foreach (line, t_thrd.libpq_cxt.parsed_hba_lines) {
        hba = (HbaLine*)lfirst(line);
        /*  認證連接行為分為本地連接行為和遠程連接行為,需分開考慮  */
        if (hba->conntype == ctLocal) {
        /*  對于local套接字,僅允許初始安裝用戶本地登錄  */
            if (roleid == INITIAL_USER_ID) {
                char sys_user[SYS_USERNAME_MAX + 1];
……
                /*  基于本地環境的uid(user identity,用戶身份標識)資訊獲取當前系統用戶名  */
                (void)getpwuid_r(uid, &pwtmp, pwbuf, pwbufsz, &pw);
                ……

                /*  記錄當前系統用戶名  */
                securec_check(strncpy_s(sys_user,SYS_USERNAME_MAX+1, pw->pw_name, SYS_USERNAME_MAX), "\0", "\0");

/*  對于訪問用戶與本地系統用戶不相匹配的場景,均需提供密碼  */
            if (strcmp(port->user_name, sys_user) != 0)
                hba->auth_method = uaSHA256;
            } else if (hba->auth_method == uaTrust) {
                hba->auth_method = uaSHA256;
            }
……
        } else {
            /*  訪問行為是遠端訪問行為,需要逐條判斷包括認證方式在內的資訊正確性  */
            if (IS_AF_UNIX(port->raddr.addr.ss_family))
                continue;
    /*  SSL連接請求套接字判斷  */
#ifdef USE_SSL
if (port->ssl != NULL) {
                    if (hba->conntype == ctHostNoSSL)
                        continue;
                } else {
                    if (hba->conntype == ctHostSSL)
                        continue;
                }
#else
             if (hba->conntype == ctHostSSL)
                   continue;
#endif
               /*  IP白名單校驗  */
               switch (hba->ip_cmp_method) {
                   case ipCmpMask:
                       if (hba->hostname != NULL) {
                           if (!check_hostname(port, hba->hostname))
                               continue;
                       } else {
                           if (!check_ip(&port->raddr, (struct sockaddr*)&hba->addr, (struct sockaddr*)&hba->mask))
                               continue;
                       }
                       break;
                   case ipCmpAll:
                       break;
                   case ipCmpSameHost:
                   case ipCmpSameNet:
                       if (!check_same_host_or_net(&port->raddr, hba->ip_cmp_method))
                           continue;
                       break;
                   default:
                       /* shouldn't get here, but deem it no-match if so */
                       continue;
            }
        } /* != ctLocal */

        /*  校驗資料庫資訊和用戶資訊  */
        if (!check_db(port->database_name, port->user_name, roleid, hba->databases))
            continue;
        if (!check_role(port->user_name, roleid, hba->roles))
            continue;
        ……
        port->hba = hba;
        return;
    }

    /*  沒有匹配則拒絕當前連接請求  */
    hba = (HbaLine*)palloc0(sizeof(HbaLine));
    hba->auth_method = uaImplicitReject;
    port->hba = hba;
}

9.2.2 口令存盤

口令是安全認證程序中的重要憑證,openGauss資料庫在執行創建用戶或修改用戶口令操作時,會將口令通過單向哈希方式加密后存盤在pg_authid系統表中,口令加密的方式與引數“password_encryption_type”的配置有關,目前系統支持MD5、SHA256 + MD5(同時存盤SHA256和MD5哈希值)和SHA256三種方式,默認采用SHA256方式加密,為兼容PostgreSQL社區和第三方工具,openGauss保留了MD5方式,但此方式安全性較低不推薦用戶使用,
口令的加密方式與認證方式密切相關,選擇不同的加密方式需要對應的修改“pg_hba.conf”組態檔中的認證方式,口令加密與認證方式對應關系如表9-1所示,

表9-1 口令加密與認證方式

password_encryption_type

加密方式

(hash演算法)

認證方式

(pg_hba.conf)

加密函式介面

0

MD5

MD5

pg_md5_encrypt

1

SHA256 + MD5

SHA256或MD5

calculate_encrypted_combined_password

2(默認值)

SHA256

SHA256

calculate_encrypted_sha256_password

創建用戶和修改用戶屬性的函式入口分別為CreateRole和AlterRole,在函式內對口令加密前會先校驗是否滿足口令復雜度,如果滿足則呼叫calculate_encrypted_password函式實作口令的加密,加密時根據引數password_encryption_type配置選擇對應的加密方式,加密完成后會清理記憶體中的敏感資訊并回傳口令密文,口令加密流程如圖9-6所示,

在這里插入圖片描述

圖9-6 口令加密流程圖

如圖9-6所示,通過呼叫calculate_encrypted_sha256_password函式實作sha256加密方式、通過呼叫pg_md5_encrypt函式實作md5方式,而calculate_encrypted_combined_password函式則融合了前面兩種加密方式,加密后系統表中包含了sha256和md5兩種哈希值,實作sha256加密的calculate_encrypted_sha256_password函式執行流程如圖9-7所示,
在這里插入圖片描述

圖9-7 calculate\_encrypted\_sha256\_password函式執行流程

9.2.3 認證機制

整個認證程序中身份認證完成后需要完成最后的認證識別,通過用戶名和密碼來驗證資料庫用戶的身份,判斷其是否為合法用戶,openGauss使用基于RFC5802協議的口令認證方案,該方案是一套包含服務器和客戶端雙向認證的用戶認證機制,
首先客戶端知道用戶名username和密碼password,客戶端發送用戶名username給服務端,服務端檢索相應的認證資訊,例如:salt、StoredKey、ServerKey和迭代次數,然后服務端發送鹽值salt和迭代次數給客戶端,接下來客戶端需要進行一些計算,給服務端發送ClientProof認證資訊,服務端通過ClientProof對客戶端進行認證,并發送ServerSignature給客戶端,最后客戶端通過ServerSignature對服務端進行認證,具體密鑰計算代碼如下所示:

SaltedPassword := Hi(password, salt, iteration_count) /*其中,Hi()本質上是PBKDF2*/
ClientKey := HMAC(SaltedPassword, "Client Key")
StoredKey := sha256(ClientKey)
ServerKey := HMAC(SaltedPassword, "Sever Key")
ClientSignature:=HMAC(StoredKey, token)
ServerSignature:= HMAC(ServerKey, token)
ClientProof:= ClientSignature XOR ClientKey

具體密鑰衍生程序如圖9-8所示,
在這里插入圖片描述

圖9-8 密鑰衍生程序

服務器端存盤的是StoredKey和ServerKey:
(1) StoredKey用來驗證客戶端用戶身份,
服務端認證客戶端通過計算ClientSignature與客戶端發來的ClientProof進行異或運算,從而恢復得到ClientKey,然后將其進行HMAC(hash-based message authentication code,散列資訊認證碼)運算,將得到的值與StoredKey進行對比,如果相等,證明客戶端驗證通過,其中ClientSignature通過StoredKey和token(亂數)進行HMAC計算得到,
(2) ServerKey用來向客戶端表明自己身份的,
客戶端認證服務端,通過計算ServerSignature與服務端發來的值進行比較,如果相等,則完成對服務端的認證,其中ServerSignature通過ServerKey和token(亂數)進行HMAC計算得到,
(3) 在認證程序中,服務端可以計算出來ClientKey,驗證完后直接丟棄不必存盤,
防止服務端偽造認證資訊ClientProof,從而仿冒客戶端,
接下來詳細描述在一個認證會話期間的客戶端和服務端的資訊交換程序,如圖9-9所示,
在這里插入圖片描述

圖9-9 openGauss認證流程

認證流程為:
(1) 客戶端發送username,
(2) 服務端回傳鹽值salt、iteration-count(迭代次數)、ServerSignature以及隨機生成的字串token給客戶端,token是隨機生成字串,服務端通過計算得到的ServerSignature回傳給客戶端,

ServerSignature := HMAC(ServerKey, token)

(3) 客戶端認證服務端并發送認證回應,回應資訊包含客戶端認證資訊ClientProof,ClientProof證明客戶端擁有ClientKey,但是不通過網路的方式發送,在收到資訊后,計算ClientProof,
客戶端利用salt和iteration-count,從password計算得到SaltedPassword,然后通過圖9-9中的公式計算得到ClientKey、StoryKey和ServerKey,
客戶端通過StoredKey和token進行哈希計算得到ClientSignature:

ClientSignature := HMAC(StoredKey,token)

通過將ClientKey和ClientSignature進行異或得到ClientProof:

ClientProof := ClientKey XOR ClientSignature

將計算得到的ClientProof和第(2)步接收的隨機字串發送給服務端進行認證,
(4) 服務端接收并校驗客戶端資訊,
使用其保存的StoredKey和token通過HMAC演算法進行計算,然后與客戶端傳來的ClientProof進行異或,恢復ClientKey;再對ClientKey進行哈希計算,得到的結果與服務端保存的StoredKey進行比較,如果相等則服務端對客戶端的認證通過,否則認證失敗,

ClientSignature := HMAC(StoredKey, token)
HMAC(ClientProof XOR ClientSignature ) = StoredKey

客戶端認證的程序通過呼叫ClientAuthentication函式完成,該函式只有一個型別Port的引數,Port結構中存盤著客戶端相關資訊,Port結構與客戶端相關的部分欄位參見“9.2.1 身份”章節介紹,完整的客戶端認證程序見ClientAuthentication函式,代碼如下所示:

void ClientAuthentication(Port* port)
{
    int status = STATUS_ERROR;
    char details[PGAUDIT_MAXLENGTH] = {0};
    char token[TOKEN_LENGTH + 1] = {0};
    errno_t rc = EOK;
    GS_UINT32 retval = 0;
hba_getauthmethod(port);
……
    switch (port->hba->auth_method) {
        case uaReject:
……
case uaImplicitReject:
        ……
/*  使用MD5口令認證  */
case uaMD5:
            sendAuthRequest(port, AUTH_REQ_MD5);
            status = recv_and_check_password_packet(port);
            break;
/*  使用sha256認證方法  */
case uaSHA256:
            /*  禁止使用初始用戶進行遠程連接  */
            if (isRemoteInitialUser(port)) {
                ereport(FATAL,
                  (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("Forbid remote connection with initial user.")));
    }
    rc = memset_s(port->token, TOKEN_LENGTH * 2 + 1, 0, TOKEN_LENGTH * 2 + 1);
    securec_check(rc, "\0", "\0");
    HOLD_INTERRUPTS();
    /*  生成亂數token  */
    retval = RAND_priv_bytes ((GS_UCHAR*)token, (GS_UINT32)TOKEN_LENGTH);
    RESUME_INTERRUPTS();
    CHECK_FOR_INTERRUPTS();
    if (retval != 1) {
        ereport(ERROR, (errmsg("Failed to Generate the random number,errcode:%u", retval)));
    }
    sha_bytes_to_hex8((uint8*)token, port->token);
    port->token[TOKEN_LENGTH * 2] = '\0';
    /*  發送認證請求到前端,認證碼為AUTH_REQ_SHA256  */
    sendAuthRequest(port, AUTH_REQ_SHA256);
    /*  接收并校驗客戶端的資訊  */
    status = recv_and_check_password_packet(port);
    break;
……
}
……
if (status == STATUS_OK)
    sendAuthRequest(port, AUTH_REQ_OK);
else {
    auth_failed(port, status);
}

/*  完成認證,關閉引數ImmediateInterruptOK  */
t_thrd.int_cxt.ImmediateInterruptOK = false;
}

在這個ClientAuthentication函式中通過先后呼叫hba_getauthmethod函式、check_hba函式,檢查客戶端地址、所連接資料庫、用戶名在檔案HBA中是否有能匹配的HBA記錄(具體HBA及check_hba相關內容參見“9.2.1 身份”節),如果能夠找到匹配的HBA記錄,則將Port結構中相關認證方法的欄位設定為HBA記錄中的引數,同時狀態值為STATUS_OK,然后根據不同的認證方法,進行相應的認證程序,具體認證方法如表9-2所示,在認證程序中可能需要和客戶端進行多次互動,最后回傳如果為STAUS_OK,則表示認證成功,并將認證成功的資訊發送回客戶端,否則發送認證失敗的資訊,

表9-2 認證方法

認證方法

描述

uaReject

0

無條件的拒絕連接

uaTrust

3

無條件的允許連接,即允許匹配HBA記錄的客戶端連入資料庫

uaMD5

5

要求客戶端提供一個MD5加密口令進行認證

uaSHA256

6

要求客戶端提供SHA256加密口令進行認證

uaGSS

7

通過GSS-API(generic security service,通用安全服務;application programming interface,應用編程介面)認證用戶

接下來介紹客戶端認證服務端并發送認證回應,客戶端根據不同的認證方法進行不同的處理程序,當前方法為AUTH_REQ_SHA256時,通過呼叫函式pg_password_sendauth完成對服務端的認證,代碼如下所示:
static int pg_password_sendauth(PGconn* conn, const char* password, AuthRequest areq)
{
int ret;
/*  初始化變數  */
……
    char h[HMAC_LENGTH + 1] = {0};
    char h_string[HMAC_LENGTH * 2 + 1] = {0};
    char hmac_result[HMAC_LENGTH + 1] = {0};
    char client_key_bytes[HMAC_LENGTH + 1] = {0};
    switch (areq) {
      case AUTH_REQ_MD5: 
/*  pg_md5_encrypt()通過MD5Salt進行MD5加密  */
……
case AUTH_REQ_MD5_SHA256:
……
      case AUTH_REQ_SHA256: {
        char* crypt_pwd2 = NULL;
        if (SHA256_PASSWORD == conn->password_stored_method || PLAIN_PASSWORD == conn->password_stored_method) {
            /*  通過SHA256方式加密密碼  */
            if (!pg_sha256_encrypt(
                    password, conn->salt, strlen(conn->salt), (char*)buf, client_key_buf, conn->iteration_count))
                return STATUS_ERROR;

            rc = strncpy_s(server_key_string,
                sizeof(server_key_string),
                &buf[SHA256_LENGTH + SALT_STRING_LENGTH],
                sizeof(server_key_string) - 1);
            securec_check_c(rc, "\0", "\0");
            rc = strncpy_s(stored_key_string,
                sizeof(stored_key_string),
                &buf[SHA256_LENGTH + SALT_STRING_LENGTH + HMAC_STRING_LENGTH],
                sizeof(stored_key_string) - 1);
            securec_check_c(rc, "\0", "\0");
            server_key_string[sizeof(server_key_string) - 1] = '\0';
            stored_key_string[sizeof(stored_key_string) - 1] = '\0';

            sha_hex_to_bytes32(server_key_bytes, server_key_string);
            sha_hex_to_bytes4(token, conn->token);
/*  通過server_key和token呼叫HMAC演算法計算,得到client_server_signature_bytes,通過該變數轉為字串變數,用來驗證與服務端傳來的server_signature是否相等,  */
            CRYPT_hmac_ret1 = CRYPT_hmac(NID_hmacWithSHA256,
                (GS_UCHAR*)server_key_bytes,
                HMAC_LENGTH,
                (GS_UCHAR*)token,
                TOKEN_LENGTH,
                (GS_UCHAR*)client_server_signature_bytes,
                (GS_UINT32*)&hmac_length);
            if (CRYPT_hmac_ret1) {
                return STATUS_ERROR;
            }
            sha_bytes_to_hex64((uint8*)client_server_signature_bytes, client_server_signature_string);

/*  呼叫函式strncmp判斷計算的client_server_signature_string和服務端傳來的server_signature值是否相等  */
            if (PG_PROTOCOL_MINOR(conn->pversion) < PG_PROTOCOL_GAUSS_BASE &&
                0 != strncmp(conn->server_signature, client_server_signature_string, HMAC_STRING_LENGTH)) {
                pwd_to_send = fail_info;  /*  不相等則認證失敗  */
            } else {
                sha_hex_to_bytes32(stored_key_bytes, stored_key_string);
                /*  通過stored_key和token計算得到hmac_result  */
                CRYPT_hmac_ret2 = CRYPT_hmac(NID_hmacWithSHA256,
                    (GS_UCHAR*)stored_key_bytes,
                    STORED_KEY_LENGTH,
                    (GS_UCHAR*)token,
                    TOKEN_LENGTH,
                    (GS_UCHAR*)hmac_result,
                    (GS_UINT32*)&hmac_length);

                if (CRYPT_hmac_ret2) {
                    return STATUS_ERROR;
                }

                sha_hex_to_bytes32(client_key_bytes, client_key_buf);
/*  hmac_result和client_key_bytes異或得到h,然后將其發送給服務端,用于驗證客戶端  */
                if (XOR_between_password(hmac_result, client_key_bytes, h, HMAC_LENGTH)) {
                    return STATUS_ERROR;
                }

                sha_bytes_to_hex64((uint8*)h, h_string);
                pwd_to_send = h_string; /* 設定要發送給服務端的值  */
            }
        } 
……
        break;
/*  清空變數  */
……
    return ret;
}

9.2.4 Kerberos安全認證

Kerberos是一種基于對稱密鑰技術的身份認證協議,開源組件Kerberos可以解決集群內節點或者行程之間的認證問題,即當開啟kerberos之后,惡意用戶無法仿冒集群內節點或行程來登錄資料庫系統,只有內部組件才可以持有用于認證的憑證,從而保證通過Kerberos認證,消減了仿冒風險,提升了資料庫系統的安全性,Kerberos協議認證互動如圖9-10所示,
在這里插入圖片描述

圖9-10 Kerberos認證標準互動流程

其中各角色和定義如表9-3所示(為下文描述方便均以縮寫代替),

表9-3 Kerberos協議角色

角色

說明

KDC(key distribution center,密鑰分發中心)

Kerberos服務程式

Client

需要訪問服務的用戶(principal),KDC和Service會對用戶的身份進行認證

Service

集成了Kerberos的服務,被訪問的服務,需要對客戶端進行認證

AS(authentication service,認證服務)

AS服務器用于身份的校驗, 內部會存盤所有的賬號資訊

TGS(ticket granting service,票據授權服務)

TGT(ticket-granting ticket)票據分發服務

openGauss可在資料庫系統部署完畢之后開啟Kerberos模式,即Kerberos服務部署在資料庫系統機器上,部署程序中會開啟Kerberos相關的服務,并派發憑證給集群內部所有的節點,初始化一系列Kerberos需要用到的環境變數,資料庫內核中通過呼叫GSS-API來實作Kebreros標準協議的通信內容,以openGauss主備之間的認證為例,在Kerberos開啟后openGauss內部行程之間認證流程如圖9-11所示,

在這里插入圖片描述

圖9-11 資料庫系統Kerberos認證流程

Kerberos提供用戶(資料庫管理員)透明的認證機制,資料庫管理員無須感知Kerberos行程/部署情況,圖9-11中分兩部分描述Kerberos互動,左側虛線框內的Kerberos協議實作部分由OM工具完成,OM工具在Kerberos初始化的時候將KDC服務拉起(krb5kdc行程),KDC服務內置了兩個服務:AS和TGS服務,客戶端(openGauss主備等資料庫服務行程)在登錄對端之前會先和KDC互動拿到TGT(ticket granting ticket,根憑證),這個步驟由OM拉起的定時任務呼叫Kerebros提供重繪票據工具來實作,默認24小時重新獲取1次,該獲取TGT的程序對應Kerberos標準協議中的AS-REQ、AS-REP、TGS-REQ和TGS-REP模塊,

右側側虛線框內的資料庫內側認證,主要是圖9-11右側虛線框內的AP-REQ流程實作,簡化流程如圖9-12所示,
在這里插入圖片描述

圖9-12 資料庫系統內核認證互動

資料庫內核封裝GSS-API資料結構,實作跟外部API互動認證,關鍵資料結構源代碼檔案為“src\include\libpq\auth.h”,相關代碼如下:

typedef struct GssConn {
    int sock;
    gss_ctx_id_t gctx;        /*  GSS 背景關系  */
    gss_name_t gtarg_nam;   /*  GSS 名稱  */
    gss_buffer_desc ginbuf;   /*  GSS 輸入token  */
    gss_buffer_desc goutbuf;  /*  GSS 輸出token  */
} GssConn; 
/*  客戶端、服務端介面,用于封裝標準kerberos協議呼叫,其中客戶端介面用于向服務端  */
/*  發起訪問,同時回應服務端介面GssServerAuth發起的票據請求  */
int GssClientAuth(int socket, char* server_host);
int GssServerAuth(int socket, const char* krb_keyfile);

在這里插入圖片描述

圖9-13 資料庫內核Kerberos認證時序圖

認證互動邏輯時序如圖9-13所示,認證流程如下,
(1) 服務端通過資料庫組態檔決定使用Kerberos協議對客戶端連接進行認證,
(2) 發起認證請求,客戶端準備需要Kerberos認證的環境和票證,發’P’報文回應請求并發送票證,
(3) 服務端驗證通過后會發送回應’R’報文,完成Kerberos認證,

感謝大家學習第9章 安全管理原始碼決議中“9.1 安全管理整體架構和代碼概覽、9.2 安全認證”的精彩內容,下一篇我們開啟“9.3 角色管理”的相關內容的介紹,
敬請期待,

💜走過路過,看到這里了,還請各位小伙伴點贊、收藏、評論,千言萬語,不勝感謝💜

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/306467.html

標籤:其他

上一篇:基于樹莓派的智能魔鏡,支持人臉識別、情感監測、熱詞喚醒、語音互動,以及與手機APP互動的實作

下一篇:selenium--面試官問元素定位不到怎么辦?作業中還在為元素定位不到而煩惱?看這一文就夠了--內附決議跟代碼解決案例!讓面試官對你刮目相看

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more