項(xiàng)目經(jīng)驗(yàn)分享|openGauss 陳賢文:受益于開(kāi)源,回饋于開(kāi)源

開(kāi)源之夏個(gè)人專(zhuān)訪與項(xiàng)目經(jīng)驗(yàn)分享持續(xù)開(kāi)放中,歡迎已從開(kāi)源之夏畢業(yè)或正在參與開(kāi)源之夏活動(dòng)的學(xué)生、導(dǎo)師一同加入專(zhuān)訪行動(dòng),掃描文末二維碼填寫(xiě)專(zhuān)訪問(wèn)卷,與大家分享你眼中的開(kāi)源之夏!
本期項(xiàng)目經(jīng)驗(yàn)分享來(lái)自openGauss社區(qū)中選學(xué)生——陳賢文,在開(kāi)源之夏2023中承擔(dān)的項(xiàng)目是openGauss權(quán)限掃描。

#?關(guān)于 openGauss?社區(qū)
openGauss是一款開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),采用木蘭寬松許可證v2發(fā)行。openGauss內(nèi)核深度融合華為在數(shù)據(jù)庫(kù)領(lǐng)域多年的經(jīng)驗(yàn),結(jié)合企業(yè)級(jí)場(chǎng)景需求,持續(xù)構(gòu)建競(jìng)爭(zhēng)力特性。同時(shí)openGauss也是一個(gè)開(kāi)源的數(shù)據(jù)庫(kù)平臺(tái),鼓勵(lì)社區(qū)貢獻(xiàn)、合作。
官網(wǎng):https://opengauss.org/zh/
# 項(xiàng)目基本信息
項(xiàng)目名稱(chēng):openGauss權(quán)限掃描
項(xiàng)目導(dǎo)師:崔永泉
項(xiàng)目描述:根據(jù)openGauss的數(shù)據(jù)庫(kù)配置和用戶(hù)權(quán)限,檢查數(shù)據(jù)庫(kù)中是否存在違規(guī)操作的可能和安全隱患。
項(xiàng)目鏈接:https://summer-ospp.ac.cn/org/prodetail/23c9e0539
# openGauss-安全管理機(jī)制筆記
主要內(nèi)容:openGauss數(shù)據(jù)庫(kù)權(quán)限管理模型、權(quán)限規(guī)劃示例、權(quán)限識(shí)別項(xiàng)目具體實(shí)施方法。
openGauss數(shù)據(jù)庫(kù)權(quán)限管理模型
由于數(shù)據(jù)庫(kù)中存儲(chǔ)著大量重要數(shù)據(jù)和各類(lèi)敏感信息,并且為持有不同權(quán)限的合法用戶(hù)提供數(shù)據(jù)共享服務(wù),這就要求數(shù)據(jù)庫(kù)具備完善的安全防御機(jī)制來(lái)抵抗來(lái)自?xún)?nèi)部和外部的惡意攻擊,以保障數(shù)據(jù)不丟失、隱私不泄露以及數(shù)據(jù)不被篡改等。當(dāng)前openGauss數(shù)據(jù)庫(kù)已經(jīng)構(gòu)建了縱深防御的安全體系,保障數(shù)據(jù)庫(kù)在應(yīng)用中的安全。完善的權(quán)限管理機(jī)制可以有效阻斷惡意用戶(hù)的越權(quán)操作。
常見(jiàn)的權(quán)限控制模型有三種:基于策略的訪問(wèn)控制模型,基于角色的訪問(wèn)控制模型以及基于會(huì)話和角色的訪問(wèn)控制模型。openGauss數(shù)據(jù)庫(kù)采用基于角色的權(quán)限訪問(wèn)控制模型(RBAC),利用角色來(lái)組織和管理權(quán)限,能夠大大簡(jiǎn)化對(duì)權(quán)限的授權(quán)管理。借助角色機(jī)制,當(dāng)給一組權(quán)限相同的用戶(hù)授權(quán)時(shí),只需將權(quán)限授予角色,再將角色授予這組用戶(hù)即可,不需要對(duì)用戶(hù)逐一授權(quán)。而且利用角色權(quán)限分離可以很好地控制不同用戶(hù)擁有不同的權(quán)限,相互制約達(dá)到平衡。
基于角色的權(quán)限訪問(wèn)控制模型(RBAC)
RBAC思想簡(jiǎn)單地說(shuō),一個(gè)用戶(hù)擁有若干角色,每一個(gè)角色擁有若干權(quán)限,每一個(gè)角色擁有若干個(gè)菜單,這樣,就構(gòu)造成“用戶(hù)-角色-權(quán)限”、“角色-菜單” 的授權(quán)模型。在這種模型中,用戶(hù)與角色、角色與權(quán)限、角色與菜單之間構(gòu)成了多對(duì)多的關(guān)系。在openGauss數(shù)據(jù)庫(kù)中,用戶(hù)和角色是基本相同的概念,唯一的區(qū)別是在創(chuàng)建角色的時(shí)默認(rèn)沒(méi)有LOGIN權(quán)限,也不會(huì)自動(dòng)創(chuàng)建同名的模 ,也就是說(shuō)一個(gè)擁有LOGIN權(quán)限的角色可以被認(rèn)為是一個(gè)用戶(hù)。在以下的介紹中我們統(tǒng)一通過(guò)用戶(hù)(USER) 來(lái)連接、訪問(wèn)數(shù)據(jù)庫(kù)以及
執(zhí)行SQL,通過(guò)角色(ROLE)來(lái)組織和管理權(quán)限。我們通過(guò)將不同的權(quán)限打包成角色授予用戶(hù),使得用戶(hù)獲得該角色中的所有權(quán)限。同時(shí)通過(guò)改變角色的權(quán)限,該角色所包含的所有成員的權(quán)限也會(huì)被自動(dòng)修改。
在openGauss數(shù)據(jù)庫(kù)系統(tǒng)中權(quán)限分為兩種:系統(tǒng)權(quán)限和對(duì)象權(quán)限。
系統(tǒng)權(quán)限是指系統(tǒng)規(guī)定用戶(hù)使用數(shù)據(jù)庫(kù)的權(quán)限,比如登錄數(shù)據(jù)庫(kù)、創(chuàng)建數(shù)據(jù)庫(kù)、創(chuàng)建用戶(hù)/角色、創(chuàng)建安全策略等。
對(duì)象權(quán)限是指在數(shù)據(jù)庫(kù)、模式、表、視圖、函數(shù)等數(shù)據(jù)庫(kù)對(duì)象上執(zhí)行特殊動(dòng)作的權(quán)限,不同的對(duì)象類(lèi)型與不同的權(quán)限相關(guān)聯(lián),比如數(shù)據(jù)庫(kù)的連接權(quán)限,表的查看、更新、插入等權(quán)限,函數(shù)的執(zhí)行權(quán)限等。基于特定的對(duì)象來(lái)描述對(duì)象權(quán)限才是有意義的。
系統(tǒng)權(quán)限
系統(tǒng)權(quán)限又稱(chēng)用戶(hù)屬性,具有特定屬性的用戶(hù)會(huì)獲得指定屬性所對(duì)應(yīng)的權(quán)限。系統(tǒng)權(quán)限無(wú)法通過(guò)角色(ROLE)被繼承。在創(chuàng)建用戶(hù)或角色時(shí)可以通過(guò)SQL語(yǔ)句CREATE ROLE/USER指定用戶(hù)具有某些屬性,或者通過(guò)ALTER ROLE/USER的方式給用戶(hù)/角色添加用戶(hù)屬性或取消用戶(hù)屬性。
openGauss數(shù)據(jù)庫(kù)支持如下系統(tǒng)權(quán)限的授予和回收:

