随着数字化技术的飞速发展,数字、连接、信号、人工智能充斥着人们工作、生活的各个领域。这些数字化信息被快速转换成数据并存放在各式各样的数据库系统中,而且通过进一步的数据管理与分析产生商业价值。这些有价值的数据或被存放在企业相对封闭的私有网络内,或被存放在相对开放的公有云环境下,又或是集成在智能系统中。人们在享受由数字化发展所带来的便捷生活的同时,也可能面临着无处不在的隐私泄露、信息篡改、数据丢失等安全风险。
数据库安全作为数据库系统的护城河,通过访问登录认证、用户权限管理、审计与监视、数据隐私保护以及安全信道等技术手段防止恶意攻击者访问、窃取、篡改和破坏数据库中的数据,阻止未经授权用户通过系统漏洞进行仿冒、提权等路径恶意使用数据库。
openGauss作为新一代自治安全数据库,为有效保障用户隐私数据、防止信息泄露,构建了由内而外的数据库安全保护措施。本篇将介绍和分析openGauss所采用的安全技术以及在不同应用场景下所采取的不同的安全实施策略。
一 、openGauss安全机制概览
作为独立的组件,传统数据库系统构建于特定的操作系统平台上,以对外提供数据服务或通过对接可视化管理界面对外提供数据管理服务,整个系统部署在一个封闭的网络环境中。系统中的数据存放于物理存储介质上,存储介质可以为机械磁盘,也可以为SSD(固态硬盘)。硬件的稳定性和可靠性作为重要的一个环节,保障了数据整体的存储安全。
随着云化技术的快速发展,数据逐步上传到云,系统所处的环境越来越复杂,相对应的系统风险也逐步增加。openGauss作为分布式系统,需要横跨不同的网络区域进行部署。除了需要像传统数据库那样从系统访问、数据导入导出、数据存储等维度来考虑系统安全体系外,还需要考虑网络安全、虚拟隔离等与实际业务场景紧密相关的安全措施。一个完整的openGauss安全机制体系如图1所示。
图1 openGauss安全机制体系
openGauss安全机制充分考虑了数据库可能的接入方,包括 DBA、用户、应用程序以及通过攻击途径连接数据库的攻击者等。
openGauss提供了用户访问所需的客户端工具 GaussSQL(缩写为 gsql),同时支持JDBC/ODBC等通用客户端工具。整个openGauss系统通过认证模块来限制用户对数据库的访问,通过口令认证、证书认证等机制来保障认证过程中的安全,同时可以通过黑白名单限制访问IP。
用户以某种角色登录系统后,通过基于角色的访问控制(Role Based Access Control, RBAC)机制,可获得相应的数据库资源以及对应的对象访问权限。
用户每次在访问数据库对象时,均需要使用存取控制机制———访问控制列表(AccessControlList,ACL) 进行权限校验。常见的用户包括超级用户、管理员用户和普通用户,这些用户依据自身角色的不同,获取相应的权限,并依据 ACL来实现对对象的访问控制。所有访问登录、角色管理、数据库运维操作等过程均通过独立的审计进程进行日志记录,以用于后期行为追溯。
openGauss在校验用户身份和口令之前,需要验证最外层访问源的安全性,包括端口限制和IP地址限制。访问信息源验证通过后,服务端身份认证模块对本次访问的身份和口令进行有效性校验,从而建立客户端和服务端之间的安全信道。整个登录过程通过一套完整的认证机制来保障,满足 RFC5802通信标准。登录系统后用户依据不同的角色权限进行资源管理。角色是目前主流的权限管理概念,角色实际是权限的集合,用户则归属于某个角色组。管理员通过增加和删除角色的权限,可简化对用户成员权限的管理。
用户登录后可访问的数据库对象包括表(Table)、视图(View)、索引(Index)、序列(Sequence)、数据库(Database)、模式(Schema)、函数(Function)及语言(Language)等。在下文将介绍其他的一些对象。实际应用场景中,不同的用户所获得的权限均不相同,因此每一次对象访问操作,都需要进行权限检查。当用户权限发生变更时,需要更新对应的对象访问权限,且权限变更即时生效。
用户对对象的访问操作本质上是对数据的管理,包括增加、删除、修改、查询等各类操作。数据在存储、传输、处理、显示等阶段都会面临信息泄露的风险。openGauss提供了数据加密、数据脱敏以及加密数据导入导出等机制保障数据的隐私安全。
二、 openGauss安全认证
openGauss是一款标准的基于客户端/服务端(C/S)模式工作的数据库系统,每一个完整的会话连接都由后台服务进程和客户端进程组成。一个完整的openGauss认证过程如图2所示。
图2 openGauss认证详细流程
- 客户端依据用户需求配置相关认证信息,这里主要指 SSL(Secure Sockets Layer,安全套接层)认证相关信息,建立与服务端之间的连接。
- 连接建立完成后,客户端发送访问所需要的连接请求信息给服务端,对请求信息的验证工作都在服务端完成。
- 服务端首先需要进行访问源的校验,即依据配置文件对访问的端口号、访问IP地址、允许用户访问范围以及访问数据对象进行校验。
- 在完成校验后连同认证方式和必要的信息返回给客户端。
- 户端依据认证方式加密口令并发送认证所需的信息给服务端。
- 服务端对收到的认证信息进行认证。认证通过,则启动会话任务与客户端进行通信提供数据库服务;否则,拒绝当前连接,并退出会话。客户端安全认证机制是openGauss的第一层安全保护机制,解决了访问源与数据库服务端间的信任问题。通过这层机制可有效拦截非法用户对数据库进行恶意访问, 避免后续的非法操作。
(一)客户端配置信息
如上面所描述的,安全认证机制首先要解决访问源可信的问题。openGauss通过系统配置将访问方式、访问源IP地址(客户端地址)以及认证方法存放在服务端的配置文件中。与这些信息同时存放的还包括数据库名、用户名。这些信息会组成一条认证记录,存放在配置文件(Host-BasedAut henticationFile,HBA 文件)中。HBA 文件记录的格式可为如下四种格式中的一种:
local DATABASE USER METHOD [OPTIONS]
host DATABASE USER ADDRESS METHOD [OPTIONS]
hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
hostnossl DATABASE USER ADDRESS METHOD [OPTIONS
一个 HBA 文件中可以包含多条记录,一条记录不能跨行存在,每条记录内部是由若干空格、/和制表符分隔的字段组成。在实际认证过程中,身份认证模块需要依据HBA 文件中记录的内容对每个连接请求进行检查,因此记录的顺序是非常关键的。
每一条记录中各个字段的具体含义如下所述:
- local:表示这条记录只接收通过 UNIX域套接字进行的连接。没有这种类型的记录,就不允许 UNIX域套接字的连接。只有在从服务器本机连接且在不指定-U参数的情况下,才是通过 UNIX域套接字连接。
- host:表示这条记录既接收一个普通的 TCP/IP套接字连接,也接收一个经过SSL加密的 TCP/IP套接字连接。
- hostssl:表示这条记录只接收一个经过SSL加密的 TCP/IP套接字连接。
- hostnossl:表示这条记录只接收一个普通的 TCP/IP套接字连接。
- DATABASE:声明当前记录所匹配且允许访问的数据库。特别地,该字段可选用all、sameuser以及samerole。其中all表示当前记录允许访问所有数据库对象; sameuser表示访问的数据库须与请求的用户同名才可访问;samerole表示访问请求的用户必须是与数据库同名角色中的成员才可访问。
- USER:声明当前记录所匹配且允许访问的数据库用户。特别地,该字段可选用all以及“+角色(角色组)”。其中all表示允许对所有数据库用户对象的访问;“+角色(角色组)”表示匹配该角色或属于该角色组的成员,这些成员通过继承方式获得。
- ADDRESS:指定与记录匹配且允许访问的IP地址范围。目前支持IPv4和IPv6两种形式的地址。
- METHOD:声明连接时所使用的认证方法。目前openGauss所支持的认证方法包括trust、reject、sha256、cert及gss。这些将在下文着重介绍。
- OPTIONS:这个可选字段的含义取决于选择的认证方法。目前作为保留项方便后续认证方法扩展,如支持基于ident认证时需要指定映射选项。
在openGauss系统安装部署完成后,HBA 文件中默认包含了超级用户的配置记录。对于其他管理员新创建的用户则需要重新进行配置。对于认证规则的配置建议遵循如下基本原则:
- 靠前的记录有比较严格的连接参数和比较弱的认证方法。
- 靠后的记录有比较宽松的连接参数和比较强的认证方法。
openGauss除了支持手工配置认证信息外,还支持使用 GUC(Grand Unified Configuration)工具进行规则配置,如允许名为jack的用户在客户端工具所在的IP地址为122.10.10.30的地方以sha256方式登录服务端数据库database1:
gs_guc set -Z coordinator -N all -I all -h "host database1 jack 122.10.10.30/32 sha256"
这条命令将在所有的 CN 侧对应的 HBA 文件中添加对应规则。
(二)服务端认证方法
openGauss安全认证方法在 HBA 文件中由数据库运维人员配置,支持trust认证、口令认证和cert认证。
1.trust认证
trust认证意味着采用当前认证模式时,openGauss无条件接收连接请求,且访问请求时无须提供口令。这个方法如果使用不当,可允许所有用户在不提供口令的情况下直接连入数据库。为保障安全,openGauss当前仅支持数据库超级用户在本地以trust方法登录,不允许远程连接使用trust认证方法。
2.口令认证
openGauss目前主要支持sha256加密口令认证。由于整个身份认证过程中,不需要还原明文口令,因此采用 PBKDF2单向加密算法。其中 Hash函数使用sha256算法,盐值salt则通过安全随机数生成。算法中涉及的迭代次数可由用户自己视不同的场景决定,需考虑安全和性能间的一个平衡。
为了保留对历史版本的兼容性,在某些兼容性场景下,openGauss还支持 MD5算法对口令进行加密,但默认不推荐。
特别地,openGauss管理员用户在创建用户信息时不允许创建空口令,这意味着非超级用户在访问登录时必须提供口令信息(命令方式或交互式方式)。用户的口令信息被存放在系统表pg_authid中的rolpassword字段中,如果为空,则表示出现元信息错误。
3.cert认证
openGauss支持使用SSL安全连接通道(在安全认证通道详细介绍)。cert认证表示使用SSL客户端进行认证,不需要提供用户密码。在该认证模式下,客户端和服务端数据经过加密处理。在连接通道建立后,服务端会发送主密钥信息给客户端以响应客户端的握手信息,这个主密钥将是服务端识别客户端的重要依据。值得注意的是,该认证方式只支持hostssl类型的规则。
在文中,提到openGauss所支持的 METHOD字段选项包括trust、reject、sha256、cert及gss。除去上述介绍的三种认证方法外,reject选项表示对于当前认证规则无条件拒绝,一般用于“过滤”某些特定的主机。gss表示使用基于gssapi的kerberos认证,该认证方法依赖kerberosserver组件,一般用于支持openGauss集群内部通信认证和外部客户端连接认证,外部客户端仅支持gsql(openGauss提供的在命令行下运行的数据库连接工具。)或JDBC连接时使用。
(三) 安全认证通道
openGauss支持SSL标准协议(TLS1.2)。SSL 协议是安全性更高的协议标准, 它们加入了数字签名和数字证书来实现客户端和服务器的双向身份验证,保证了通信双方更加安全的数据传输。
openGauss在安装部署完成后,默认开启SSL认证模式。安装包中也包含了认证所需要的证书和密钥信息。这些证书由 CA 可信中心颁发。假定服务器的私钥为server.key,证书为server.crt,客户端的私钥为client.key,证书为client.crt,CA 根证书名称为cacert.pem。这些证书信息存放在“/home/ommdbadmin”目录。需要说明的是,集群安装部署完成后,服务端证书、私钥及根证书均已默认配置完成。用户只需要配置客户端相关的参数。
1.配置客户端参数
客户端参数配置依据实际场景分为单向认证配置和双向认证配置,整个配置信息存储在客户端工具所在的环境配置文件中(如.bashrc文件)。单向认证需要配置如下参数:
export PGSSLMODE="verify-ca"
export PGSSLROOTCERT="/home/ommdbadmin/cacert.pem"
双向认证需配置如下参数:
export PGSSLCERT="/home/ommdbadmin/client.crt"
export PGSSLKEY="/home/ommdbadmin/client.key"
export PGSSLMODE="verify-ca"
export PGSSLROOTCERT="/home/ommdbadmin/cacert.pem"
2.修改客户端密钥的权限
客户端根证书、密钥、证书以及密钥密码加密文件的权限,需保证为600。如果权限不满足要求,则客户端无法以SSL连接到集群。配置如下:
chmod 600 cacert.pem
chmod 600 client.key
chmod 600 client.crt
chmod 600 client.key.cipher
chmod 600 client.key.ran
在实际应用中,应结合场景进行配置。从安全性考虑,建议使用双向认证方式,此时客户端的 PGSSLMODE变量建议设置为verify-ca。但如果本身数据库处在一个安全的环境下,且业务场景属于高并发、低时延业务则可使用单向认证模式。
除了通过SSL进行安全的 TCP/IP 连接外,openGauss还支持 SSH 隧道进行安全的 TCP/IP连接。SSH 专为远程登录会话和其他网络服务提供安全性的协议。从SSH 客户端来看,SSH 提供了两种级别的安全验证。
- 基于口令的安全验证:使用账号和口令登录到远程主机。所有传输的数据都会被加密,但是不能保证正在连接的服务器就是需要连接的服务器。可能会有其他服务器冒充真正的服务器,也就是受到“中间人”方式的攻击。
- 基于密钥的安全验证:用户必须为自己创建一对密钥,并把公钥放在需要访问的服务器上。这种级别的认证不仅加密所有传送的数据,而且避免“中间人”攻击方式。但是整个登录的过程可能需要10秒。
在实际执行过程中,SSH 服务和数据库服务应运行在同一台服务器上。
(四) RFC5802认证协议
在实际应用过程中,仅仅选定认证方法是不够的,还需要有一套完整的认证机制。这个机制要很好地解决客户端和服务端认证交互过程中的通信风险,还要解决客户端接收到加密口令后的验证问题。
openGauss目前选用标准的 RFC5802 认证机制来解决相关问题。它实际上是SCRAM(Salted Challenge Response Authentication Mechanism,是指Salted质询响应身份验证机制或者基于盐值的质询响应身份验证机制)标准流程中的协议。SCRAM 是一套包含服务器和客户端双向确认的用户认证体系,配合信道绑定可以避免中间人攻击。下面将着重介绍该协议内容。
- 客户端知道用户名username和密码password,客户端发送username给服务端,服 务 端 检 索 相 应 的 认 证 信 息,例 如 salt、StoredKey、ServerKey 和 迭 代 次 数iteration-count(注意,服务端可能对于所有的用户都是用相同的迭代次数)。然后,服务端发送盐值salt和迭代次数给客户端。
- 客户端需要进行一些计算,给服务端发送 ClientProof认证信息,服务端通过ClientProof对客户端进行认证,并发送ServerSignature给客户端。
- 客户端通过ServerSignature对服务端进行认证。具体密钥计算公式如下:
SaltedPassword := Hi (password, salt, i) 其中,Hi()本质上是PBKDF2。
ClientKey := HMAC(SaltedPassword, "Client Key")
StoredKey := Hash(ClientKey)
AuthMessage := client-first-message-bare + "," +
server-first-message + "," +
client-final-message-without-proof
ServerKey := HMAC(SaltedPassword, "Server Key"
其中:
- AuthMessage:是通过连接认证交换的信息来计算的。
- client-first-message-bare:主要包含客户端给服务端发送的用户名username和随机字符串 C-Nonce。
- server-first-message:主 要 是 盐 值 salt、迭 代 次 数 以 及 随 机 生 成 的 字 符 串Nonce。
- client-final-message-without-proof:不包含认证信息 ClientProof,包含随机字符串 Nonce。
具体密钥衍生过程如图3所示。
图3 密钥衍生过程
在这里,服务端存的是StoredKey和ServerKey。
- StoredKey:用来验证客户端的客户身份,服务端认证客户端。通过计算ClientSignature与客户端发来的ClientProof进行异或运算,从而恢复得到 ClientKey, 然后将其进行哈希运算,将得到的值与StoredKey进行对比。如果相等,证明客户端验证通过。
- ServerKey:用来向客户端表明自己身份,客户端认证服务端。通过计算ServerSignature与服务端发来的值进行比较,如果相等,则完成对服务端的认证。
在认证过程中,服务端可以计算出 ClientKey,验证完后直接丢弃不必存储。防止服务端伪造认证信息 ClientProof,从而仿冒客户端。要做到合法的登录,必须知道Password、SaltedPassword或者 ClientKey。如果 StoredKey和 ServerKey泄露,则无法做到合法登录。
图4描述了在一个认证会话期间的客户端和服务端的详细信息交换过程。
图4 服务端、客户端认证标准流程
- 客户端发送username和随机生成的挑战值 C-Nonce给服务端。
- 服务端返回盐值 salt、迭代次数以及随机 生 成 的 挑 战 值 Nonce给 客 户 端。Nonce是将从客户端收到的 C-Nonce和随机生成字符串组合形成的新挑战值。
- 客户端发送认证响应。响应信息包含客户端认证信息 ClientProof和挑战值Nonce。ClientProof证明客户端拥有 ClientKey,但是不通过网络的方式发送。在收到信息后,首先需要校验传来的挑战值 Nonce,校验通过后,计算 ClientProof。 客户端利用盐值salt和迭代次数,从password计算得到 SaltedPassword,然后通过密钥计算公式计算得到ClientKey、StoredKey和ServerKey。计算AuthMessage、ClientSignature。通过将客户端首次发送的信息,服务端首次发送的信息以及客户端的响应信息(不包含认证信息)连接起来得到 AuthMessage。代码如下:
AuthMessage := client-first-message-bare + "," +server-first-message + "," + client-final-message-without-proof
ClientSignature := HMAC(StoredKey, AuthMessage
客户端通过将ClientKey和ClientSignature进行异或得到ClientProof:
ClientProof := ClientKey XOR ClientSignature
将计算得到的ClientProof和第2步接收的随机字符串Nonce发送给服务端进行认证。
- 服务端认证 Nonce和 ClientProof,并且发送自己的认证信息 ServerSignature。首先需要校验Nonce,校验通过后,计算 ServerSignature。使用其保存的StoredKey和AuthMessage通过 HMAC(HashMessageAuthenticationCode,哈希消息认证码) 算法进 行 计 算,然 后 与 客 户 端 传 来 的 ClientProof进 行 异 或,恢 复 ClientKey,再 对ClientKey进行哈希计算,得到的结果与服务端保存的 StoredKey进行比较。如果相等,则服务端对客户端的认证通过。
ClientSignature := HMAC(StoredKey, AuthMessage)
H(ClientProof XOR ClientSignature ) == StoredKe
- 服务端通过计算得到的ServerSignature返回给客户端。
ServerSignature := HMAC(ServerKey, AuthMessage)
- 客户端通过将ServerKey和AuthMessage进行 HMAC计算得到的ServerSignature 与服务端传来的 ServerSignature进行比较。如果相等,则客户端完成对 服 务 端 的 认证。
三、openGauss角色管理机制
数据库发展早期,访问控制通常可以分 为 自 主 访 问 控 制 (Discretionary Access Control,DAC)和强制访问控制(Mandatory Access Control,MAC)。在自主访问控制模式下,用户是数据对象的控制者,用户依据自身的意愿决定是否将自己的对象访问权或部分访问权授予其他用户。而在强制访问控制模式下,对特定用户指定授权,用户不能将权限转交给他人。在实际应用中,DAC模式太弱,MAC又太强,且两者工作量较大,不便于管理。基于角色的访问控制机制(Role-BasedAccessControl,RBAC) 是一种更加灵活的机制,可以作为传统访问控制机制(DAC、MAC)的代替,也是较为有效的管理方法。
openGauss继承了业界目前通用的权限管理模型,实现了基于角色的访问控制机制。整个机制中的核心概念是“角色”,其更深层次的含义是角色组,即角色所拥有的权限实际上对应着这个角色组中所有成员的权限。管理员只需要将管理所希望的权限赋给角色,用户再从角色继承相应的权限即可,而无须对用户进行单一管理。当管理员需要增加和删减相关的权限时,角色组内的用户成员也会自动继承权限变更。
基于角色管理模型,用户可具备对对象的访问操作权限,并基于此完成数据管理。而这些用户所具备的权限是会经常发生变化的,为了有效地防止诸如权限提升、利用权限漏洞进行恶意操作等行为,必须进行权限的合理管控,即对象权限管理。更重要的是,需要在对象被访问操作时对当前用户的合法权限进行有效性检查,即对象权限检查。
(一)角色管理模型
在openGauss内核中,用户和角色是基本相同的两个对象,通过CREATE ROLE和CREATE USER分别来创建角色和用户,两者语法基本相同。以CREATE ROLE的语法为例进行说明,其语法为(通过“\h CREATE ROLE”可以在系统中查询):
CREATE ROLE role_name [ [ WITH ] option [ ... ] ] [ ENCRYPTED | UNENCRYPTED ] { PASSWORD | IDENTIFIED BY } { 'password' | DISABLE };
其中设置子句option的选项可以是:
{SYSADMIN | NOSYSADMIN}
| {AUDITADMIN | NOAUDITADMIN} | {CREATEDB | NOCREATEDB}
| {USEFT | NOUSEFT} | {CREATEROLE | NOCREATEROLE}
| {INHERIT | NOINHERIT} | {LOGIN | NOLOGIN}
| {REPLICATION | NOREPLICATION} | {INDEPENDENT | NOINDEPENDENT}
| {VCADMIN | NOVCADMIN} | CONNECTION LIMIT connlimit
| VALID BEGIN 'timestamp' | VALID UNTIL 'timestamp'
| RESOURCE POOL 'respool' | USER GROUP 'groupuser'
| PERM SPACE 'spacelimit' | NODE GROUP logic_cluster_name
| IN ROLE role_name [, ...] | IN GROUP role_name [, ...]
| ROLE role_name [, ...] | ADMIN role_name [, ...]
| USER role_name [, ...] | SYSID uid
| DEFAULT TABLESPACE tablespace_name | PROFILE DEFAULT
| PROFILE profile_name | PGUSER
该命令仅可由具备 CREATE ROLE或者超级管理员权限的用户执行。对语法中涉及的关键参数做如下说明:
(1)ENCRYPTED | UNENCRYPTED
用于控制密码是否以密文形态存放在系统表中。目前该参数无实际作用,因为密码强制以密文形式存储。
(2)SYSADMIN | NOSYSADMIN
决定一个新创建的角色是否为“系统管理员”,默认为 NOSYSADMIN。
与该参数具有相类似概念的还包括 AUDITADMIN|NOAUDITADMIN、CREATEDB|NOCREATEDB、CREATEROLE|NOCREATEROLE,分别表示新创建的角色是否具有审计管理员权限,是否具有创建数据库权限,以及是否具有创建新角色的权限。
(3)USEFT|NOUSEFT
决定一个新角色是否能操作外表,包括新建外表、删除外表、修改外表和读写外表,默认为 NOUSEFT。
(4)INDEPENDENT|NOINDEPENDENT
定义私有、独立的角色。具有INDEPENDENT 属性的角色,管理员对其进行的控制、访问的权限被分离,具体规则如下:
- 未经INDEPENDENT 角色授权,管理员无权对其表对象进行增加、删除、查询、修改、复制、授权操作。
- 未经INDEPENDENT 角色授权,管理员无权修改INDEPENDENT 角色的继承关系。
- 管理员无权修改INDEPENDENT 角色的表对象的属主。
- 管理员无权去除INDEPENDENT 角色的INDEPENDENT 属性。
- 管理员无权修改INDEPENDENT 角色的数据库口令,INDEPENDENT 角色需要管理好自身口令,口令丢失无法重置。
- 管理员属性用户不允许定义修改为INDEPENDENT 属性。
(5)CONNECTION LIMIT
声明该角色可以使用的并发连接数量,默认值为-1,表示没有限制。
(6)PERM SPACE
设置用户使用空间的大小。
CREATEUSER语法与 CREATE ROLE基本相同,option选项范围也相同。事实上,用户和角色在openGauss内部是基本相同的两个对象。区别在于:①创建角色时默认没有登录权限,而创建用户时包含了登录权限;②创建用户时,系统会默认创建一个与之同名的schema,用于该用户进行对象管理。因此在权限管理实践中,建议通过角色进行权限的管理,通过用户进行数据的管理。
管理员通过 GRANT 语法将角色赋给相应的用户可使该用户拥有角色的权限。而在实际场景中,一个用户可以从属于不同的角色,从而拥有不同角色的权限。同样角色之间的权限也可以进行相互传递。用户在继承来自于不同角色的权限时,应尽量避免权限冲突的场景,如某一用户同时具有角色 A 不能访问表 T 的权限和角色 B访问表 T 的权限。
为了更清晰地描述权限管理模型,需要说明openGauss系统中的权限分为两种类型:系统权限和对象权限。系统权限描述了用户使用数据库的权限(如访问数据库、创建数据库、创建用户等)。对象权限,顾名思义,描述了用户操作数据库对象的权限(如增加、删除、修改、查表对象、执行函数、使用表空间等)。
通过上述CREATEROLE和CREATE USER的语法发现,在创建过程中,通过指定每一个options的值就可以设定该角色的属性。而这些属性事实上定义了该角色的系统权限,以及该角色登录认证的方式。这些属性包括是否具备登录权限(LOGIN),是否为超级用户(SUPERUSER),是否具备创建数据库的权限(CREATEDB),是否具备创建角色的权限(CREATEROLE),当前角色的初始口令信息(PASSWORD)以及是否可以继承其所属角色的权限的能力(INHERIT)。
角色所有的权限都记录在系统表pg_authid里面,通过对应的字段进行描述。如pg_authid表中对应的createrole字段用于标记当前角色是否拥有创建角色的权利。
角色的这些系统属性实际 上 定 义 了 用 户 使 用 数 据 库 权 限 的 大 小。例 如,所 有 具 有 CREATEROLE权限的角色都可以创建新的角色或用户。
在整个数据库系统的安装部署时会创建一个初始化用户。该初始化用户拥有最高权限,也称为系统的超级用户,这也是 pg_authid表中唯一一个superuser字段为true(真)的角色。
超级用户可以按照实际的业务诉求创建普通用户,也可以通过其所创建的管理员创建新的普通用户,再进行权限的管理。超级用户可以随时进行权限的赋予和撤回, 也可以直接参与到实际的数据管理业务中。在单用户场景的作业管理模式中,使用超级用户使权限和数据管理变得非常的高效。
(二)三权分立模型
如上文所述,openGauss安装完成后会得到一个具有最高权限的超级用户。数据库超级用户的高权限意味着该用户可以做任何系统管理操作和数据管理操作,甚至可以修改数据库对象,包括接下来将要介绍的审计日志信息。对于企业管理来说, 手握超级用户权限的管理人员可以在无人知晓的情况下改变数据行为,这带来的后果是不可想象的。
在上文提到,初始化用户不允许远程登录,仅可本地登录。那么,在组织行为上由IT 部门严格监控拥有该权限的员工在本地的操作行为,就可有效避免诸如修改表中数据等“监守自盗”行为的发生。为了实际管理需要,在数据库内部就需要其他的管理员用户来管理整个系统,如果将大部分的系统管理权限都交给某一个用户来执行,实际上也是不合适的,因为这等同于超级用户。
为了很好地解决权限高度集中的问题,在openGauss系统中引入三权分立角色模型,如图5所示。三权分立角色模型最关键的三个角色为安全管理员、系统管理员和审计管理员。其中,安全管理员用于创建数据管理用户;系统管理员对创建的用户进行赋权;审计管理员则审计安全管理员、系统管理员、普通用户实际的操作行为。
图5 三权分立角色模型
通过三权分立角色模型实现权限的分派,且三个管理员角色独立行使权限,相互制约制衡。使得整个系统的权限不会因为权限集中而引入安全的风险。
事实上,产品使用过程中的安全是技术本身与组织管理双重保障的结果,在系统实现三权分立模型后,需要有三个对应的产品自然人分别握有对应的账户信息,以达到真正权限分离的目的。
(三)对象访问控制
数据库中每个对象所拥有的权限信息经常发生变化,比如授予对象的部分操作权限给其他用户,或者删除用户对某些对象的操作权限。为了保护数据安全,当用户要对某个数据库对象进行操作之前,必须检查用户对对象的操作权限,仅当用户对此对象拥有合法操作的权限时,才允许用户对此对象执行相应操作。ACL(AccessControl list,访问控制列表)是openGauss进行对象权限管理和权限检查的基础。在数据库内部,每个对象都具有一个对应的 ACL,在该 ACL数据结构上存储了此对象的所有授权信息。当用户访问对象时,只有它在对象的 ACL 中并且具有所需的权限时才能访问该对象。当用户对对象的访问权限发生变更时,只需要在 ACL 上更新对应的权限即可。
事实上,ACL是内核中存储控制单元 ACE(Access Control Entry,访问控制项)的集合,这些存储控制单元记录了授权者 OID、受权者 OID 以及权限位三部分信息。其中,权限位是一个32位整数,每一位标记一个具体的权限操作,如 ACL_SELECT(第二位信息)标记查询用户是否有对对象的查询权限。每一个 ACE 对应一个 AclItem结构,记录了完整的对象访问用户和执行单元信息。在openGauss内部,每一个对象都对应一个 ACL,用户可以依据 ACL信息来校验对象上存在的权限信息。依据实际对象(如表、函数、语言)的不同,内核提供了不同的函数以实现对当前对象访问权限的校验:has_table_privilege__ ARGS函数中的星号分别代表用户信息和数据库对象信息。根据 ARGS(泛指一个可变数量的参数列表)提取的诸如用户信息、表信息、需要校验的权限信息,然后依据 ACL中记录的权限集与操作所需的权限集进行比对。如果 ACL记录的权限集大于操作所需的权限集,则 ACL检查通过,否则失败。
当管理者对对象的权限进行授权/回收时,需要修改 ACL 中对应的权限信息,即在对应的权限标记位添加或删除指定的权限(权限对应的标志位被修改为0或者1),完成对 ACL的更新操作。需要注意的是,在实际权限操作中,应尽可能避免循环授权情况的发生。
Gauss松鼠会是汇集数据库爱好者和关注者的大本营, 大家共同学习、探索、分享数据库前沿知识和技术, 互助解决问题,共建数据库技术交流圈。