Skip to content

PostgreSQL SSL/TLS配置

SSL/TLS 证书生成

SSL/TLS 证书是实现加密通信的基础,PostgreSQL 支持自签名证书和第三方权威机构签发的证书。

1. 自签名证书生成

自签名证书适用于内部测试和私有环境,以下是生成步骤:

bash
# 创建证书存储目录
mkdir -p /var/lib/postgresql/15/main/ssl
cd /var/lib/postgresql/15/main/ssl

# 生成根证书私钥(2048位,带密码保护)
openssl genrsa -des3 -out root.key 2048

# 生成根证书签名请求
openssl req -new -key root.key -out root.csr

# 生成自签名根证书(有效期10年)
openssl x509 -req -in root.csr -signkey root.key -out root.crt -days 3650

# 生成服务器私钥(2048位,无密码保护,方便PostgreSQL自动加载)
openssl genrsa -out server.key 2048

# 生成服务器证书请求,指定服务器名称为postgres-server
openssl req -new -key server.key -out server.csr -subj "/CN=postgres-server"

# 使用根证书签署服务器证书(有效期10年)
openssl x509 -req -in server.csr -CA root.crt -CAkey root.key -CAcreateserial -out server.crt -days 3650

# 设置证书文件权限,确保只有postgres用户可访问
chmod 600 server.key
chown postgres:postgres *.key *.crt *.csr

2. 使用 Let's Encrypt 证书

Let's Encrypt 提供免费的受信任证书,适用于生产环境:

bash
# 安装 Certbot 工具(用于获取 Let's Encrypt 证书)
sudo apt-get install certbot

# 使用独立模式获取证书,指定域名 postgres.example.com
sudo certbot certonly --standalone -d postgres.example.com

# 将获取的证书复制到 PostgreSQL 证书目录
sudo cp /etc/letsencrypt/live/postgres.example.com/fullchain.pem /var/lib/postgresql/15/main/ssl/server.crt
sudo cp /etc/letsencrypt/live/postgres.example.com/privkey.pem /var/lib/postgresql/15/main/ssl/server.key