openGauss提供SQL語(yǔ)句CREATE/ALTER ROLE/USER實(shí)現(xiàn)系統(tǒng)權(quán)限的授予和回收,示例如下:
#例1:創(chuàng)建角色role1,同時(shí)授予role1創(chuàng)建數(shù)據(jù)庫(kù)的權(quán)限
openGauss=# CREATE ROLE role1 WITH CREATEDB password 'openGauss@2021';
CREATE ROLE
#例2:授予角色role1監(jiān)控管理員的權(quán)限,同時(shí)取消創(chuàng)建數(shù)據(jù)庫(kù)的權(quán)限
openGauss=# ALTER ROLE role1 WITH MONADMIN NOCREATEDB;
ALTER ROLE
#例3:查看系統(tǒng)表pg_authid或系統(tǒng)視圖pg_roles獲取角色role1的相關(guān)信息
openGauss=# SELECT rolname,rolcreatedb,rolmonitoradmin FROM pg_authid WHERE rolname= 'role1';
rolname | rolcreatedb | rolmonitoradmin
---------+-------------+-----------------
role1 ? | f ? ? ? ? ? | t
(1 row)
對(duì)象權(quán)限
對(duì)象所有者缺省具有該對(duì)象上的所有操作權(quán)限,比如修改、刪除對(duì)象的權(quán)限,查看對(duì)象的權(quán)限,將對(duì)象的操作權(quán)限授予其他用戶(hù),或撤銷(xiāo)已經(jīng)授予的操作權(quán)限等。其中對(duì)象的ALTER、 DROP、COMMENT、INDEX、VACUUM以及對(duì)象的可再授予權(quán)限屬于所有者固有的權(quán)限,隱式擁有。但對(duì)象所有者可以撤消自己的普通權(quán)限,例如,使表對(duì)自己以及其他人都只可讀。
對(duì)象權(quán)限可以通過(guò)角色(ROLE)被繼承,這樣方便用戶(hù)將這些單個(gè)的權(quán)限打包成一個(gè)角色進(jìn)行權(quán)限管理。openGauss數(shù)據(jù)庫(kù)針對(duì)每一類(lèi)數(shù)據(jù)庫(kù)對(duì)象支持如下對(duì)象權(quán)限:

