天天看點

你應該知道的數倉安全:都是同名Schema惹的禍

作者:華為雲開發者聯盟

本文分享自華為雲社群《你應該知道的數倉安全——都是同名Schema惹的禍》,作者: zhangkunhn 。

典型場景

經常遇到小夥伴問到:

  • 我是管理者賬号,怎麼還沒有權限?
  • 管理者給我賦權了啊,怎麼還沒有權限?

當小夥伴詢問的時候,我第一時間就會想到都是使用者同名Schema惹的禍。

你應該知道的數倉安全:都是同名Schema惹的禍

同名Schema是私有Schema

我們知道,CREATE USER文法在建立使用者的同時會在目前資料庫中建立一個與使用者同名的SCHEMA。這個Schema很特殊,隻有兩種使用者能在這個Schema下面建立表、視圖、函數等對象:

  1. 使用者自己
  2. 管理者

然而,不管誰建立的,對象的所有者(Owner)都是使用者自己。基于這個事實,我們可以稱使用者同名Schema為私有Schema。私有表明了目前Schema的特殊性,在這個Schema下面的所有對象都是這個使用者自己的,不管是誰建立的。

我們來看一個例子。資料庫中有三個使用者,如表所示。

你應該知道的數倉安全:都是同名Schema惹的禍

使用管理者dbadmin執行以下SQL:

gaussdb=# create table ua.ta (c1 int);
 CREATE TABLE
 gaussdb =# select relname, relowner, rolname from pg_class c, pg_authid a where relname = 'ta' and c.relowner= a.oid;
  relname | relowner | rolname 
 ---------+----------+---------
  t1      |    16546 | ua(不是dbadmin)
 (1 row)           

可以看到:

系統管理者在普通使用者同名schema下建立的對象,所有者為schema的同名使用者

讓我們來總結第一點:同名Schema是私有Schema,這個Schema下面的所有對象的所有者都是使用者自己,不管是誰建立的。管理者在私有Schema下建立的表等對象會發生Owner切換。

視圖規則:按照view的owner做權限檢查

再來談視圖和視圖封裝的基表的權限。視圖對基表的權限檢查是按照視圖的Owner做權限檢查。例如

create view v1 as select * from t1;

使用者執行select * from v1時做權限檢查分為兩步:

  1. 首先檢查目前使用者對視圖v1的SELECT權限;
  2. 然後檢查視圖v1的owner對基表t1的SELECT權限。

而不是直接檢查目前使用者對基表t1的SELECT權限。

總結第二點:視圖會按照視圖的Owner對基表做權限檢查。

私有Schema與視圖規則導緻莫名其妙的權限報錯

由于私有Schema會造成Owner切換,而視圖規則要求對基表按照視圖Owner做權限檢查。那麼在私有Schema下面建立視圖就會導緻莫名其妙的現象:

私有Schema + view規則 --> 管理者無權限通路自己建立的視圖。

gaussdb =# set role dbadmin password ‘*******’;      -- 切換到管理者使用者
 SET
 gaussdb => create table ua.ta (c1 int);              -- 表ta的owner是???
 CREATE TABLE
 gaussdb => create view ub.vb as select * from ua.ta; -- 視圖vb的owner是???
 CREATE VIEW
 gaussdb => select * from ub.vb;                      -- 管理者建立的view,他竟然無權限!!!
 ERROR: SELECT permission denied to user “ub” for relation “ua.ta“             

我們以管理者使用者在使用者ua的私有schema下建立表ta, 之後在使用者ub的schema下建立了視圖vb, 視圖vb的基表是ua.ta。管理者執行對視圖vb的查詢,報錯無權限。

對于這個莫名其妙的現象,我們仔細捋一捋其中的來龍去脈。

  1. 根據私有Schema切換Owner的法則,盡管是管理者建立的,ta的owner切換到ua, 同樣vb的owner應該是u2.
  2. 結合view規則,對基表按照視圖Owner做權限檢查,視圖vb的owner對基表ua.ta是否具有select權限。視圖vb的owner是ub,而ub對ua.ta無select權限,是以查詢報錯。

權限報錯消除

如何解決這種權限報錯呢?從上述梳理中,其實已經明白了如何賦權來消除這種報錯。那就是給視圖的owner使用者ub賦予基表ua.ta的SELCT權限:管理者或者使用者ua執行下面的賦權語句即可。

GRANT SELECT on ua.ta to ub;            

有小夥伴 問了,我每次都這麼仔細捋一捋,感覺很浪費時間,有沒有簡單的方法。答案是有的,隻需從查詢的權限報錯着手,不需要每次都捋一捋。

我們目前的權限報錯有着非常完備的提醒,會給使用者顯示如下提示:

SELECT permission denied to user “user_name” for relation “ schema_name.table_name“

可以看到,權限報錯包括哪個權限、哪個使用者、哪個schema的哪個對象。那麼看到這個之後,可以直接找管理者或者Owner來執行授予操作就可以了。

對于上述報錯,直接就對應到賦權語句:

grant SELECT on schema_name.table_name to user_name;

當然這個賦權跟我們前面的分析是殊途同歸的。

現在來回想下,是不是一切都清晰了。那麼我們再來看一遍示例。以管理者dbadmin執行以下SQL語句。

gaussdb => create table ua.ta (c1 int);              -- ta的owner是ua
 CREATE TABLE
 gaussdb => create view ub.vb as select * from ua.ta; -- vb的owner是ub
 CREATE VIEW
 postgres=# select * from ub.vb;                      -- 按照報錯的指引來
 ERROR: SELECT permission denied to user “ub” for relation “ua.ta“ 
 gaussdb =# grant usage on schema ua to ub;           -- 将schema ua和基表ta的權限給ub
 GRANT
 gaussdb =# grant select on ua.ta to ub;
 GRANT
 postgres=# select * from ub.vb;                      -- 權限檢查通過,可以正常查詢
  c1 
 ----
 (0 rows)           

補充知識:

  1. CREATE USER文法在建立使用者的同時會在目前資料庫中,為該使用者建立一個同名的SCHEMA;其他資料庫中,則不會建立同名的SCHEMA;如果需要,可使用create schema authorization user_name文法,該文法會根據使用者名來建立同名schema。
  2. 為什麼使用者同名Schema這麼特殊,别的Schema沒有這些特點?因為:a) 在建立使用者時同時建立了與使用者同名的Schema,并将Schema的owner設定為同名使用者;b) 在建立對象時,如果建立對象的schema是使用者同名Schema,就會将對象的Owner切換為同名使用者,而不是執行SQL語句的目前使用者。

總結

遇到權限報錯第一時間想到是否涉及同名schema。同名Schema是使用者的私有Schema。私有Schema中所有的對象Owner都是使用者自己,不管是誰建立的。在私有Schema中建立對象,對象Owner會切換到同名使用者。視圖規則是按照視圖Owner來檢查對基表的權限。由于私有Schema的Owner切換機制和視圖規則導緻了同名Schema的權限報錯。根據報錯的提示,授予使用者相應的權限就可以解決權限報錯問題。