# 设置正确的文件权限和所有者
sudo chown postgres:postgres /var/lib/postgresql/15/main/ssl/*
sudo chmod 600 /var/lib/postgresql/15/main/ssl/server.key

服务器 SSL/TLS 配置

配置 PostgreSQL 服务器使用 SSL/TLS 加密连接,需要修改主配置文件并调整认证规则。

1. 基础配置

修改 postgresql.conf 文件,启用 SSL 并配置证书路径:

txt
# 启用 SSL 加密连接
ssl = on

# 指定 SSL 证书文件路径
ssl_cert_file = 'ssl/server.crt'  # 服务器证书
ssl_key_file = 'ssl/server.key'    # 服务器私钥
ssl_ca_file = 'ssl/root.crt'       # 根证书(可选,用于客户端证书验证)

# 配置允许的 SSL 协议版本
ssl_min_protocol_version = 'TLSv1.2'  # 最低使用 TLS 1.2
ssl_max_protocol_version = 'TLSv1.3'  # 最高支持 TLS 1.3

# 配置加密算法套件
ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES'  # 使用高强度加密算法,禁用弱算法
ssl_prefer_server_ciphers = on           # 优先使用服务器指定的加密算法

2. 客户端认证配置

修改 pg_hba.conf 文件,配置不同来源的 SSL 连接要求:

txt
# 要求所有远程 IPv4 和 IPv6 连接使用 SSL 加密
hostssl all             all             0.0.0.0/0               md5
hostssl all             all             ::/0                    md5

# 仅允许本地连接使用非 SSL 方式
local   all             all                                     peer
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5

# 要求特定网段的客户端提供有效的 SSL 证书
# 这是双向 SSL 认证配置
hostssl all             all             192.168.1.0/24          cert clientcert=1

3. 重启数据库使配置生效

bash
# 重启 PostgreSQL 服务,使 SSL 配置生效
sudo systemctl restart postgresql

客户端 SSL/TLS 配置

客户端连接 PostgreSQL 服务器时,需要根据服务器的 SSL 配置选择合适的连接方式和验证级别。

1. psql 客户端配置

psql 是 PostgreSQL 自带的命令行客户端,支持多种 SSL 连接模式:

bash
# 基本 SSL 连接:要求使用 SSL,但不验证证书
psql "host=postgres-server port=5432 dbname=mydb user=myuser sslmode=require"

# 验证服务器证书:确保连接到的是受信任的服务器
psql "host=postgres-server port=5432 dbname=mydb user=myuser sslmode=verify-ca sslrootcert=root.crt"

# 验证服务器主机名:确保连接到的是正确的服务器,防止中间人攻击
psql "host=postgres-server port=5432 dbname=mydb user=myuser sslmode=verify-full sslrootcert=root.crt"

# 使用客户端证书:双向 SSL 认证,服务器也验证客户端身份
psql "host=postgres-server port=5432 dbname=mydb user=myuser sslmode=verify-full sslrootcert=root.crt sslcert=client.crt sslkey=client.key"

2. 应用程序配置

不同编程语言的 PostgreSQL 客户端库都支持 SSL 连接配置,以下是常见语言的配置示例:

Python (psycopg2)

Python 的 psycopg2 库是 PostgreSQL 最常用的客户端库之一:

python
import psycopg2

# 配置 SSL 连接参数
conn = psycopg2.connect(
    host="postgres-server",
    port=5432,
    dbname="mydb",
    user="myuser",
    password="mypassword",
    sslmode="verify-full",  # 使用最高级别的 SSL 验证
    sslrootcert="root.crt",  # 根证书路径
    sslcert="client.crt",    # 客户端证书路径
    sslkey="client.key"      # 客户端私钥路径
)

# 使用连接执行查询
with conn.cursor() as cur:
    cur.execute("SELECT 1;")
    result = cur.fetchone()
    print(result)

Java (JDBC)

Java 应用程序使用 PostgreSQL JDBC 驱动连接数据库:

java
// 配置 SSL 连接 URL
String url = "jdbc:postgresql://postgres-server:5432/mydb?" +
             "sslmode=verify-full&" +
             "sslrootcert=root.crt&" +
             "sslcert=client.crt&" +
             "sslkey=client.key";

// 建立数据库连接
Connection conn = DriverManager.getConnection(url, "myuser", "mypassword");

// 使用连接执行查询
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1;");
while (rs.next()) {
    System.out.println(rs.getInt(1));
}

Node.js (pg)

Node.js 应用程序使用 pg 模块连接 PostgreSQL:

javascript
const fs = require('fs');
const { Client } = require('pg');

// 创建客户端实例,配置 SSL 参数
const client = new Client({
  host: 'postgres-server',
  port: 5432,
  database: 'mydb',
  user: 'myuser',
  password: 'mypassword',
  ssl: {
    rejectUnauthorized: true,  // 拒绝未授权的服务器证书
    ca: fs.readFileSync('root.crt').toString(),  // 根证书
    cert: fs.readFileSync('client.crt').toString(),  // 客户端证书
    key: fs.readFileSync('client.key').toString()    // 客户端私钥
  }
});

// 连接数据库
client.connect()
  .then(() => {
    // 执行查询
    return client.query('SELECT 1;');
  })
  .then(result => {
    console.log(result.rows);
  })
  .catch(err => {
    console.error('连接失败:', err);
  })
  .finally(() => {
    // 关闭连接
    client.end();
  });

SSL/TLS 验证方法

sslmode描述安全性
disable禁用 SSL最低
allow尝试使用 SSL,失败则降级
prefer优先使用 SSL,失败则降级
require要求使用 SSL,但不验证证书
verify-ca要求使用 SSL,并验证 CA 证书
verify-full要求使用 SSL,验证 CA 证书和主机名最高

SSL/TLS 性能优化

1. 证书优化

bash
# 使用 ECDSA 证书(比 RSA 更高效)
openssl ecparam -genkey -name prime256v1 -out server.key
openssl req -new -key server.key -out server.csr -subj "/CN=postgres-server"
openssl x509 -req -in server.csr -CA root.crt -CAkey root.key -CAcreateserial -out server.crt -days 3650

2. 配置优化

修改 postgresql.conf 文件:

txt
# 使用更高效的密码套件
ssl_ciphers = 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'

# 启用 SSL 会话缓存
ssl_session_cache = 'shared:SSL:10m'  # 共享缓存,大小 10MB
ssl_session_timeout = 300s  # 会话超时时间

3. 硬件加速

bash
# 检查是否支持硬件加速
grep -i aes /proc/cpuinfo

# 检查 OpenSSL 是否支持硬件加速
openssl engine -t -c

SSL/TLS 安全最佳实践

1. 证书管理

bash
# 定期轮换证书
# 提前 30 天生成新证书
openssl req -new -key server.key -out server.csr -subj "/CN=postgres-server"
openssl x509 -req -in server.csr -CA root.crt -CAkey root.key -CAcreateserial -out server.crt -days 3650

# 监控证书过期
openssl x509 -enddate -noout -in server.crt

2. 安全配置

txt
# 禁用旧版本协议
ssl_min_protocol_version = 'TLSv1.2'

# 禁用弱密码套件
ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES:!RC4:!CAMELLIA:!SEED'

# 启用严格的证书验证
ssl_verify_client_cert = on

3. 访问控制

txt
# 结合防火墙使用
hostssl all             all             192.168.1.0/24          md5
hostssl all             all             10.0.0.0/8              md5
hostssl all             all             0.0.0.0/0               reject

SSL/TLS 验证

1. 服务器端验证

bash
# 检查 PostgreSQL 是否启用 SSL
psql -h postgres-server -p 5432 -U postgres -c "SHOW ssl;"

# 查看 SSL 配置
psql -h postgres-server -p 5432 -U postgres -c "SHOW ssl_cert_file;"
psql -h postgres-server -p 5432 -U postgres -c "SHOW ssl_key_file;"

# 查看连接的 SSL 状态
psql -h postgres-server -p 5432 -U postgres -c "\conninfo"

2. 客户端验证

bash
# 检查证书有效性
openssl verify -CAfile root.crt server.crt

# 查看证书详情
openssl x509 -in server.crt -text -noout

# 测试 SSL 连接
openssl s_client -connect postgres-server:5432 -state -debug

常见问题(FAQ)

Q1:如何确认 PostgreSQL 是否启用了 SSL?

A1:

sql
-- 方法1:查看 SSL 设置
SHOW ssl;

-- 方法2:查看连接信息
\conninfo

-- 方法3:从客户端检查
psql -h postgres-server -U postgres -c "SHOW ssl;"

Q2:SSL 连接失败,如何排查?

A2:

  1. 检查 PostgreSQL 日志:tail -f /var/log/postgresql/postgresql-15-main.log
  2. 验证证书文件权限:ls -l /var/lib/postgresql/15/main/ssl/
  3. 测试 SSL 连接:openssl s_client -connect postgres-server:5432
  4. 检查 pg_hba.conf 配置:确保使用了 hostssl 而不是 host
  5. 检查防火墙设置:确保 5432 端口已开放

Q3:如何强制所有连接使用 SSL?

A3:

  1. 修改 pg_hba.conf,仅允许 hostssl 连接
  2. 在应用程序中设置 sslmode=require 或更高
  3. 考虑禁用本地非 SSL 连接(根据安全需求)

Q4:SSL 对性能有影响吗?

A4:SSL 会带来一定的性能开销(通常 5-15%),但可以通过以下方式优化:

  • 使用 ECDSA 证书
  • 启用 SSL 会话缓存
  • 使用高效的密码套件
  • 利用硬件加速

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

A5:

  1. 生成客户端证书:
    bash
    openssl genrsa -out client.key 2048
    openssl req -new -key client.key -out client.csr -subj "/CN=myuser"
    openssl x509 -req -in client.csr -CA root.crt -CAkey root.key -CAcreateserial -out client.crt -days 3650
  2. 修改 pg_hba.conf:
    txt
    hostssl all             all             192.168.1.0/24          cert clientcert=1
  3. 客户端连接时提供证书:
    bash
    psql "host=postgres-server dbname=mydb user=myuser sslmode=verify-full sslrootcert=root.crt sslcert=client.crt sslkey=client.key"

Q6:如何使用 Let's Encrypt 证书配置 PostgreSQL?

A6:

  1. 安装 Certbot 并获取证书
  2. 复制证书到 PostgreSQL 目录
  3. 修改 postgresql.conf 配置 SSL 参数
  4. 修改 pg_hba.conf 要求 SSL 连接
  5. 重启 PostgreSQL 服务

Q7:SSL 证书过期了怎么办?

A7:

  1. 生成新证书(使用相同的 CN 和配置)
  2. 替换旧证书文件
  3. 重启 PostgreSQL 服务
  4. 更新所有客户端的根证书(如果使用自签名证书)