openGauss提供SQL語(yǔ)句GRANT/REVOKE實(shí)現(xiàn)對(duì)象權(quán)限的授予和回收:
#創(chuàng)建連接
[omm@localhost root]$ gsql -d postgres -r
gsql ((openGauss 3.1.0 build 4e931f9a) compiled at 2022-09-29 14:40:01 commit 0 last mr ?release)
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.
#創(chuàng)建測(cè)試數(shù)據(jù)
openGauss=# create database testdb;
CREATE DATABASE
openGauss=# \c testdb
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "testdb" as user "omm".
testdb=# create user test identified by 'test@123';
NOTICE: ?The encrypted password contains MD5 ciphertext, which is not secure.
CREATE ROLE
testdb=# create user user1 identified by 'test@123';
NOTICE: ?The encrypted password contains MD5 ciphertext, which is not secure.
CREATE ROLE
testdb=# alter database testdb owner to test;
ALTER DATABASE
testdb=# set search_path to test;
SET
testdb=# create table tbl1 (id int);
CREATE TABLE
testdb=# insert into tbl1 values(1),(2),(3);
INSERT 0 3
#例1:將對(duì)表tbl1進(jìn)行select的權(quán)限以及將select再賦權(quán)的權(quán)限授予用戶(hù)user1,
#賦權(quán)后用戶(hù)user1有權(quán)對(duì)tbl執(zhí)行select操作且user1有權(quán)限將select權(quán)限再賦予其他用戶(hù)
[omm@home ~]$ gsql -d testdb -c "GRANT select ON TABLE test.tbl1 TO user1 WITH GRANT OPTION"
GRANT
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select * from test.tbl1"
ERROR: ?permission denied for schema test
LINE 1: select * from test.tbl1
? ? ? ? ? ? ? ? ? ? ?^
DETAIL: ?N/A
#如上因?yàn)閡ser1沒(méi)有test模式的usage權(quán)限,所以即便給他授權(quán)了模式下的表的select權(quán)限也訪問(wèn)不了
gsql -d testdb -c "GRANT usage ON schema test TO user1"
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO user1"
GRANT
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select * from test.tbl1"
id
----
?1
?2
?3
(3 rows)
#此時(shí)user1沒(méi)有對(duì)表alter、drop的權(quán)限
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "drop table test.tbl1"
ERROR: ?permission denied for relation tbl1
DETAIL: ?N/A
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "alter table test.tbl1 add column name text"
ERROR: ?permission denied for relation tbl1
DETAIL: ?N/A
#例2:將對(duì)表tbl1進(jìn)行alter和drop的權(quán)限賦給用戶(hù)user1
#賦權(quán)后用戶(hù)user1有權(quán)對(duì)tbl1進(jìn)行修改(ALTER)和刪除(DROP)操作
[omm@home ~]$ gsql -d testdb -c "GRANT alter, drop ON TABLE test.tbl1 TO user1;"
GRANT
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "alter table test.tbl1 add column name text"
ALTER TABLE
#例3:撤銷(xiāo)用戶(hù)user1對(duì)表tbl進(jìn)行select的權(quán)限
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select * from test.tbl1"
id | name
----+------
?1 |
?2 |
?3 |
(3 rows)
[omm@home ~]$ gsql -d testdb -c "REVOKE select ON test.tbl1 FROM user1"
REVOKE
#撤銷(xiāo)后用戶(hù)user1對(duì)tbl進(jìn)行select操作會(huì)報(bào)錯(cuò):
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select * from test.tbl1"
ERROR: ?permission denied for relation tbl1
DETAIL: ?N/A
本次項(xiàng)目的目的就在于區(qū)分對(duì)象權(quán)限的情況:
CREATE USER
通過(guò)CREATE USER創(chuàng)建的用戶(hù),默認(rèn)具有LOGIN權(quán)限。
通過(guò)CREATE USER創(chuàng)建用戶(hù)的同時(shí),系統(tǒng)會(huì)在執(zhí)行該命令的數(shù)據(jù)庫(kù)中,為該用戶(hù)創(chuàng)建一個(gè)同名的SCHEMA。
系統(tǒng)管理員在普通用戶(hù)同名schema下創(chuàng)建的對(duì)象,所有者為schema的同名用戶(hù)(非系統(tǒng)管理員)。
CREATE ROLE
角色是擁有數(shù)據(jù)庫(kù)對(duì)象和權(quán)限的實(shí)體。在不同的環(huán)境中角色可以認(rèn)為是一個(gè)用戶(hù),一個(gè)組或者兼顧兩者。
在數(shù)據(jù)庫(kù)中添加一個(gè)新角色,角色無(wú)登錄權(quán)限。
創(chuàng)建角色的用戶(hù)必須具備CREATE ROLE的權(quán)限或者是系統(tǒng)管理員。
schema
Schema又稱(chēng)作模式。通過(guò)管理Schema,允許多個(gè)用戶(hù)使用同一數(shù)據(jù)庫(kù)而不相互干擾,可以將數(shù)據(jù)庫(kù)對(duì)象組織成易于管理的邏輯組,同時(shí)便于將第三方應(yīng)用添加到相應(yīng)的Schema下而不引起沖突。
三權(quán)分立機(jī)制
伴隨著數(shù)據(jù)庫(kù)的發(fā)展以及所面向業(yè)務(wù)場(chǎng)景的擴(kuò)展,對(duì)數(shù)據(jù)庫(kù)權(quán)限分離以及權(quán)限管理的細(xì)粒度劃化提出了更高的要求,為了滿(mǎn)足多樣化用戶(hù)的業(yè)務(wù)安全要求,openGauss數(shù)據(jù)庫(kù)針對(duì)權(quán)限模型進(jìn)行了更細(xì)粒度的權(quán)限劃分,使得用戶(hù)可以更靈活地依據(jù)實(shí)際業(yè)務(wù)進(jìn)行用戶(hù)權(quán)限分配和管理,除了基本系統(tǒng)權(quán)限和對(duì)象權(quán)限的劃分外,還有一些高階的權(quán)限管理機(jī)制用來(lái)滿(mǎn)足客戶(hù)的業(yè)務(wù)訴求,比如三權(quán)分立機(jī)制。
openGauss安裝完成后會(huì)得到一個(gè)具有最高權(quán)限的超級(jí)用戶(hù)。數(shù)據(jù)庫(kù)超級(jí)用戶(hù)的高權(quán)限意味著該用戶(hù)可以做任何系統(tǒng)管理操作和數(shù)據(jù)管理操作,甚至可以修改數(shù)據(jù)庫(kù)對(duì)象,包括接下來(lái)將要介紹的審計(jì)日志信息。對(duì)于企業(yè)管理來(lái)說(shuō), 手握超級(jí)用戶(hù)權(quán)限的管理人員可以在無(wú)人知曉的情況下改變數(shù)據(jù)行為,這帶來(lái)的后果是不可想象的。
在上文提到,初始化用戶(hù)不允許遠(yuǎn)程登錄,僅可本地登錄。那么,在組織行為上由IT 部門(mén)嚴(yán)格監(jiān)控?fù)碛性摍?quán)限的員工在本地的操作行為,就可有效避免諸如修改表中數(shù)據(jù)等“監(jiān)守自盜”行為的發(fā)生。為了實(shí)際管理需要,在數(shù)據(jù)庫(kù)內(nèi)部就需要其他的管理員用戶(hù)來(lái)管理整個(gè)系統(tǒng),如果將大部分的系統(tǒng)管理權(quán)限都交給某一個(gè)用戶(hù)來(lái)執(zhí)行,實(shí)際上也是不合適的,因?yàn)檫@等同于超級(jí)用戶(hù)。
為了很好地解決權(quán)限高度集中的問(wèn)題,在openGauss系統(tǒng)中引入三權(quán)分立角色模型,如圖所示。三權(quán)分立角色模型最關(guān)鍵的三個(gè)角色為安全管理員、系統(tǒng)管理員和審計(jì)管理員。其中,安全管理員用于創(chuàng)建數(shù)據(jù)管理用戶(hù);系統(tǒng)管理員對(duì)創(chuàng)建的用戶(hù)進(jìn)行賦權(quán);審計(jì)管理員則審計(jì)安全管理員、系統(tǒng)管理員、普通用戶(hù)實(shí)際的操作行為。

