Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PostgreSQL SSL 证书

Martin 支持 PostgreSQL 连接的 SSL 证书身份验证。本指南涵盖证书生成、PostgreSQL 配置和 Martin 设置。

何时使用 SSL 证书

在以下情况使用 SSL 证书:

  • martin 和 Postgis 在不同机器上部署
  • 合规要求(PCI DSS、HIPAA 等)
  • 云 PostgreSQL 部署
  • 需要基于证书身份验证的高安全性环境

SSL 模式

sslmode窃听
保护
中间人
攻击保护
说明
disable⛔⛔我不关心安全性,也不想承担加密的开销。
allow🤷⛔我不关心安全性,但如果服务器坚持,我愿意承担加密的开销。
prefer🤷⛔我不关心加密,但如果服务器支持,我愿意承担加密的开销。
require✅⛔我希望我的数据被加密,我接受开销。我相信网络将确保我始终连接到我想要的服务器。
verify-ca✅取决于
CA 策略
我希望我的数据被加密,我接受开销。我想确保我连接到一个我信任的服务器。
verify-full✅✅我希望我的数据被加密,我接受开销。我想确保我连接到一个我信任的服务器,并且它是我指定的那个。

我们的建议:verify-full 或 allow。 在这两者之间的情况并不多。

特别是,默认模式(prefer)没有太大意义。 来自 postgres 文档:

如表所示,从安全角度来看这没有意义,它只是在可能的情况下承诺性能开销。 它仅作为默认值提供以实现向后兼容,不建议在安全部署中使用。

有关不同权衡的更完整解释,请参阅 PostgreSQL SSL 证书文档。

生成证书

对于基本的 SSL 加密,您需要:

  • server-cert.pem - PostgreSQL 服务器证书
  • server-key.pem - PostgreSQL 服务器私钥
  • ca-cert.pem - 证书颁发机构证书
┌─────────────────┐    SSL/TLS     ┌─────────────────┐
│     Martin      │◄─────────────►│   PostgreSQL    │
└─────────────────┘   verify-full  └─────────────────┘
         │                                   │
    ┌─────────┐                        ┌─────────────┐
    │ CA 证书 │                        │ 服务器证书  │
    │         │                        │ 服务器密钥  │
    └─────────┘                        └─────────────┘

自签名证书

要作为 CA 生成证书,您需要一个私钥。 要验证证书,您需要 CA 证书。

# 生成 CA 私钥
openssl genrsa -out ca-key.pem 3072

# 生成 CA 证书
openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem \
    -subj "/C=US/ST=State/L=City/O=Organization/CN=Test CA"

然后您可以生成服务器证书:

# 生成服务器私钥
openssl genrsa -out server-key.pem 3072

# 使用 SAN 扩展生成服务器证书签名请求
openssl req -new -key server-key.pem -out server-csr.pem \
    -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost" \
    -addext "subjectAltName = DNS:localhost"

# 使用 SAN 扩展生成由 CA 签名的服务器证书
openssl x509 -req -days 365 -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem \
    -CAcreateserial -out server-cert.pem -extensions v3_req \
    -extfile <(printf "[v3_req]\nsubjectAltName = DNS:localhost")

# 设置权限
chmod 400 *-key.pem
chmod 444 *-cert.pem ca-cert.pem

生产证书

对于生产环境,使用来自以下的证书:

  • 常规证书颁发机构(Let’s Encrypt、DigiCert、GlobalSign)
  • 云提供商管理的证书颁发机构
  • 组织内部证书颁发机构

PostgreSQL 配置

services:
  db:
    image: postgis/postgis:17-3.5
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - ./server-cert.pem:/var/lib/postgresql/server.crt:ro
      - ./server-key.pem:/var/lib/postgresql/server.key:ro
    command: -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
docker compose up

tip

Postgres 需要 SSL 证书的特定文件权限和所有权。 在 docker 中这可能有点棘手:

alpine 镜像的默认 user:group 为 70:70 debian 镜像的默认 user:group 为 999:999

您可以通过运行以下命令来更改:

chown 999:999 *.pem
chmod 400 *.pem

使用 psql 测试

通过以下方式测试 SSL 连接

PGSSLROOTCERT=ca-cert.pem psql "postgres://postgres:password@localhost:5432/postgres?sslmode=verify-full"

tip

如果您遇到文件权限错误,请确保当前用户可以访问这些文件。 前面的步骤可能将它们设置为当前用户不可读。

然后,通过以下方式验证 SSL 状态

-- 启用 SSL 信息扩展(ssl_is_used 函数所需)
CREATE EXTENSION IF NOT EXISTS sslinfo;

-- 检查 SSL 状态
SELECT ssl_is_used();

-- SSL 连接详细信息
SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid();

Martin 配置

Martin 可以使用环境变量、CLI 或配置文件进行配置。 您选择哪一个取决于您自己。 您不需要配置两次。

  • 环境变量(点击展开)
    export PGSSLROOTCERT=./ca-cert.pem
    export DATABASE_URL="postgres://postgres:password@localhost:5432/postgres?sslmode=verify-full"
    martin
    
  • 配置文件(点击展开)
    postgres:
      ssl_root_cert: './ca-cert.pem'
      connection_string: 'postgres://postgres:password@localhost:5432/postgres?sslmode=verify-full'
    
  • 命令行(点击展开)
    martin --ca-root-file ./ca-cert.pem \
          "postgres://postgres:password@localhost:5432/postgres?sslmode=verify-full"
    

故障排除

您可以通过以下命令获取更多上下文:

export PGSSLMODE=verify-full
export PGSSLROOTCERT=./ca-cert.pem
# 详细 psql
psql -h localhost -U postgres -d postgres -v

# 调试 Martin
RUST_LOG=debug martin postgres://...

可能发生以下错误:

  • 证书验证失败(点击展开)
    • 检查服务器证书是否由 CA 签名
    • 验证 PGSSLROOTCERT 中的 CA 证书路径
    • 确保证书文件可读
  • 主机名验证失败(点击展开)
    • 服务器证书 CN/SAN 必须与主机名匹配
    • 如果主机名不匹配,请使用 verify-ca 而不是 verify-full
  • 权限被拒绝(点击展开)
    • 检查证书文件权限
    • 私钥应该是 chmod 400 并且运行应用程序的用户可读
  • 连接被拒绝(点击展开)
    • 验证 PostgreSQL 接受 SSL 连接
    • 检查 pg_hba.conf 是否允许来自您 IP 的 SSL

通过 SSL 使用 postgres 的安全最佳实践

  • 使用至少 3072 位 RSA 密钥
  • 使用受限权限(chmod 400)保护私钥
  • 在过期前轮换证书
  • 在生产环境中使用 verify-full
  • 监控证书过期
  • 安全存储 ca-key.pem(仅证书管理需要)
  • 对生产证书使用安全的密钥管理