PGSQL 有提供一個函數 pg_ls_dir(),用來查看主機底下的目錄內容,一直以來
沒什麼太大用途的感覺。。不過,PGSQL 在 v11 幫這個函數導入一個新功能~
方便我們在綁手綁腳的情況底下(例如,僅能透過 pgAdmin 等 UI 看資料庫,不能
夠使用 SSH 登入主機進行管理、操作),一窺主機的狀況。
沒什麼太大用途的感覺。。不過,PGSQL 在 v11 幫這個函數導入一個新功能~
方便我們在綁手綁腳的情況底下(例如,僅能透過 pgAdmin 等 UI 看資料庫,不能
夠使用 SSH 登入主機進行管理、操作),一窺主機的狀況。
這邊用 Linux 上面的 EDB 企業版作示範(原生 PGSQL 也一樣適用)。
在 PGSQL 10 與之前的版本,pg_ls_dir() 是只有限制在查看資料目錄($PGDATA)
裡面的內容物,這之外的目錄是不能查看的。以下是 EDB 10 的狀況:
裡面的內容物,這之外的目錄是不能查看的。以下是 EDB 10 的狀況:
edb=# select version();
version
--------------------------------------------------------------------------------------------------------------
EnterpriseDB 10.7.15 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36), 64-bit
(1 row)
edb=# -- DB Session 當前目錄就位在 $PGDATA 下,這邊以相對目錄語法 ./ 查看
edb=# select pg_ls_dir('.');
pg_ls_dir
------------------------------------------
pg_tblspc
global
pg_commit_ts
pg_dynshmem
pg_notify
pg_serial
pg_snapshots
pg_subtrans
pg_twophase
pg_multixact
base
pg_replslot
pg_stat
pg_stat_tmp
pg_xact
pg_logical
PG_VERSION
postgresql.conf
postgresql.auto.conf
pg_ident.conf
log
pg_hba.conf
pg_wal
postmaster.opts
dbms_pipe
postmaster.pid
current_logfiles
backup_label.old
recovery.done
(29 rows)
edb=# -- 查看上一層目錄 ../
edb=# select pg_ls_dir('..');
ERROR: path must be in or below the current directory
edb=#
到了 PGSQL 11,pg_ls_dir() 的功能擴充了,只要使用足夠權限的帳號(DB Superuser 或是身處 pg_read_server_files 群組),開始可以看到 DB 運作的 OS 帳號可以觸碰的目錄內容了。以下是 EDB 11 的狀況:
edb=# select version();
version
-----------------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 11.1 (EnterpriseDB Advanced Server 11.1.7) on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16), 64-bit
(1 row)
edb=# select pg_ls_dir('.');
pg_ls_dir
----------------------
pg_wal
global
pg_commit_ts
pg_dynshmem
pg_notify
pg_serial
pg_snapshots
pg_subtrans
pg_twophase
pg_multixact
base
pg_replslot
pg_tblspc
pg_stat
pg_stat_tmp
pg_xact
pg_logical
PG_VERSION
postgresql.auto.conf
pg_ident.conf
log
postmaster.opts
edb_wait_states
traces
pg_hba.conf
postgresql.conf
postmaster.pid
dbms_pipe
current_logfiles
(29 rows)
edb=# select pg_ls_dir('..');
pg_ls_dir
---------------
backups
data
initdb.log
archived_wals
(4 rows)
edb=#
這個功能,可以處碰到的地方,以 DB Process Owner 可以觸及的目錄位置為限。以下示範去查看 /root 目錄內容,但是會被拒絕
edb=# select pg_ls_dir('/root');
ERROR: could not open directory "/root": Permission denied
edb=#
從這可以看到,這就是為什麼 PostgreSQL 不允許用 root 帳號去啟動資料庫的理由了。
允許這樣查看的 DB 帳號,需要是 pg_read_server_files 這個群組的成員才行。不然,就還是舊版的行為,只能檢視資料目錄裡面的內容物。
這邊直接建立一個普通帳號來觀察:
edb=# \du
List of roles
Role name | Attributes | Member of
-----------------------+------------------------------------------------------------+-----------
aaa | Profile default | {}
aq_administrator_role | No inheritance, Cannot login +| {}
| Profile default |
enterprisedb | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
| Profile default |
edb=# \c edb aaa
You are now connected to database "edb" as user "aaa".
edb=> select pg_ls_dir('..');
ERROR: permission denied for function pg_ls_dir
edb=> select pg_ls_dir('.');
ERROR: permission denied for function pg_ls_dir
edb=>
就算是不小心把這個函數的執行權限賦予帳號 aaa,也是看不到 $PGDATA 的外面
edb=# \df pg_ls_dir
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+-----------+------------------+------------------------+------
pg_catalog | pg_ls_dir | SETOF text | text | func
pg_catalog | pg_ls_dir | SETOF text | text, boolean, boolean | func
(2 rows)
edb=#
edb=# grant EXECUTE on FUNCTION pg_ls_dir(text) to aaa ;
GRANT
edb=# grant EXECUTE on FUNCTION pg_ls_dir(text,boolean,boolean) to aaa ;
GRANT
edb=# \c edb aaa
You are now connected to database "edb" as user "aaa".
edb=> select pg_ls_dir('.');
pg_ls_dir
----------------------
pg_wal
global
pg_commit_ts
pg_dynshmem
pg_notify
pg_serial
pg_snapshots
pg_subtrans
pg_twophase
pg_multixact
base
pg_replslot
pg_tblspc
pg_stat
pg_stat_tmp
pg_xact
pg_logical
PG_VERSION
postgresql.auto.conf
pg_ident.conf
log
postmaster.opts
edb_wait_states
traces
pg_hba.conf
postgresql.conf
postmaster.pid
dbms_pipe
current_logfiles
(29 rows)
edb=>
edb=> select pg_ls_dir('..');
ERROR: path must be in or below the current directory
edb=>
所以,有適當的帳戶管理的狀況下,這是不用困擾的。
若是在無法以 SSH 登入主機的情況,這功能在檢查環境與異常問題還蠻重要的~
一個實際的案例,就是檢查 WAL 備份目錄的存取權限:如果沒有辦法存取,會在 pg_stat_archiver 出現 failed arhcived WAL 的狀態。
在 PGSQL 11 版,還有其他功能比較強大的群組,用來擴增應用、管理的彈性。不過,事情總是有好有壞:有了這些比較強效的功能,就更需要注意帳戶管理以及 HBA 控制,免得好功能變成被鑽的漏洞,那就麻煩了。
參考資料
以下是這陣子很流行的假訊息(虛實參雜)的紀錄:事後官方有澄清了喔
沒有留言:
張貼留言