通過(guò)三權(quán)分立角色模型實(shí)現(xiàn)權(quán)限的分派,且三個(gè)管理員角色獨(dú)立行使權(quán)限,相互制約制衡。使得整個(gè)系統(tǒng)的權(quán)限不會(huì)因?yàn)闄?quán)限集中而引入安全的風(fēng)險(xiǎn)。
事實(shí)上,產(chǎn)品使用過(guò)程中的安全是技術(shù)本身與組織管理雙重保障的結(jié)果,在系統(tǒng)實(shí)現(xiàn)三權(quán)分立模型后,需要有三個(gè)對(duì)應(yīng)的產(chǎn)品自然人分別握有對(duì)應(yīng)的賬戶(hù)信息,以達(dá)到真正權(quán)限分離的目的。
三權(quán)分立是對(duì)系統(tǒng)權(quán)限管理機(jī)制的補(bǔ)充,核心思想是將管理數(shù)據(jù)庫(kù)對(duì)象的權(quán)限、管理用戶(hù)的權(quán)限和管理審計(jì)日志的權(quán)限分離,從而避免一個(gè)管理員擁有過(guò)度集中的權(quán)利帶來(lái)的高風(fēng)險(xiǎn)。通過(guò)將GUC參數(shù)enableSeparationOfDuty設(shè)置為on來(lái)打開(kāi)三權(quán)分立開(kāi)關(guān)。
openGauss=# select name,setting,unit,context from pg_settings where name ~ 'enableSeparationOfDuty';
? ? ? ? ?name ? ? ? ? ?| setting | unit | ?context
------------------------+---------+------+------------
enableSeparationOfDuty | off ? ? | ? ? ?| postmaster
(1 row)
三權(quán)分立開(kāi)關(guān)打開(kāi)后,SYSADMIN的權(quán)限范圍將縮小,不再包括允許創(chuàng)建用戶(hù)/角色的權(quán)限,也不再包括允許查看、刪除數(shù)據(jù)庫(kù)審計(jì)日志的權(quán)限。SYSADMIN,CREATEROLE,AUDITADMIN三種系統(tǒng)權(quán)限的權(quán)限范圍互相隔離,互不影響,而且一個(gè)用戶(hù)僅能被賦予其中一個(gè)屬性。三權(quán)分立打開(kāi)后的權(quán)限范圍如下:

列級(jí)訪問(wèn)控制
在一些業(yè)務(wù)場(chǎng)景中,數(shù)據(jù)表中的某些列存儲(chǔ)了重要的信息,需要對(duì)用戶(hù)不可見(jiàn),但其他列的數(shù)據(jù)又需要用戶(hù)能夠查看或操作,此時(shí)就需要針對(duì)數(shù)據(jù)表的特定列做訪問(wèn)控制,實(shí)現(xiàn)針對(duì)用戶(hù)的列級(jí)別的訪問(wèn)控制。
#創(chuàng)建測(cè)試數(shù)據(jù)
gsql -d postgres -r
create database testdb;
\c testdb
create user test identified by 'test@123';
create user user1 identified by 'test@123';
alter database testdb owner to test;
set search_path to test;
create table tbl (id int,name varchar(20));
insert into tbl values(1,'test1'),(2,'test2'),(3,'test3');
#例1:將對(duì)表tbl的第一列(id)進(jìn)行select的權(quán)限和對(duì)表tbl的第二列(name)進(jìn)行update的權(quán)限授予用戶(hù)user1
#賦權(quán)后用戶(hù)user1有權(quán)對(duì)tbl的第一列執(zhí)行select操作和對(duì)第二列執(zhí)行update操作
[omm@home ~]$ gsql -d testdb -c "GRANT select(id),update(name) ON TABLE test.tbl TO user1;"
GRANT
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select id from test.tbl"
ERROR: ?permission denied for schema test
LINE 1: select id from test.tbl
? ? ? ? ? ? ? ? ? ? ? ^
DETAIL: ?N/A
#如上因?yàn)閡ser1沒(méi)有test模式的usage權(quán)限,所以即便給他授權(quán)了模式下的表的select權(quán)限也訪問(wèn)不了
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO user1"
GRANT
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select id from test.tbl"
id
----
?1
?2
?3
(3 rows)
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select name from test.tbl"
ERROR: ?permission denied for relation tbl
DETAIL: ?N/A
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "update test.tbl set name = 'haha' where id=3"
UPDATE 1
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "update test.tbl set id = 4 where id=3"
ERROR: ?permission denied for relation tbl
DETAIL: ?N/A
#例2:撤銷(xiāo)用戶(hù)user1對(duì)表tbl的第一列id進(jìn)行select的權(quán)限
#撤銷(xiāo)后用戶(hù)user1不再具有查看表tbl的第一列id數(shù)據(jù)的權(quán)限
[omm@home ~]$ gsql -d testdb -c "REVOKE select(id) ON test.tbl FROM user1"
REVOKE
[omm@home ~]$ gsql -d testdb -U user1 -W test@123 ?-c "select id from test.tbl"
ERROR: ?permission denied for relation tbl
DETAIL: ?N/A
行級(jí)訪問(wèn)控制
在實(shí)際業(yè)務(wù)中還存在另外一種場(chǎng)景,同一張數(shù)據(jù)表,只允許用戶(hù)查看滿(mǎn)足特定條件的行數(shù)據(jù),此時(shí)就需要將訪問(wèn)控制精確到數(shù)據(jù)表的行級(jí)別,使得不同用戶(hù)執(zhí)行相同的SQL查詢(xún)、更新或刪除操作,讀取到的結(jié)果是不同的。
用戶(hù)可以在數(shù)據(jù)表上創(chuàng)建行級(jí)訪問(wèn)控制(row level security)策略,該策略是針對(duì)特定數(shù)據(jù)庫(kù)用戶(hù)、特定SQL操作生效的表達(dá)式。當(dāng)數(shù)據(jù)庫(kù)用戶(hù)訪問(wèn)數(shù)據(jù)表時(shí),滿(mǎn)足策略條件的行對(duì)用戶(hù)可見(jiàn),不滿(mǎn)足條件的行對(duì)用戶(hù)不可見(jiàn),從而實(shí)現(xiàn)針對(duì)用戶(hù)的行級(jí)別的訪問(wèn)控制。
openGauss提供SQL語(yǔ)句CREATE/ALTER/DROP ROW LEVEL SECURITY進(jìn)行行級(jí)訪問(wèn)權(quán)限策略的創(chuàng)建/修改/刪除操作:
#創(chuàng)建測(cè)試數(shù)據(jù)
gsql -d postgres -r
create database testdb;
\c testdb
create user test identified by 'test@123';
create user mary identified by 'test@123';
create user tom identified by 'test@123';
alter database testdb owner to test;
set search_path to test;
#步驟1:創(chuàng)建信息表pat_info記錄醫(yī)院病人的個(gè)人信息:
create table pat_info(patience varchar(20),doctor varchar(20),age int);
insert into pat_info values('peter','mary',25),('bob','mary',56),('julie','tom',38)
#查詢(xún)表數(shù)據(jù)
[omm@home ~]$ gsql -d testdb -U test -W test@123 ?-c "select * from test.pat_info"
patience | doctor | age
----------+--------+-----
peter ? ?| mary ? | ?25
bob ? ? ?| mary ? | ?56
julie ? ?| tom ? ?| ?38
(3 rows)
#步驟2:創(chuàng)建行級(jí)訪問(wèn)控制策略,使得醫(yī)生只能查看屬于自己的病人信息:
[omm@home ~]$ gsql -d testdb -c "CREATE ROW LEVEL SECURITY POLICY rls_select ON test.pat_info FOR select USING(doctor=current_user)"
CREATE ROW LEVEL SECURITY POLICY
#步驟3:打開(kāi)信息表pat_info上的行級(jí)訪問(wèn)控制開(kāi)關(guān)
[omm@home ~]$ gsql -d testdb -c "ALTER TABLE test.pat_info ENABLE ROW LEVEL SECURITY;"
ALTER TABLE
#步驟4:將信息表pat_info的查看權(quán)限賦予所有人
[omm@home ~]$ gsql -d testdb -c "grant select on table test.pat_info to public;"
GRANT
#步驟5:Mary醫(yī)生的查看結(jié)果:
[omm@home ~]$ gsql -d testdb -U mary -W test@123 ?-c "select * from test.pat_info"
ERROR: ?permission denied for schema test
LINE 1: select * from test.pat_info
? ? ? ? ? ? ? ? ? ? ?^
DETAIL: ?N/A
[omm@home ~]$
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO mary"
GRANT
[omm@home ~]$ gsql -d testdb -U mary -W test@123 ?-c "select * from test.pat_info"
patience | doctor | age
----------+--------+-----
peter ? ?| mary ? | ?25
bob ? ? ?| mary ? | ?56
(2 rows)
#Tom醫(yī)生的查看結(jié)果:
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO tom"
GRANT
[omm@home ~]$ gsql -d testdb -U tom -W test@123 ?-c "select * from test.pat_info"
行級(jí)訪問(wèn)控制
在實(shí)際業(yè)務(wù)中還存在另外一種場(chǎng)景,同一張數(shù)據(jù)表,只允許用戶(hù)查看滿(mǎn)足特定條件的行數(shù)據(jù),此時(shí)就需要將訪問(wèn)控制精確到數(shù)據(jù)表的行級(jí)別,使得不同用戶(hù)執(zhí)行相同的SQL查詢(xún)、更新或刪除操作,讀取到的結(jié)果是不同的。
用戶(hù)可以在數(shù)據(jù)表上創(chuàng)建行級(jí)訪問(wèn)控制(row level security)策略,該策略是針對(duì)特定數(shù)據(jù)庫(kù)用戶(hù)、特定SQL操作生效的表達(dá)式。當(dāng)數(shù)據(jù)庫(kù)用戶(hù)訪問(wèn)數(shù)據(jù)表時(shí),滿(mǎn)足策略條件的行對(duì)用戶(hù)可見(jiàn),不滿(mǎn)足條件的行對(duì)用戶(hù)不可見(jiàn),從而實(shí)現(xiàn)針對(duì)用戶(hù)的行級(jí)別的訪問(wèn)控制。
openGauss提供SQL語(yǔ)句CREATE/ALTER/DROP ROW LEVEL SECURITY進(jìn)行行級(jí)訪問(wèn)權(quán)限策略的創(chuàng)建/修改/刪除操作:
#創(chuàng)建測(cè)試數(shù)據(jù)
gsql -d postgres -r
create database testdb;
\c testdb
create user test identified by 'test@123';
create user mary identified by 'test@123';
create user tom identified by 'test@123';
alter database testdb owner to test;
set search_path to test;
#步驟1:創(chuàng)建信息表pat_info記錄醫(yī)院病人的個(gè)人信息:
create table pat_info(patience varchar(20),doctor varchar(20),age int);
insert into pat_info values('peter','mary',25),('bob','mary',56),('julie','tom',38)
#查詢(xún)表數(shù)據(jù)
[omm@home ~]$ gsql -d testdb -U test -W test@123 ?-c "select * from test.pat_info"
patience | doctor | age
----------+--------+-----
peter ? ?| mary ? | ?25
bob ? ? ?| mary ? | ?56
julie ? ?| tom ? ?| ?38
(3 rows)
#步驟2:創(chuàng)建行級(jí)訪問(wèn)控制策略,使得醫(yī)生只能查看屬于自己的病人信息:
[omm@home ~]$ gsql -d testdb -c "CREATE ROW LEVEL SECURITY POLICY rls_select ON test.pat_info FOR select USING(doctor=current_user)"
CREATE ROW LEVEL SECURITY POLICY
#步驟3:打開(kāi)信息表pat_info上的行級(jí)訪問(wèn)控制開(kāi)關(guān)
[omm@home ~]$ gsql -d testdb -c "ALTER TABLE test.pat_info ENABLE ROW LEVEL SECURITY;"
ALTER TABLE
#步驟4:將信息表pat_info的查看權(quán)限賦予所有人
[omm@home ~]$ gsql -d testdb -c "grant select on table test.pat_info to public;"
GRANT
#步驟5:Mary醫(yī)生的查看結(jié)果:
[omm@home ~]$ gsql -d testdb -U mary -W test@123 ?-c "select * from test.pat_info"
ERROR: ?permission denied for schema test
LINE 1: select * from test.pat_info
? ? ? ? ? ? ? ? ? ? ?^
DETAIL: ?N/A
[omm@home ~]$
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO mary"
GRANT
[omm@home ~]$ gsql -d testdb -U mary -W test@123 ?-c "select * from test.pat_info"
patience | doctor | age
----------+--------+-----
peter ? ?| mary ? | ?25
bob ? ? ?| mary ? | ?56
(2 rows)
#Tom醫(yī)生的查看結(jié)果:
[omm@home ~]$ gsql -d testdb -c "GRANT usage ON schema test TO tom"
GRANT
[omm@home ~]$ gsql -d testdb -U tom -W test@123 ?-c "select * from test.pat_info"
權(quán)限規(guī)劃示例
將測(cè)試用例全部移植完成,本次移植涉及7個(gè)測(cè)試文件、全部功能接口和搜索選項(xiàng)、近3000行代碼,針對(duì)實(shí)機(jī)進(jìn)行單元測(cè)試,發(fā)現(xiàn)其中的不符合預(yù)期的功能接口,針對(duì)性進(jìn)行調(diào)試適配,確保功能可用。最后整理測(cè)試報(bào)告TESE.md文件,列明測(cè)試用例涉及的接口和實(shí)機(jī)測(cè)試結(jié)果。?
本示例以項(xiàng)目維度進(jìn)行權(quán)限管理示例。
DBA擁有open Gauss實(shí)例的高權(quán)限賬號(hào),名稱(chēng)是dbsuperuser。
舉例業(yè)務(wù)項(xiàng)目名稱(chēng)是oaauth,OA系統(tǒng),新建schema名稱(chēng)是oaauth、oaauth_1。
項(xiàng)目中新增的資源owner賬號(hào)和角色Role規(guī)劃如下:

