Files
secrets/deploy/postgres-tls-hardening.md
agent 1b11f7e976
Some checks failed
Secrets MCP — Build & Release / 检查 / 构建 / 发版 (push) Successful in 3m54s
Secrets MCP — Build & Release / 部署 secrets-mcp (push) Failing after 7s
release(secrets-mcp): v0.3.3 — 强制 PostgreSQL TLS 校验
显式引入数据库 TLS 配置并在生产环境拒绝弱 sslmode,避免连接静默降级。同步更新 deploy/README 与运维 runbook,落地 db.refining.ltd 的证书与服务器配置流程。

Made-with: Cursor
2026-04-01 15:18:14 +08:00

2.5 KiB

PostgreSQL TLS Hardening Runbook

This runbook applies to:

  • PostgreSQL server: 47.117.131.22 (db.refining.ltd)
  • secrets-mcp app server: 47.238.146.244 (secrets.refining.app)

1) Issue certificate for db.refining.ltd (Let's Encrypt + Cloudflare DNS-01)

Install acme.sh on the PostgreSQL server and use a Cloudflare API token with DNS edit permission for the target zone.

curl https://get.acme.sh | sh -s email=ops@refining.ltd
export CF_Token="your_cloudflare_dns_token"
export CF_Zone_ID="your_zone_id"
~/.acme.sh/acme.sh --issue --dns dns_cf -d db.refining.ltd --keylength ec-256

Install cert/key into a PostgreSQL-readable path:

sudo mkdir -p /etc/postgresql/tls
sudo ~/.acme.sh/acme.sh --install-cert -d db.refining.ltd --ecc \
  --fullchain-file /etc/postgresql/tls/fullchain.pem \
  --key-file /etc/postgresql/tls/privkey.pem \
  --reloadcmd "systemctl reload postgresql || systemctl restart postgresql"
sudo chown -R postgres:postgres /etc/postgresql/tls
sudo chmod 600 /etc/postgresql/tls/privkey.pem
sudo chmod 644 /etc/postgresql/tls/fullchain.pem

2) Configure PostgreSQL TLS and access rules

In postgresql.conf:

ssl = on
ssl_cert_file = '/etc/postgresql/tls/fullchain.pem'
ssl_key_file = '/etc/postgresql/tls/privkey.pem'

In pg_hba.conf, allow app traffic via TLS only (example):

hostssl  secrets-mcp  postgres  47.238.146.244/32  scram-sha-256

Keep a safe admin path (local socket or restricted source CIDR) before removing old plaintext host rules.

Reload PostgreSQL:

sudo systemctl reload postgresql

3) Verify server-side TLS

openssl s_client -starttls postgres -connect db.refining.ltd:5432 -servername db.refining.ltd

The handshake should succeed and the certificate should match db.refining.ltd.

4) Update secrets-mcp app server env

Use environment values like:

SECRETS_DATABASE_URL=postgres://postgres:***@db.refining.ltd:5432/secrets-mcp
SECRETS_DATABASE_SSL_MODE=verify-full
SECRETS_ENV=production

If you use private CA instead of public CA, also set:

SECRETS_DATABASE_SSL_ROOT_CERT=/etc/secrets/pg-ca.crt

Restart secrets-mcp after updating env.

5) Verify from app server

Run positive and negative checks:

  • Positive: app starts, migrations pass, dashboard + MCP API work.
  • Negative:
    • wrong hostname -> connection fails
    • wrong CA file -> connection fails
    • disable TLS on DB -> connection fails

This ensures no silent downgrade to weak TLS in production.