閱讀729 返回首頁    go 技術社區[雲棲]


Oracle 12c多租戶特性詳解:全局用戶與本地用戶的原理與維護


640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy
(題圖來自Oracle VP , Sally Piao的攝影佳作,感謝攝影師授權)


編輯手記:這一節我們將介紹多租戶架構中用戶及權限的變化,全局用戶和本地用戶,管理方式和內部實現,這篇文章來自<深入解析Oracle>一書的摘錄。


前情回顧:Oracle 12c多租戶特性詳解:從Schema到PDB的變化與隔離


COMMON 和 Local 用戶

無論在 CDB 和 Non-CDB 數據庫中,用戶都擁有一個 Schema,擁有一係列的 Schema 對象,在 CDB 中由於 PDB 的引入,用戶範疇有所不同。


在 CDB 模式下,公用用戶(Common User)和本地用戶(Local User)兩個概念被引入進來,公用用戶可以在 CDB 和 PDB中同時存在,能夠連接 ROOT 和 PDB 進行操作;而本地用戶則隻在特定的 PDB 中存在,也隻能在特定的 PDB 中執行操作;在 PDB 中不能創建公用用戶,而在 CDB 中(CDB$ROOT 中)同樣不能創建本地用戶。


在 CDB 中創建的公用用戶要求以 c##或C## 開頭,以下測試以常規方式命名的用戶將會創建失敗,符合規則的用戶可以被創建:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=
當創建公用用戶時,Oracle 會向每個 PDB 中同時創建該用戶,如果 PDB 未打開,則創建工作會以任務的方式延後。以下查詢顯示數據庫中隻在容器1中存在新創建的用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

此時打開 PDB,則數據庫會自動完成之前掛起的內部創建工作:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


下圖描述了公用用戶和本地用戶的區別:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


在擁有了 CREATE SESSION 權限後,公用用戶能夠登陸包括 Root 在內的任何 Container。公用用戶一般在每個 PDB 中都存在對應的用戶信息,在 PDB 中不能存在與公用用戶重名的用戶,如初始的 SYS 和 SYSTEM 用戶都屬於公用用戶。也隻有公用用戶能夠授權或被授權相應的公用角色和權限。

 

公用權限是指對所有 Container 都有效的係統或者對象權限,例如一個公用用戶被授予了公用權限 CREATE ANY TABLEWITH ADMIN OPTION 可以將這個權限轉授給其他公用用戶。公用用戶之外的權限被稱為本地權限(Local Privilege).

 

公用角色是指在所有 Container 中都可見的角色,這些角色可能包含全局和本地權限。本地角色隻能包含本地權限。授予公用角色的公用權限,對於具有該角色的用戶在任何可以連接的 Container 中都將具有該權限。

 

以下是一些相關的常識性介紹:

  • 一個公用用戶在不同 Container 中的 Schema 可以不同;

  • 本地用戶隻能在各自的 PDB 中進行操作,在不同 PDB 中可以存在同名的本地用戶;

  • PDB 中的本地用戶不能登陸其他 PDB 或 ROOT;

  • PDB 的本地用戶隻需要在本 PDB 內保持用戶名唯一;

  • 本地用戶能否訪問一個公用 Schema 中的對象取決於其擁有的具體權限;

  • PDB 能夠通過 DB Link 訪問其他的 PDB;

 

在 CDB、PDB 模式下,一個權限在被授權的 Container 中存在。因此,在 PDB 中授予的本地權限和角色和在 Non-CDB 中沒有不同,例如,在 PDBHRPDB 中授予本地用戶 HR 的 SELECT ANYTABLE 權限,僅在該 PDB 中生效。

 

相對而言,公用權限和角色可以跨越 Container 生效,當需要跨 Container 進行操作時,需要公用權限或角色,並且這些權限需要在現有和將來創建的 Container 中生效。

 

在 CDB 中,每個權限或者是在某個 Container 中的本地權限,或者是在所有Container中生效的公用權限。公用權限確保公用用戶無需在不同 PDB中重複授權。

 

類似 CREATE ANYTABLE 的權限,其自身既不是公用權限也不是本地權限,如果一個用戶通過 CONTAINER=CURRENT 方式授權,則被授權用戶擁有的是本地權限;如果一個權限通過 CONTAINER=ALL 方式授權,則用戶獲得的是公用權限。因此,一個權限稱其為本地或公用權限,完全依賴於其授權方式。

 

在 CDB 中,每個角色或者是基於 PDB 的本地角色,或者是對全體 PDB 生效的公用角色,所有係統提供的角色(如 DBA)都屬於公用角色。

 