新增業(yè)務(wù)賬號(hào)時(shí),根據(jù)不同需求,采用如下管理模式創(chuàng)建:
oaauth_readwrite = oaauth_role_readwrite + login權(quán)限
oaauth_readonly = oaauth_role_readonly + login權(quán)限
就是通過(guò)角色加登錄權(quán)限設(shè)計(jì)為需要的新的賬號(hào)。
配置步驟
1. 創(chuàng)建項(xiàng)目資源owner賬號(hào)oaauth_owner和項(xiàng)目Role。DBA使用dbsuperuser高權(quán)限賬號(hào)執(zhí)行如下操作。
--- oaauth_owner 是項(xiàng)目管理賬號(hào),此處密碼僅為示例,請(qǐng)注意修改。
CREATE USER oaauth_owner WITH LOGIN PASSWORD 'asdfy181BASDfadasdbfas';
CREATE ROLE oaauth_role_readwrite;
CREATE ROLE oaauth_role_readonly;
--- 設(shè)置: 對(duì)于oaauth_owner 創(chuàng)建的表,oaauth_role_readwrite 有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權(quán)限。
ALTER DEFAULT PRIVILEGES FOR ROLE oaauth_owner GRANT ALL ON TABLES TO oaauth_role_readwrite;
--- 設(shè)置: 對(duì)于oaauth_owner 創(chuàng)建的SEQUENCES,oaauth_role_readwrite 有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權(quán)限。
ALTER DEFAULT PRIVILEGES FOR ROLE oaauth_owner GRANT ALL ON SEQUENCES TO oaauth_role_readwrite;
--- 設(shè)置: 對(duì)于 oaauth_owner 創(chuàng)建的表, oaauth_role_readonly 只有 DQL(SELECT)權(quán)限。
ALTER DEFAULT PRIVILEGES FOR ROLE oaauth_owner GRANT SELECT ON TABLES TO oaauth_role_readonly;
2. 創(chuàng)建oaauth_readwrite、oaauth_readonly業(yè)務(wù)賬號(hào)。
?DBA使用dbsuperuser高權(quán)限賬號(hào)執(zhí)行如下操作。
--- oaauth_readwrite只有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權(quán)限。
CREATE USER oaauth_readwrite WITH LOGIN PASSWORD 'dfandfnapSDhf23hbEfabf';
GRANT oaauth_role_readwrite TO oaauth_readwrite;
--- oaauth_readonly只有 DQL(SELECT)權(quán)限。
CREATE USER oaauth_readonly WITH LOGIN PASSWORD 'F89h912badSHfadsd01zlk';
GRANT oaauth_role_readonly TO oaauth_readonly;
3. 創(chuàng)建schema oaauth,并授權(quán)給項(xiàng)目Role。
DBA使用dbsuperuser高權(quán)限賬號(hào)執(zhí)行如下操作。
--- schema oaauth的owner是 oaauth_owner賬號(hào)
CREATE SCHEMA oaauth AUTHORIZATION oaauth_owner;
--- 授權(quán)ROLE相關(guān)SCHEMA訪問(wèn)權(quán)限。
GRANT USAGE ON SCHEMA oaauth TO oaauth_role_readwrite;
GRANT USAGE ON SCHEMA oaauth TO oaauth_role_readonly;
說(shuō)明:
oaauth_readwrite和oaauth_readonly自動(dòng)繼承了相關(guān)Role的權(quán)限變更,不需要再額外操作。
應(yīng)用場(chǎng)景示例
場(chǎng)景1:使用oaauth_owner賬號(hào):對(duì)schema oaauth中的表進(jìn)行DDL(CREATE、DROP、ALTER)操作
CREATE TABLE oaauth.test(id bigserial primary key, name text);
CREATE INDEX idx_test_name on oaauth.test(name);
場(chǎng)景2:使用 oaauth_readwrite/oaauth_readonly 賬號(hào)進(jìn)行業(yè)務(wù)開(kāi)發(fā)
業(yè)務(wù)開(kāi)發(fā)遵循最小權(quán)限原則,盡量使用oaauth_readonly賬號(hào),需要DML操作的地方才使用oaauth_readwrite賬號(hào)。這樣也方便在業(yè)務(wù)層做讀寫(xiě)分離。
說(shuō)明:
業(yè)務(wù)層做讀寫(xiě)分離,避免了自動(dòng)讀寫(xiě)分離中間件proxy帶來(lái)的額外成本和性能損耗。
即使目前還沒(méi)有使用只讀實(shí)例,也建議區(qū)分 readonly客戶(hù)端、readwrite客戶(hù)端,為使用只讀實(shí)例做準(zhǔn)備。readonly客戶(hù)端建議使用readonly賬號(hào),最小權(quán)限原則,規(guī)避權(quán)限誤用。
– readonly客戶(hù)端,使用readonly賬號(hào),設(shè)置JDBC URL:只讀實(shí)例1地址,只讀實(shí)例2地址,讀寫(xiě)實(shí)例地址。
– readwrite客戶(hù)端,使用readwrite賬號(hào),設(shè)置JDBC URL:讀寫(xiě)實(shí)例地址。
使用oaauth_readwrite賬號(hào),對(duì)schema oaauth中的表進(jìn)行DQL(SELECT)、DML(UPDATE、INSERT、DELETE)操作:
INSERT INTO oaauth.test (name) VALUES('name0'),('name1');
SELECT id,name FROM oaauth.test LIMIT 1;
--- oaauth_readwrite沒(méi)有 DDL(CREATE、DROP、ALTER)權(quán)限
CREATE TABLE oaauth.test2(id int);
ERROR: ?permission denied for schema oaauth
LINE 1: create table oaauth.test2(id int);
DROP TABLE oaauth.test;
ERROR: ?must be owner of table test
ALTER TABLE oaauth.test ADD id2 int;
ERROR: ?must be owner of table test
CREATE INDEX idx_test_name on oaauth.test(name);
ERROR: ?must be owner of table test
使用oaauth_readonly賬號(hào),對(duì)schema oaauth中的表進(jìn)行DQL(SELECT)操作:
INSERT INTO oaauth.test (name) VALUES('name0'),('name1');
ERROR: ?permission denied for table test
SELECT id,name FROM oaauth.test LIMIT 1;
id | name
----+-------
?1 | name0
(1 row)
場(chǎng)景3:不同項(xiàng)目交叉授權(quán)
如果有另外1個(gè)項(xiàng)目employee,需求為賬號(hào)employee_readwrite增加oaauth項(xiàng)目的表只讀權(quán)限。DBA使用dbsuperuser高權(quán)限賬號(hào)做如下操作:
--- 給賬號(hào) employee_readwrite 加上 oaauth_role_readonly 權(quán)限集合。
GRANT oaauth_role_readonly TO employee_readwrite;
場(chǎng)景4:項(xiàng)目新增 schema oaauth_2,并授權(quán)給項(xiàng)目Role
oaauth_readwrite、oaauth_readonly、employee_readwrite賬號(hào)自動(dòng)繼承了相關(guān)Role的權(quán)限變更,不需要再額外操作。DBA使用dbsuperuser 高權(quán)限賬號(hào)做如下操作:
CREATE SCHEMA oaauth_1 AUTHORIZATION oaauth_owner;
--- 授權(quán)ROLE相關(guān)SCHEMA訪問(wèn)權(quán)限。
--- CREATE 使得 oaauth_role_admin 對(duì)schema oaauth_1中的表有 DDL(CREATE、DROP、ALTER)權(quán)限。
GRANT USAGE ON SCHEMA oaauth_1 TO oaauth_role_readwrite;
GRANT USAGE ON SCHEMA oaauth_1 TO oaauth_role_readonly;
賬號(hào)權(quán)限查詢(xún)
通過(guò)本文介紹的賬號(hào)權(quán)限管理模型創(chuàng)建的賬號(hào),可以通過(guò)如下方式查詢(xún)具體權(quán)限信息。
使用PostgreSQL客戶(hù)端命令行終端連接RDS PostgreSQL數(shù)據(jù)庫(kù),具體請(qǐng)參見(jiàn)連接PostgreSQL實(shí)例?。然后使用\du命令查看:
從上述查詢(xún)結(jié)果示例中可以看出:employee_readwrite賬號(hào)的Member of列中,內(nèi)容為oaauth_role_readonly,employee_role_readwrite,因此,此賬號(hào)對(duì)employee項(xiàng)目表具有DQL和DML權(quán)限,對(duì)oaauth項(xiàng)目表具有DQL權(quán)限。
使用SQL查詢(xún):
SELECT r.rolname, r.rolsuper, r.rolinherit,
?r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
?r.rolconnlimit, r.rolvaliduntil,
?ARRAY(SELECT b.rolname
? ? ? ?FROM pg_catalog.pg_auth_members m
? ? ? ?JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
? ? ? ?WHERE m.member = r.oid) as memberof
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
WHERE r.rolname !~ '^pg_'
ORDER BY 1;
用戶(hù)權(quán)限查詢(xún)實(shí)例
查詢(xún)用戶(hù):\du

