Skip to content

PostgreSQL 传输加密(SSL/TLS)

核心概念

PostgreSQL的传输加密基于SSL/TLS协议,用于保护客户端与服务器之间的数据传输安全。主要涉及以下核心概念:

  • SSL/TLS协议:用于加密网络通信的安全协议
  • 数字证书:用于身份验证和加密密钥交换
  • 证书颁发机构(CA):负责颁发和验证数字证书
  • 加密算法:用于数据加密和签名的算法
  • SSL模式:控制客户端与服务器的SSL连接行为

证书管理

生成自签名证书

bash
# 创建证书目录
mkdir -p /etc/postgresql/ssl
cd /etc/postgresql/ssl

# 生成CA私钥
openssl genrsa -des3 -out ca.key 2048

# 生成CA证书
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

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

# 生成服务器证书请求
openssl req -new -key server.key -out server.csr

# 生成服务器证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365

# 移除私钥密码
openssl rsa -in server.key -out server.key

# 设置权限
chmod 600 server.key
chown postgres:postgres server.key

使用商业CA证书

bash
# 生成私钥
openssl genrsa -out server.key 2048

# 生成证书请求
openssl req -new -key server.key -out server.csr

# 将CSR提交给商业CA获取证书
# 收到CA证书后,将证书文件复制到PostgreSQL SSL目录
cp server.crt /etc/postgresql/ssl/
cp intermediate.crt /etc/postgresql/ssl/
cp root.crt /etc/postgresql/ssl/

# 合并证书链
cat server.crt intermediate.crt root.crt > server.chain.crt

服务器配置

基础SSL配置

bash
# 编辑postgresql.conf
vim /etc/postgresql/14/main/postgresql.conf

# 启用SSL
ssl = on

# 指定SSL证书文件
ssl_cert_file = '/etc/postgresql/ssl/server.crt'
ssl_key_file = '/etc/postgresql/ssl/server.key'
ssl_ca_file = '/etc/postgresql/ssl/ca.crt'

# 配置SSL密码套件(推荐使用强加密算法)
ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES'

# 配置SSL协议版本
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = 'TLSv1.3'

# 启用SSL会话缓存
ssl_prefer_server_ciphers = on

强制SSL连接

bash
# 编辑pg_hba.conf,强制某些IP段使用SSL
vim /etc/postgresql/14/main/pg_hba.conf

# 示例:强制所有来自192.168.1.0/24网段的连接使用SSL
hostssl all all 192.168.1.0/24 md5

# 示例:强制所有连接使用SSL
hostssl all all 0.0.0.0/0 md5

重启PostgreSQL服务

bash
systemctl restart postgresql-14

客户端配置

psql客户端配置

bash
# 基本SSL连接
psql "host=db.example.com port=5432 dbname=mydb user=myuser sslmode=require"

# 验证服务器证书
psql "host=db.example.com port=5432 dbname=mydb user=myuser sslmode=verify-ca sslrootcert=/path/to/ca.crt"

# 验证服务器主机名
psql "host=db.example.com port=5432 dbname=mydb user=myuser sslmode=verify-full sslrootcert=/path/to/ca.crt"

应用程序配置(Python示例)

python
# 使用psycopg2配置SSL连接
import psycopg2

conn = psycopg2.connect(
    host="db.example.com",
    port=5432,
    dbname="mydb",
    user="myuser",
    password="mypassword",
    sslmode="verify-full",
    sslrootcert="/path/to/ca.crt"
)

SSL模式说明

SSL模式描述安全级别
disable禁用SSL
allow优先使用非SSL,失败时尝试SSL
prefer优先使用SSL,失败时尝试非SSL
require必须使用SSL,但不验证证书
verify-ca必须使用SSL并验证CA证书
verify-full必须使用SSL并验证CA证书和主机名最高

生产环境最佳实践

证书管理最佳实践

  • 使用2048位或更高强度的RSA密钥
  • 定期轮换证书(建议每1-2年)
  • 安全存储私钥,设置严格的文件权限
  • 使用证书监控工具跟踪证书过期时间
  • 考虑使用自动化工具管理证书生命周期

