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 控制,免得好功能變成被鑽的漏洞,那就麻煩了。
參考資料
以下是這陣子很流行的假訊息(虛實參雜)的紀錄:事後官方有澄清了喔
沒有留言:
張貼留言