查詢(xún)用戶(hù)opengauss的數(shù)據(jù)庫(kù)的權(quán)限:
opengauss=# select a.datname,b.rolname,string_agg(a.pri_t,',') from (select datname,(aclexplode(COALESCE(datacl, acldefault('d'::"char",datdba)))).grantee as grantee,(aclexplode(COALESCE(datacl, acldefault('d'::"char", datdba)))).privilege_type as pri_t from pg_database where datname not like 'template%') a,pg_roles b where (a.grantee=b.oid or a.grantee=0) and b.rolname='opengauss' group by a.datname,b.rolname;
? ?datname ? ?| ?rolname ?| ? ? ? ? ? ? ? ? string_agg ? ? ? ? ? ? ? ?
---------------+-----------+--------------------------------------------
testdb ? ? ? ?| opengauss | TEMPORARY,CONNECT
db_department | opengauss | TEMPORARY,CONNECT
postgres ? ? ?| opengauss | TEMPORARY,CONNECT
opengauss ? ? | opengauss | TEMPORARY,CONNECT,CREATE,TEMPORARY,CONNECT
(4 rows)
顯示用戶(hù)opengauss對(duì)于opengauss數(shù)據(jù)庫(kù)具有TEMPORARY,CONNECT,CREATE,TEMPORARY,CONNECT等權(quán)限
根據(jù)用戶(hù)名查詢(xún)table 權(quán)限,可以通過(guò)視圖information_schema.table_privileges來(lái)查看,為了方便展示,sql如下
opengauss=# select table_name,table_schema,grantee,string_agg(privilege_type,',') from information_schema.table_privileges where grantee='opengauss' group by table_name,table_schema,grantee;
如圖所示,omm對(duì)于各個(gè)表都具有權(quán)限。