性能优化

bash
# 启用SSL会话缓存
ssl_session_cache = 'shared:SSL:10m'

# 调整SSL缓冲区大小
ssl_buffer_size = 16384

# 选择高效的加密算法
ssl_ciphers = 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'

# 启用OCSP stapling(PostgreSQL 9.6+)
ssl_stapling = on
ssl_stapling_verify = on

监控与日志

bash
# 启用SSL相关日志
log_connections = on
log_disconnections = on
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h,ssl=%m'

# 监控SSL连接数
SELECT ssl, count(*) FROM pg_stat_ssl GROUP BY ssl;

# 查看SSL连接详细信息
SELECT * FROM pg_stat_ssl;

版本差异考虑

  • PostgreSQL 9.5及以下:支持TLSv1.0和TLSv1.1(已过时)
  • PostgreSQL 9.6+:支持TLSv1.2和OCSP stapling
  • PostgreSQL 12+:支持TLSv1.3
  • PostgreSQL 13+:增强了SSL性能和安全性
  • PostgreSQL 14+:改进了SSL配置选项和默认设置

故障排除

常见问题及解决方案

bash
# 问题1:SSL连接失败,错误信息:"sslmode value "verify-full" invalid when SSL support is not compiled in"
# 解决方法:确认PostgreSQL编译时包含SSL支持
pg_config --configure | grep ssl

# 问题2:证书验证失败,错误信息:"root certificate file "root.crt" does not exist"
# 解决方法:确保ca.crt文件存在且权限正确
ls -la /etc/postgresql/ssl/

# 问题3:SSL握手失败,错误信息:"no pg_hba.conf entry for host"
# 解决方法:检查pg_hba.conf配置,确保使用hostssl而不是host

调试SSL连接

bash
# 启用详细SSL日志
set ssl_renegotiation_limit = 0;
set log_error_verbosity = 'verbose';

# 使用openssl测试SSL连接
openssl s_client -connect db.example.com:5432 -CAfile /path/to/ca.crt

# 检查证书有效期
openssl x509 -in server.crt -noout -dates

常见问题(FAQ)

Q1:如何验证PostgreSQL是否启用了SSL?

A1:可以通过以下方法验证:

sql
-- 检查SSL设置
SHOW ssl;

-- 查看当前连接的SSL状态
SELECT ssl FROM pg_stat_ssl WHERE pid = pg_backend_pid();

-- 使用psql检查
psql "host=localhost dbname=postgres sslmode=require" -c "\conninfo"

Q2:SSL对PostgreSQL性能有什么影响?

A2:SSL会带来一定的性能开销,主要体现在:

  1. CPU开销:用于加密和解密数据
  2. 网络开销:加密后数据量略有增加
  3. 连接建立延迟:SSL握手过程需要额外的网络往返

可以通过以下方法减轻性能影响:

  • 使用高效的加密算法(如AES-GCM)
  • 启用SSL会话缓存
  • 调整SSL缓冲区大小
  • 考虑使用硬件加速(如SSL卸载设备)

Q3:如何配置双向SSL认证?

A3:双向SSL认证要求客户端也提供证书:

bash
# 服务器配置
ssl = on
ssl_ca_file = '/etc/postgresql/ssl/ca.crt'

# 客户端配置
sslmode=verify-full
sslrootcert=/path/to/ca.crt
sslcert=/path/to/client.crt
sslkey=/path/to/client.key

# pg_hba.conf配置
hostssl all all 0.0.0.0/0 cert

Q4:如何更新过期的SSL证书?

A4:按以下步骤更新证书:

  1. 生成新的证书(使用相同的私钥或生成新私钥)
  2. 备份旧证书
  3. 将新证书复制到SSL目录
  4. 重启PostgreSQL服务
  5. 验证新证书是否生效

Q5:如何禁用旧版TLS协议?

A5:在postgresql.conf中配置:

bash
# 仅允许TLSv1.2和TLSv1.3
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = 'TLSv1.3'

# 禁用不安全的密码套件
ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES:!RC4:!SSLv3:!TLSv1:!TLSv1.1'