在視圖 DBA_USERS 和 CDB_USERS 中都包含了一個字段 COMMON,用於標識公用用戶和本地用戶。


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


以下查詢顯示 SYSTEM 作為公用用戶在四個容器中存在:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


數據庫中存在17個公用用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


以下查詢列出了數據庫中的本地用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


通過指定 CONTAINER 可以限定創建用戶的類型,當使用 ALL 選項時,以下命令就創建了一個名為 APPADMIN 的公用用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

查詢 dba_users 視圖,可以看到 APPADMIN 的相關用戶屬性:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


注意,在 CDB$ROOT 中不能創建本地用戶或角色:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


在 PDB 中才可以創建本地用戶,以下測試首先連接到 PDB(名稱為 ENMO)中,連接用戶具備 DBA 權限可以創建用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


當然在 PDB 中也不允許創建公用用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


同樣在 PDB 中也不能刪除公用用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

以下 SQL 成功在 PDB 下創建了本地用戶:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

類似的,本地用戶不能被授予公用權限或角色,以下嚐試在全局授權的命令會返回明確的錯誤:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

在 PDB 內授予本地權限之後,新創建的用戶可以登陸本地 PDB 數據庫:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=
下麵來研究一下角色。在 CDB_ROLES 視圖可以查詢 CDB 的角色信息,以下查詢可以看到由於 PDB 的引入,角色記錄大大增加:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

對於 DBA 公用角色來說,在每個 Container 中都存在相應的信息記錄:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=
而對於 PDB_DBA 角色,僅在 PDB 中存在:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

同用戶管理類似,在 CDB$ROOT 中可以建立公用角色,但是不能創建本地角色,公用角色在每個 PDB 中都存在,同樣需要以 c## 為前綴開頭:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

在 PDB 中,同樣不能創建公用角色,僅能創建本地角色:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

對於係統權限和對象權限,CDB 相應的增加了對應視圖用於存儲這些信息:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

在 CDB 中可以像在 NON-CDB 的數據庫中一樣進行權限授予與回收:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


COMMON 和 Local 用戶的內部隔離


在技術實現上,本地用戶和公用用戶都存儲在底層的 USER$ 字典表,該表的結構如下(內容摘錄自 $ORACLE_HOME/rdbms/admin/dcore.bsq 文件):


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


注意以上結構中的 SPARE1 字段,該字段的注釋是“用於 Schema 級別的補充記錄”,那麼這裏補充記錄的是什麼內容呢?


我們再來查看一下 DBA_USERS 這個視圖的內容(摘錄內容自$ORACLE_HOME/rdbms/admin/cdenv.sql 文件),其中顯示 COMMON 字段內容對應了“decode(bitand(u.spare1,128), 128, 'YES', 'NO')”這一運算結果:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

 

針對在 PDB 中創建的 EYGLE 用戶,我們來解析一下 CDB 和 PDB 的用戶隔離,由於用戶信息是存儲在 USER$ 表中,以下查詢顯示在 PDB 中存在的用戶在 CDB 中並不存在,也就是說 PDB 中的用戶,僅在 PDB 自己的 SYSTEM 表空間字典表 USER$ 中存在:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


 首先我們跟蹤一下在 PDB 中創建用戶的過程:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


在跟蹤文件目錄搜索一下創建用戶的語句:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


在跟蹤文件中記錄了創建用戶的過程,密碼已經被隱藏,摘錄主要語句如下,注意 insert 語句將用戶信息插入到 USER$ 表中:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


如果我們在 CDB 級別創建一個公用用戶,那麼 Oracle 數據庫將如何處理呢?

以下在 CDB 級別進行一次跟蹤:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


檢查跟蹤文件,可以發現存在兩次 INSERT USER$ 的操作,其中一次是用戶進程執行的,另外一次由並行進程執行,也就是將同樣的記錄插入到 PDB 中:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

 

現在我們再創建一個新的 PDB:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


打開兩個 PDB:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


接下來啟用會話和全局的跟蹤:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


現在可以看到,除了會話進程插入 USER$ 之外,兩個並行進程執行了向 PDB 的數據插入,這也就是 CDB 與 PDB 的用戶隔離與管理:


640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


文章轉自數據和雲公眾號,原文鏈接

最後更新:2017-07-18 11:33:21

  上一篇:go  Oracle 12c多租戶特性詳解:從Schema到PDB的變化與隔離
  下一篇:go  Oracle 12c多租戶特性詳解:PDB 的創建、克隆與維護