# 開(kāi)源之夏個(gè)人隨訪
--項(xiàng)目經(jīng)歷--
OSPP:和大家介紹一下自己吧
陳賢文:大家好!我是來(lái)自華科的陳賢文同學(xué),專(zhuān)業(yè)是機(jī)械工程,目前在國(guó)家數(shù)控中心從事數(shù)控系統(tǒng)算法優(yōu)化與功能開(kāi)發(fā),對(duì)軟件開(kāi)發(fā)和開(kāi)源很感興趣,喜歡用程序化的方式解決重復(fù)性問(wèn)題。
OSPP:最初是怎樣接觸到開(kāi)源的?介紹一下自己的開(kāi)源項(xiàng)目經(jīng)歷?
陳賢文:最早接觸開(kāi)源是在高中的時(shí)候,班上組織活動(dòng)需要使用錄屏工具,上網(wǎng)了解到了OBS Studio,這款開(kāi)源軟件十分的實(shí)用,給我留下了深刻的印象。主要的項(xiàng)目經(jīng)歷一個(gè)是使用Java開(kāi)發(fā)了一款商家外賣(mài)后端管理平臺(tái),完整的學(xué)習(xí)了項(xiàng)目開(kāi)發(fā)流程,鍛煉了基本的開(kāi)發(fā)能力,還有就是自身在從事的數(shù)控系統(tǒng)的開(kāi)發(fā)項(xiàng)目,主要是對(duì)新型加工代碼進(jìn)行識(shí)別加工和規(guī)劃。
OSPP:之前掌握的技術(shù)棧和項(xiàng)目經(jīng)驗(yàn)對(duì)你此次開(kāi)源之夏項(xiàng)目開(kāi)發(fā)有什么幫助嗎?
陳賢文:有很大的幫助,本次開(kāi)發(fā)主要是對(duì)openGauss的權(quán)限掃描和安全策略設(shè)計(jì),通過(guò)學(xué)習(xí),我掌握了數(shù)據(jù)庫(kù)訪問(wèn)控制的操作,會(huì)使用SpringBoot來(lái)搭建開(kāi)發(fā)的框架。
OSPP:以你所在的高校為例,你覺(jué)得當(dāng)前高校學(xué)生參與開(kāi)源的氛圍怎么樣?高校學(xué)生參與開(kāi)源的機(jī)會(huì)多嗎?
陳賢文:當(dāng)前高校學(xué)生參與開(kāi)源的熱情很高,我們實(shí)驗(yàn)室就有很多人報(bào)名開(kāi)源之夏,但是我們高校學(xué)生參與開(kāi)源的機(jī)會(huì)確實(shí)相對(duì)來(lái)說(shuō)比較少,技術(shù)性的開(kāi)源工作對(duì)同學(xué)來(lái)說(shuō)門(mén)檻還是有一定的高。
--參與開(kāi)源社區(qū)--
OSPP:參與開(kāi)源之夏之前是否參與過(guò)開(kāi)源社區(qū)?參與開(kāi)源之夏的過(guò)程中你對(duì)社區(qū)的認(rèn)識(shí)有什么變化嗎?
陳賢文:這是我第一次加入到開(kāi)源社區(qū)中來(lái),我之前對(duì)開(kāi)源軟件和開(kāi)源社區(qū)的概念和運(yùn)作方式有一些了解,但并沒(méi)有實(shí)際參與過(guò)其中的活動(dòng)或貢獻(xiàn)。參與開(kāi)源之夏讓我明白了在開(kāi)源社區(qū)中貢獻(xiàn)的重要性,無(wú)論是提交代碼、修復(fù)漏洞、編寫(xiě)文檔還是提供技術(shù)支持。每個(gè)小的貢獻(xiàn)都可以對(duì)整個(gè)社區(qū)產(chǎn)生積極的影響,并推動(dòng)項(xiàng)目的進(jìn)步。
OSPP:你認(rèn)為團(tuán)隊(duì)協(xié)作能力在開(kāi)源中是如何體現(xiàn)的?
陳賢文:比如分工合作,協(xié)同開(kāi)發(fā),對(duì)一個(gè)功能一起做貢獻(xiàn),還可以社區(qū)互動(dòng),分享經(jīng)驗(yàn),提供幫助等。
OSPP:在開(kāi)發(fā)過(guò)程中,有什么印象深刻的問(wèn)題或經(jīng)歷嗎?社區(qū)和導(dǎo)師為你提供了怎樣的幫助?
陳賢文:深刻的點(diǎn)在剛開(kāi)始接觸openGauss,連接的時(shí)候會(huì)各種報(bào)錯(cuò),自己研究了之后,尋求社區(qū)的幫助,大家一起交流,我在過(guò)程中也結(jié)識(shí)了很多伙伴,導(dǎo)師給我指導(dǎo)了大概的思路和方法,對(duì)我的學(xué)習(xí)指出了方向。
OSPP:是否會(huì)持續(xù)參與開(kāi)源社區(qū)呢?為什么?
陳賢文:我還會(huì)繼續(xù)參與開(kāi)源社區(qū),為開(kāi)源做出自己的一份力,受益于開(kāi)源,回饋于開(kāi)源,提升自我,展現(xiàn)自我。
--寄語(yǔ)--
OSPP:對(duì)想要參與以及還未參與開(kāi)源的同學(xué)鼓勵(lì)一下吧!
陳賢文:開(kāi)源項(xiàng)目就在那里,總有一些新的需求和方向可以為之貢獻(xiàn)自己的力量,當(dāng)我們就有了一定的技術(shù)能力和知識(shí)儲(chǔ)備,了解和掌握開(kāi)源工具、語(yǔ)言和框架了之后,就一起來(lái)加入開(kāi)源社區(qū)吧!找到合適的開(kāi)源項(xiàng)目之后,勇敢和導(dǎo)師與社區(qū)開(kāi)發(fā)者交流,參與進(jìn)來(lái),一起分享自己的知識(shí)和經(jīng)驗(yàn),幫助他人解決問(wèn)題,一起學(xué)習(xí)與成長(zhǎng)!
END
專(zhuān)欄編輯:大夢(mèng)
校對(duì):校大山、陳賢文
制圖:GoodWhite
附錄:
參考:
1、https://blog.csdn.net/myneth/article/details/129036436
2、https://www.kancloud.cn/sinkiang/skadmin_document/1267757
3、schema介紹:https://www.jb51.net/article/275164.htm
4、RDS實(shí)踐
5、sks-admin
6、postgresql查詢(xún)權(quán)限

專(zhuān)欄投稿請(qǐng)聯(lián)系開(kāi)源小助手:kaiyuanzhixia 或?qū)诰庉嫞篐ungryfish34(備注“專(zhuān)欄投稿”加速通過(guò)),或填寫(xiě)下方專(zhuān)訪信息收集問(wèn)卷。
