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(仅证书管理需要) - 对生产证书使用安全的密钥管理