不過通常都以預設的配置,產生出以 postgres(企業版為 enterprisedb)為 Superuser 的資料庫服務。
除了預設的 Superuser 帳戶之外,Superuser 的權限也可以手動賦予其他新的資料庫帳戶。
更進一步,甚至可以類似 Linux 底下的 sudo 功能,使一個一般帳戶加入一個「Superuser 群組」:平常這些帳戶不能執行 Superuser 權限的動作;但在必要時,便能類似 sudo 一樣,切換身份,暫時成為 Superuser。
那要怎麼設定呢?
在 Postgres 中的帳戶系統中,資料庫這些物件都稱作角色(role);並且可以將角色(role)進一部分成群組(group)和帳戶(user)
群組這種資料庫腳色不能登入,在建立時可以用 NOLOGIN 來設定
postgres=# CREATE ROLE my_superuser SUPERUSER NOLOGIN;
嘗試登入會被禁止,就算 pg_hba.conf 中允許也一樣
postgres=# \c postgres my_superuser FATAL: role "my_superuser" is not permitted to log in Previous connection kept
接著是一般帳戶的建立,以及加入群組。通常一個帳戶可以繼承多個角色,也就是可以加入多個群組的意思(Note:一般帳戶也可以被繼承~)。一般的權限劃上,我們可以使帳戶繼承某些群組,然後在群組上作 GRANT/REVOKE,這麼一來,就不用逐一針對個別帳戶,一個個去配置權限,達到簡化帳戶權限管理的功能。
以下便建立一個普通帳戶,使它加入上面所建立的群組:
postgres=# CREATE USER usual_admin IN ROLE my_superuser NOINHERIT;
現在可見,共有三個帳戶了
postgres=# \du List of roles Role name | Attributes | Member of --------------+------------------------------------------------------------+---------------- my_superuser | Superuser, Cannot login | {} postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} usual_admin | No inheritance | {my_superuser}
接著登入這個一般帳戶
postgres=# \c postgres usual_admin You are now connected to database "postgres" as user "usual_admin". postgres=>
然後開始進行測試。我們利用 pg_shadow 這個系統表的存取來示範。一般狀況下,不是 Superuser 沒辦法存取這個表格,因為這個表格記載帳號密碼資訊。
postgres=> \c You are now connected to database "postgres" as user "usual_admin". postgres=> select * from pg_shadow; ERROR: permission denied for relation pg_shadow
上面顯示,一般狀況下,普通帳戶沒辦法存取 pg_shadow。接著我們便要暫時切換成 Superuser 來存取 pg_shadow。
我們示範 SET ROLE 指令,分別切換當前帳戶為資料庫內建的 Superuser 或成為他所屬群組來作比較。以下所示,目前帳戶沒有繼承預設的 Superuser,因此不能切換過去。然而可以切換到剛剛建立的 Superuser 群組
postgres=> SET ROLE postgres; ERROR: permission denied to set role "postgres" postgres=> SET ROLE my_superuser; SET postgres=# SELECT session_user, current_user; session_user | current_user --------------+-------------- usual_admin | my_superuser (1 row) postgres=# select * from pg_shadow; usename | usesysid | usecreatedb | usesuper | userepl | usebypassrls | passwd | valuntil | useconfig -------------+----------+-------------+----------+---------+--------------+--------+----------+----------- postgres | 10 | t | t | t | t | | | usual_admin | 16386 | f | f | f | f | | | (2 rows) postgres=#
上面查詢了兩個參數,session_user 與 current_user,分別顯示原本這個 Session 的帳戶,以及目前取得的帳戶身份(也就是群組)。我們可以看到這樣會直接切換成 my_superuser 來執行。要中止的話,可以用 RESET ROLE
postgres=# SELECT session_user, current_user; session_user | current_user --------------+-------------- usual_admin | my_superuser (1 row) postgres=# RESET ROLE; RESET postgres=> SELECT session_user, current_user; session_user | current_user --------------+-------------- usual_admin | usual_admin (1 row)
由上對照可見,session role 仍然一樣,只是執行時的 current role 的暫時變動,以取得相關帳戶的執行權限。
有了這種類似 Sudo 的功能,我們就能放心的在 pg_hba.conf 中「凍結」預設 Superuser 的登入,避免不必要的直接登入、使用,降低被攻擊的可能(因為十之八九都是 port 5432 搭配 postgres Superuser,或是 port 5444 搭配 enterprisedb Superuser);一般管理者也能在必要時用自己的帳戶執行 Superuser 指令,又可以減低因為手殘而誤打指令的風險。
可惜的是,在 SET ROLE 時,沒辦法再跳出打密碼確認的功能,因為在 Postgres 登入認證(Authentication)完畢後,就已經是合法的連線,不會再因為特定 SQL 指令而要求用密碼確認權限(Authorisation)。這樣比較像是 No Password Sudoer~
最後一提,SET SESSION AUTHORIZATION 是另一種不一樣的行為:這個指令是從 Superuser 暫時降階到比較普通權限的帳戶。由於該指令能夠連 session 的帳戶都暫且變更掉(請直接參考手冊內範例),相當於重新用其他帳號登入資料庫,這與 SET ROLE 是不一樣的行為。
參考資料:
沒有留言:
張貼留言