暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

openGauss数据库源码解析系列文章——安全管理源码解析(一)

Gauss松鼠会 2022-02-25
1078

Gauss松鼠会

学习 探索 分享数据库知识和技术 共建数据库技术交流圈

关注
openGauss作为新一代自治安全数据库,提供了丰富的数据库基础安全能力,并逐步完善各类高阶安全能力。这些安全能力涵盖了访问登录认证、用户权限管理、审计与追溯及数据安全隐私保护等。本章节将围绕openGauss安全机制进行源码解读,以帮助数据库内核开发者在进行内核开发时正确地理解和使用安全功能接口,持续为产品提供安全保护能力,或基于当前安全能力进一步开发新的安全能力。

9.1  安全管理整体架构和代码概览

不同于数据库其他业务模块,安全管理模块并非逻辑集中的。安全管理模块中的安全能力是分散化的,在数据库整个业务逻辑的不同阶段提供对应的安全能力,从而构建数据库整体纵深安全防御能力。一个完整的安全管理整体架构如图1所示。

图1  openGauss安全机制体系

虽然整个安全机制是分散化的,但是每一个安全子模块都独立负责了一个完整的安全能力。如安全认证机制模块主要解决用户访问控制、登录通道安全问题;用户角色管理模块解决用户创建及用户权限管理问题。因此整体的安全管理体系架构的代码解读也将根据整个体系的划分来进行描述。

1. 认证机制

认证机制子模块在业务流程上主要包括认证配置文件管理、用户身份识别、口令校验等过程,其核心流程及接口定义如图2所示。

图2  openGauss安全认证代码接口

2. 用户角色管理

用户角色管理子模块在业务流程上主要包括角色创建、修改、删除、授权和回收。由于openGauss并未严格区分用户和角色,因此用户的管理与角色管理共用一套接口,仅在部分属性上进行区分。角色管理子模块涉及的功能及其对应的接口如图3所示。

图3  openGauss角色管理代码接口

3. 对象访问控制

对象访问控制子模块在业务流程上主要包括对象授权、对象权限回收以及实际对象操作时的对象权限检查,其核心流程及接口定义如图4所示。

图4  openGauss对象权限管理代码接口

4. 审计机制

审计机制子模块主要包括审计日志的创建和管理以及数据库的各类管理活动和业务活动的审计追溯。审计日志管理包括新创建审计日志、审计日志轮转、审计日志清理。审计日志追溯包括活动发生时的日志记录以及审计信息查询接口。其核心流程及接口定义如图5所示。

图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”配置文件中的认证方式。口令加密与认证方式对应关系如表1所示。
表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

创建用户和修改用户属性的函数入口分别为CreateRoleAlterRole在函数内对口令加密前会先校验是否满足口令复杂度,如果满足则调用calculate_encrypted_password函数实现口令的加密。加密时根据参数password_encryption_type配置选择对应的加密方式,加密完成后会清理内存中的敏感信息并返回口令密文。口令加密流程如图6所示

 

图6  口令加密流程图

如图6所示,通过调用calculate_encrypted_sha256_password函数实现sha256加密方式、通过调用pg_md5_encrypt函数实现md5方式,而calculate_encrypted_combined_password函数则融合了前面两种加密方式,加密后系统表中包含了sha256和md5两种哈希值。实现sha256加密的calculate_encrypted_sha256_password函数执行流程如图7所示。

图7  calculate_encrypted_sha256_password函数执行流程

以上图文详细介绍了安全管理整体架构和代码概览及安全认证中身份认证口令存储的相关内容,下篇图文将继续介绍安全认证中认证机制、Kerberos安全认证的相关内容,敬请期待!


- END -





Gauss松鼠会
汇集数据库从业人员及爱好者
互助解决问题 共建数据库技术交流圈


文章转载自Gauss松鼠会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论