使用SSL/TLS配置保护PostgreSQL连接:完整指南
学习如何使用SSL/TLS加密保护PostgreSQL连接。本全面指南涵盖服务器端和客户端配置,包括生成证书、修改`postgresql.conf`和`pg_hba.conf`,以及设置客户端以实现安全的加密通信。保护传输中的敏感数据,确保符合现代安全标准。
使用SSL/TLS配置保护PostgreSQL连接:完整指南
PostgreSQL SSL/TLS配置包含两个独立任务。第一个是加密,防止网络上的其他人读取传输中的凭据或查询结果。第二个是身份验证,确保客户端连接的是真实的数据库服务器,而不是冒充它的机器。许多配置只完成了第一部分,却意外跳过了第二部分。
这种区别在实际部署中至关重要。sslmode=require会加密连接,但本身并不完全验证服务器主机名。sslmode=verify-full则会进行验证。如果你的应用程序通过公共网络、共享企业网络、你无法完全控制的Kubernetes覆盖网络或任何可能被拦截流量的环境进行连接,verify-full应该是目标。
理解PostgreSQL中的SSL/TLS
SSL/TLS(安全套接层/传输层安全)是一种加密协议,旨在为计算机网络上的通信提供安全性。当应用于PostgreSQL时,它会对数据库服务器和客户端之间交换的数据进行加密。这可以防止未经授权的方拦截和读取敏感信息,如凭据、财务数据或个人详细信息。
PostgreSQL客户端支持多种SSL模式:
sslmode=disable:仅使用普通未加密连接。sslmode=prefer:首先尝试TLS,如果TLS不可用,则回退到普通TCP。这很方便,但可能隐藏配置错误。sslmode=require:要求TLS加密,但不一定验证服务器主机名。sslmode=verify-ca:要求TLS并验证证书链到受信任的CA。sslmode=verify-full:要求TLS,验证CA,并验证主机名与证书匹配。
在服务器端,ssl = on仅表示PostgreSQL能够接受TLS连接。它并不强制每个客户端都使用TLS。强制执行在pg_hba.conf中通过hostssl规则以及避免使用允许相同用户和网络在不使用TLS的情况下连接的更宽泛的host规则来实现。
SSL/TLS配置的先决条件
在开始配置PostgreSQL的SSL/TLS之前,请确保你具备以下条件:
- 已安装OpenSSL:OpenSSL工具包对于生成和管理SSL证书至关重要。它通常预装在Linux和macOS系统上。对于Windows,你可能需要单独下载并安装它。
- 访问PostgreSQL配置文件:你需要管理员权限来修改
postgresql.conf和pg_hba.conf文件。 - 理解证书颁发机构(CA):虽然你可以为测试创建自签名证书,但生产环境最好使用由受信任的证书颁发机构(CA)或内部企业CA签名的证书。
服务器端SSL/TLS配置
服务器端配置包括启用SSL、指定SSL证书和密钥的位置,以及配置客户端身份验证。
1. 生成或获取SSL证书和密钥
为PostgreSQL服务器获取SSL证书主要有两种方式:
- 自签名证书(用于测试/开发):这些证书使用OpenSSL创建,默认情况下不被外部客户端信任。它们适用于初始设置和内部测试。
- 来自证书颁发机构(CA)的证书(用于生产):从受信任的公共CA(例如Let's Encrypt、DigiCert)或内部企业CA获取证书。这确保客户端可以验证服务器的身份。
使用OpenSSL创建自签名证书:
这是开发和内部环境的常见方法。在PostgreSQL服务器或安装了OpenSSL的机器上执行以下命令:
创建证书目录:保持证书组织有序是一个好习惯。
sudo mkdir -p /etc/postgresql/ssl sudo chown postgres:postgres /etc/postgresql/ssl cd /etc/postgresql/ssl生成服务器私钥:此密钥应保密。
sudo openssl genrsa -out server.key 2048创建服务器证书签名请求(CSR):其中包含有关服务器的信息。
sudo openssl req -new -key server.key -out server.csr使用客户端将连接的主机名,例如
db01.internal.example.com。现代客户端通常会检查主题备用名称(SAN),因此当你的CA流程支持时,请在证书请求中包含DNS名称。使用你自己的CA签署证书(用于内部使用):
- 创建根CA私钥和证书(如果你还没有):
# 生成CA私钥 sudo openssl genrsa -des3 -out root.key 2048 # 创建CA证书(有效期为3650天) sudo openssl req -new -x509 -days 3650 -key root.key -out root.crt - 使用CA签署服务器CSR:这将创建受信任的服务器证书。
sudo openssl x509 -req -days 365 -in server.csr -CA root.crt -CAkey root.key -set_serial 01 -out server.crt
- 创建根CA私钥和证书(如果你还没有):
设置权限:确保PostgreSQL用户可以读取这些文件。
sudo chown postgres:postgres server.key server.crt root.crt sudo chmod 600 server.key sudo chmod 644 server.crt root.crt
使用来自公共/企业CA的证书:
如果你从CA获取证书,通常会收到:
server.crt:你的服务器的公共证书。server.key:你的服务器的私钥。root.crt(或类似):CA的根证书(以及可能的中间证书)。
将这些文件放在安全目录中(例如/etc/postgresql/ssl/),并确保PostgreSQL用户具有读取权限。
2. 配置postgresql.conf
编辑你的postgresql.conf文件(通常位于PostgreSQL数据目录中)以启用SSL并指定证书文件。
#------------------------------------------------------------------------------
# SSL
#------------------------------------------------------------------------------
ssl = on
# 这些文件都是PEM格式,如果未配置服务器密钥/证书,则忽略它们。
# 默认情况下,这些文件应位于服务器的数据目录中。
# 或者,它们可以指定为完整路径。
ssl_cert_file = '/etc/postgresql/ssl/server.crt' # (如果需要,更改文件名)
ssl_key_file = '/etc/postgresql/ssl/server.key' # (如果需要,更改文件名)
ssl_ca_file = '/etc/postgresql/ssl/root.crt' # (可选,用于客户端证书验证)
# 可选:如果需要,指定密码套件
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
# 可选:启用客户端证书验证
#ssl_ca_file必须设置为包含要信任的CA证书的文件
#ssl_crl_file = ''
#ssl_crl_dir = ''
ssl = on:在服务器上启用SSL支持。ssl_cert_file:服务器公共证书的路径。ssl_key_file:服务器私钥的路径。ssl_ca_file:PostgreSQL在验证客户端证书时应信任的CA证书的路径。客户端使用自己的CA文件(例如sslrootcert)来验证服务器。
3. 配置pg_hba.conf以强制执行SSL
pg_hba.conf文件控制客户端身份验证。你需要修改条目以强制执行SSL连接。
默认情况下,pg_hba.conf中的条目如下所示:
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
# IPv4本地连接:
host all all 127.0.0.1/32 scram-sha-256
# IPv6本地连接:
host all all ::1/128 scram-sha-256
要强制执行SSL,请将host条目更改为hostssl:
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
# IPv4本地连接:
hostssl all all 127.0.0.1/32 scram-sha-256
# IPv6本地连接:
hostssl all all ::1/128 scram-sha-256
# 外部网络访问示例 - 需要SSL
hostssl all app_user 10.20.0.0/16 scram-sha-256
hostssl all app_user 2001:db8:20::/48 scram-sha-256
hostssl:此记录类型需要SSL连接。任何不使用SSL的连接尝试都将被拒绝。hostnossl:此记录类型明确禁止SSL连接。host:允许SSL和非SSL连接。如果在hostssl规则之前或代替它存在匹配的host规则,客户端可能仍然可以在没有TLS的情况下连接。
除非有充分理由并且有其他控制措施,否则避免发布0.0.0.0/0访问权限。大多数生产数据库应仅接受来自应用程序子网、堡垒主机、连接池或私有网络范围的连接。
4. 重启PostgreSQL服务器
修改postgresql.conf和pg_hba.conf后,必须重启PostgreSQL服务才能使更改生效。
# 对于使用systemd的系统(大多数现代Linux发行版)
sudo systemctl restart postgresql
# 对于使用init.d的系统
sudo service postgresql restart
客户端SSL/TLS配置
客户端也需要配置为安全连接。这涉及指定连接参数,可能提供客户端证书,以及验证服务器的证书。
1. 连接字符串参数
通过psql或任何PostgreSQL客户端库连接时,可以在连接字符串中或作为单独选项指定SSL参数。
基本SSL连接(仅服务器身份验证):
psql "sslmode=require host=your_server_hostname dbname=your_db user=your_user"
sslmode:控制客户端的SSL行为。disable:仅允许非SSL连接。allow:允许非SSL,但如果服务器支持,则首选SSL。prefer(默认):首选SSL,但如果SSL失败,则允许非SSL。require:仅允许SSL连接。如果服务器不支持SSL,则连接失败。verify-ca:仅允许SSL连接,并验证服务器证书是否由受信任的CA签名。必须设置sslrootcert参数。verify-full:仅允许SSL连接,验证服务器证书是否来自受信任的CA,并验证服务器主机名是否与证书的通用名称(CN)或主题备用名称(SAN)匹配。
验证服务器证书(verify-ca或verify-full):
为了增强安全性,客户端应验证服务器的身份。这要求客户端信任签署服务器证书的CA。
- 获取CA证书:获取用于签署服务器证书的
root.crt文件(或适当的CA证书)。 - 指定
sslrootcert:告诉客户端在哪里找到此CA证书。
psql "sslmode=verify-full host=your_server_hostname dbname=your_db user=your_user sslrootcert=/path/to/your/root.crt"
这是你应该从运行应用程序的同一主机或容器测试的连接字符串。一个常见的失败是psql在管理员笔记本电脑上工作,因为那里存在CA文件,而应用程序容器失败,因为从未挂载CA包。
2. 客户端证书(双向身份验证)
为了获得更高级别的安全性,你可以实现双向身份验证,其中服务器也使用客户端证书验证客户端的身份。
生成客户端证书:
与服务器证书类似,你需要一个客户端私钥和一个由服务器信任的CA(通常与服务器证书使用相同的CA)签署的客户端证书。
生成客户端私钥:
openssl genrsa -des3 -out client.key 2048创建客户端CSR:
openssl req -new -key client.key -out client.csr提供详细信息,确保通用名称对客户端是唯一的。
使用CA签署客户端CSR:
sudo openssl x509 -req -days 365 -in client.csr -CA root.crt -CAkey root.key -set_serial <unique_serial> -out client.crt设置权限:
chmod 600 client.key chmod 644 client.crt
配置pg_hba.conf以进行客户端证书身份验证:
在服务器上,你需要配置pg_hba.conf以接受客户端证书身份验证。这通常使用cert身份验证方法。
# TYPE DATABASE USER ADDRESS METHOD
# 要求SSL和客户端证书身份验证用于特定用户/数据库
hostssl all your_user your_client_ip/32 cert map=your_cert_map
如果你希望将特定的客户端证书详细信息(如Subject或SubjectAltName)映射到PostgreSQL用户,则可能还需要定义证书映射文件(cert_map选项)。有关详细的cert身份验证和证书映射设置,请参阅PostgreSQL文档。
配置客户端使用证书:
更新客户端的连接字符串以包含其证书和密钥的路径:
psql "sslmode=verify-full host=your_server_hostname dbname=your_db user=your_user \
sslrootcert=/path/to/your/root.crt sslcert=/path/to/your/client.crt sslkey=/path/to/your/client.key"
最佳实践和提示
- 使用
verify-fullsslmode:在客户端使用verify-full以减少中间人攻击风险。 - 保护私钥:确保私钥(
.key文件)具有严格的文件权限(例如chmod 600),并且仅服务器上的PostgreSQL用户和客户端上的连接用户可以读取。 - 定期续订证书:证书有到期日期。实施一个流程在它们到期前续订,以避免连接中断。
- 集中证书管理:对于较大规模的部署,考虑使用证书管理系统或自动化证书颁发和续订。
- 监控日志:检查PostgreSQL日志中启动或连接尝试期间的任何SSL相关错误。
- 文档:参考官方PostgreSQL文档,获取针对你的PostgreSQL版本的最新参数和高级配置选项。
快速验证清单
重启PostgreSQL后,检查服务器是否已启用TLS监听:
SHOW ssl;
SHOW ssl_cert_file;
SHOW ssl_key_file;
然后从客户端主机测试:
psql "host=your_server_hostname dbname=your_db user=your_user sslmode=verify-full sslrootcert=/path/to/root.crt"
在会话内部,确认连接已加密:
SELECT ssl, version, cipher
FROM pg_stat_ssl
WHERE pid = pg_backend_pid();
如果ssl为false,则你的pg_hba.conf规则并未按你预期的方式强制执行。如果verify-full失败但require有效,则证书可能缺少正确的主机名,客户端不信任CA,或者应用程序通过IP地址连接而证书是为DNS名称颁发的。
良好的PostgreSQL TLS设置不仅仅是ssl = on。它是一个链条:包含正确名称的证书、具有严格权限的私钥、实际强制执行TLS的hostssl规则,以及验证服务器而不仅仅是加密套接字的客户端。