CKH 網誌

PostgreSQL 16 安全遠端連線:TLS、來源限制與拒絕測試

實測環境與硬體規格

項目實際測試配置
測試日期2026-10-02
作業系統Ubuntu 24.04.5 LTS
主機數量2 台新建隔離 VM;下列資源為每台配置
CPU2 vCPU
記憶體4 GiB
系統磁碟32 GiB;HDD 儲存、VirtIO、ext4
Linux 核心6.8.0-139-generic
PostgreSQLpsql (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)

讓遠端資料庫連線同時具備加密、伺服器身分驗證與來源限制,並實測錯誤憑證、錯誤密碼、明文及不允許來源的拒絕結果。

本文以全新 Ubuntu 24.04 隔離主機和合成資料實測。套件來自經過簽章驗證、符合 Noble 的套件來源;沒有使用正式資料庫或正式網站的帳號。讀者請依自己的環境確認來源與版本。

圖中是測試主機實際 bash PTY 的執行紀錄,由瀏覽器呈現;提示符統一為 lab$,執行結果未改寫。文字命令另行保留,方便複製。

開始前需完成 PostgreSQL 16 的原生安裝與叢集啟動,可先閱讀 Ubuntu 24.04 安裝篇。本系列使用 demo 範例資料庫;需要既有 sample 表的篇章,依 搬機篇的資料建立步驟 準備 100 筆合成資料。請在獨立教學環境操作。

一、先分清楚三道控制

控制用途
TLS + verify-full加密,並驗證 CA 和資料庫主機名稱
SCRAM驗證資料庫帳號與密碼
pg_hba.conf限制哪個來源、資料庫與角色可以使用哪種認證

伺服器 ssl=on 代表提供 TLS,並不代表同一個埠上的所有連線都被強制加密。是否接受明文必須由 HBA 規則明確決定。伺服器 TLS 文件

本文用 db.example.test、伺服器 192.0.2.10、客戶端 192.0.2.11 作文件範例。這些位址不是可直接連入的公開服務;測試 VM 使用隔離路由,讀者須換成自己可達的位址及有權管理的名稱。

二、建立短期教學 CA 與伺服器憑證

在資料庫主機的私有工作目錄執行。CA 私鑰只留在管理端;只把 CA 公開憑證交給客戶端。正式環境應採用受管理的憑證生命週期,不能把本篇兩天效期的教學憑證拿去長期運作。

umask 077
mkdir -p ~/demo-tls && cd ~/demo-tls
openssl req -x509 -newkey rsa:2048 -nodes -days 2 \
  -keyout ca.key -out ca.crt -subj '/CN=Tutorial Test CA'
openssl req -new -newkey rsa:2048 -nodes \
  -keyout server.key -out server.csr -subj '/CN=db.example.test'
cat > server.ext <<'EOF'
subjectAltName=DNS:db.example.test
extendedKeyUsage=serverAuth
EOF
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 2 -extfile server.ext
sudo install -o postgres -g postgres -m 0600 server.key /etc/postgresql/16/main/server.key
sudo install -o postgres -g postgres -m 0644 server.crt /etc/postgresql/16/main/server.crt

三、設定 PostgreSQL 與最小 HBA 規則

先備份既有設定。以下是空白隔離主機的完整示範;有其他應用的正式主機應逐條審查,保留必要管理與復原通道。listen_addresses 的位址要確實存在於伺服器網路介面。

# /etc/postgresql/16/main/conf.d/demo-tls.conf
listen_addresses = '127.0.0.1,192.0.2.10'
ssl = on
ssl_cert_file = '/etc/postgresql/16/main/server.crt'
ssl_key_file = '/etc/postgresql/16/main/server.key'
password_encryption = 'scram-sha-256'
# /etc/postgresql/16/main/pg_hba.conf
local     all   postgres                 peer
local     all   all                      peer
hostssl   demo  app_user 192.0.2.11/32   scram-sha-256
hostnossl all   all      0.0.0.0/0       reject
host      all   all      0.0.0.0/0       reject
host      all   all      ::/0            reject

HBA 由上往下取第一條符合規則。這份配置只允許指定客戶端以 TLS 登入 demo/app_user,明文和其他來源被明確拒絕;若已有更前面的寬鬆規則,後面的限制不會補救它。HBA 規則順序

sudo -u postgres psql -X -d postgres
\password app_user
\q
sudo systemctl restart postgresql@16-main
sudo -u postgres psql -X -d postgres -c 'SHOW ssl;'
openssl x509 -in /etc/postgresql/16/main/server.crt -noout -ext subjectAltName
圖1:伺服器 TLS、SCRAM 與憑證 SAN
圖1:伺服器 TLS、SCRAM 與憑證 SAN。實際 PTY 紀錄,點圖可開啟原尺寸。

四、從另一台客戶端使用 verify-full

先將 CA 公開憑證放在客戶端,並確認 db.example.test 的 DNS 指向資料庫位址。若測試用 hosts 對應由 Cloud-Init 管理,需修改其 hosts 範本或使用受管理 DNS;本次找出開機覆寫後已補驗名稱持續有效。

psql -X -W \
  'host=db.example.test port=5432 user=app_user dbname=demo sslmode=verify-full sslrootcert=/path/to/ca.crt connect_timeout=5' \
  -c 'SELECT current_user, ssl, version, inet_client_addr() FROM pg_stat_ssl WHERE pid=pg_backend_pid();'

verify-full 同時核對信任鏈與主機名稱,不能用 sslmode=require 取代這兩項檢查。上面 -W 讓密碼互動輸入,命令中沒有密碼值。libpq 憑證驗證

圖2:獨立客戶端的實際 TLS 連線;位址為文件範例
圖2:獨立客戶端的實際 TLS 連線;位址為文件範例。實際 PTY 紀錄,點圖可開啟原尺寸。

截圖的 check-demo-tls 是測試專用包裝程式:在客戶端本機讀取權限 0600 的私有密碼,以同一套 libpq 連線參數執行查詢,只列出角色、TLS 與文件用 IP;不是將密碼放在畫面或命令參數。

五、一定要做拒絕測試

測試實際結果
正確 CA、名稱、密碼與來源連線成功;TLS 啟用
sslmode=disableHBA 拒絕明文
錯誤主機名稱憑證名稱驗證失敗
不信任該 CA憑證驗證失敗
錯誤密碼SCRAM 認證失敗
其他來源位址HBA 拒絕

本次重新啟動資料庫與客戶端 VM,再確認範例名稱解析、verify-full、TLS 狀態及來源位址均正確。HBA 是資料庫層限制;網路邊界仍應依實際環境限制 5432 的可達來源。

這次驗證了什麼

驗證項目結果
跨兩台 VM 的 verify-full 連線成功通過
明文、錯誤名稱、CA、密碼與來源皆被拒絕通過
查詢確認 TLS 啟用與指定來源通過
兩台 VM 重新開機後仍正常通過

實測範圍:使用短期教學 CA 與兩台隔離 VM;驗證資料庫認證與來源限制,未測正式 CA 簽發、憑證自動續期、雙向 TLS 或跨 Internet 的 5432 開放。

官方參考資料

伺服器 TLS、pg_hba.conf、verify-full