你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

将具有 TLS 安全性的客户端连接到数据库

客户端应用程序和数据库服务器之间的连接始终将加密与行业标准传输层安全性(TLS)配合使用,以前称为安全套接字层(SSL)。

注释

开源 PostgreSQL 在其命令、变量和文档中使用旧名称 SSL,以避免中断现有实现。 本文使用首字母缩略词 TLS,而在命令名称和变量中使用 SSL。

Azure Database for PostgreSQL 支持使用 TLS 1.2 和 1.3 的加密连接。 服务器拒绝所有尝试使用 TLS 1.0 和 TLS 1.1 加密流量的传入连接。

默认情况下,服务器在客户端和服务器之间强制实施安全连接。 若要禁用此强制,并允许加密和未加密的客户端通信,请将服务器参数 require_secure_transport 更改为 OFF。 还可以通过设置服务器参数来设置 ssl_max_protocol_version TLS 版本。 请勿禁用 Tls。

重要

Microsoft为 Azure Database for PostgreSQL 启动 TLS 证书轮换 ,以更新中间 CA 证书和生成的证书链。 根 CA 保持不变。

如果客户端 配置使用 TLS 的建议配置,则无需执行任何作。

证书轮换计划

  • Azure 区域美国中西部、东亚和英国南部于 2025 年 11 月 11 日开始其 TLS 证书轮换。
  • 从 2026 年 1 月 19 日开始,此证书轮换计划扩展到包括 Azure 政府在内的其余(中国除外)区域。
  • 2026年春节(春节)后,中国地区还将进行证书轮换,其中包括 对其中一种根 CA 的更改

客户端 TLS 配置

默认情况下,PostgreSQL 不会验证服务器证书。 由于此默认行为,客户端无法检测服务器标识是否被欺骗(例如,如果有人修改 DNS 记录或接管服务器 IP 地址)。 若要防止此类欺骗,请对客户端启用 TLS 证书验证。

可以为客户端的 TLS 设置配置许多连接参数。 一些重要事项包括:

  • ssl:使用 TLS 进行连接。 此属性不需要值。 它的存在表明是 TLS 连接。 为了与将来的版本兼容,请使用值 true。 在此模式下,建立 TLS 连接时,客户端驱动程序会验证服务器的标识,以防止中间人攻击。

  • sslmode:如果需要加密,并且希望连接无法加密时失败,请将此参数设置为 require。 此设置可确保服务器配置为接受此主机或 IP 地址的 TLS 连接,并且服务器能够识别客户端证书。 如果服务器不接受 TLS 连接或无法识别客户端证书,则连接将失败。 下表列出了此设置的值:

    sslmode Explanation
    disable 不使用加密。 Azure Database for PostgreSQL 需要 TLS 连接,因此不要使用此设置。
    allow 如果服务器设置需要或强制执行加密,则使用加密。 Azure Database for PostgreSQL 需要 TLS 连接,因此此设置等效于 prefer
    prefer 如果服务器设置允许加密,则使用加密。 Azure Database for PostgreSQL 需要 TLS 连接。
    require 使用加密。 它确保服务器配置为接受 TLS 连接。
    verify-ca 使用加密。 使用客户端上存储的受信任根证书验证服务器证书。
    verify-full 使用加密。 将服务器证书与存储在客户端上的证书进行验证。 它还会验证服务器证书是否使用与连接相同的主机名。 除非专用 DNS 解析程序使用不同的名称来引用 Azure Database for PostgreSQL 服务器,否则请使用此设置。

默认sslmode模式在基于libpq的客户端(例如PSQLJDBC)之间有所不同。 基于 libpq 的客户端默认为 preferJDBC 客户端默认为 verify-full.

  • sslcertsslkeysslrootcert:这些参数替代客户端证书的默认位置、PKCS-8 客户端密钥和根证书。 它们默认分别位于 /defaultdir/postgresql.crt/defaultdir/postgresql.pk8/defaultdir/root.crt,其中在 Linux 系统中为 defaultdir,在 Windows 中为 ${user.home}/.postgresql/

重要

在使用 sslmode=verify-full 设置和用于交叉签名中间证书的根 CA 证书时,某些 Postgres 客户端库可能无法连接。 此配置会导致替代信任路径。 在这种情况下,显式指定 sslrootcert 参数。 或者,将 PGSSLROOTCERT 环境变量设置为本地路径,其中将Microsoft RSA 根 CA 2017 根 CA 证书放置在默认值中 %APPDATA%\postgresql\root.crt

安装受信任的根证书颁发机构(CA)

下载并转换根 CA 证书

对于使用系统证书存储来信任根证书的 Windows 客户端,无需采取任何操作,因为 Windows 会通过 Windows 更新来部署新的根 CA 证书。

对于 Java 客户端、VS Code 扩展和其他不使用系统存储的客户端(例如 PSQLPerl),以及 Linux 上的客户端:需要下载根 CA 证书并将其合并到 PEM 文件中。 至少应包含以下根 CA 证书:

注释

对于中国区域和具有轮换扩展的客户: Digicert Global Root CA(pem 文件) 仍然有效:将其包含在合并的 PEM 文件中。

如果对 Azure Database for PostgreSQL 使用的根 CA 进行了更改,请包括所有 Azure 根 CA 证书,以减少将来对合并文件更新的需求。 可以在 Azure 证书颁发机构详细信息中找到 Azure 根 CA 证书的列表。

若要将证书导入客户端证书存储,可能需要将任何 CRT 格式证书转换为 PEM 格式,并将 PEM 文件连接成单个文件。 可以使用 OpenSSL X509 实用工具 将 CRT 文件转换为 PEM。

openssl x509 -inform DER -in certificate-filename.crt -out certificate-filename.pem -outform PEM

将根 CA 证书合并到单个 PEM 文件中

对于某些客户端,可以使用任何文本编辑器或命令行工具将所有 PEM 文件连接到单个文件中。

-----BEGIN CERTIFICATE-----
(Root CA1 content: DigiCertGlobalRootG2.crt.pem)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Root CA2 content: Microsoft ECC Root Certificate Authority 2017.crt.pem)
-----END CERTIFICATE-----

对于中国区域和具有轮换扩展的客户:

-----BEGIN CERTIFICATE-----
(Root CA0 content: DigiCertGlobalRootCA.crt.pem)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Root CA1 content: DigiCertGlobalRootG2.crt.pem)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Root CA2 content: Microsoft ECC Root Certificate Authority 2017.crt.pem)
-----END CERTIFICATE-----

合并和更新 Java 应用程序的根 CA 证书

自定义 Java 应用程序使用名为 cacerts的默认密钥存储,其中包含受信任的证书颁发机构 (CA) 证书。 cacerts证书文件驻留在安全属性目录中java.home\lib\security,其中java.home运行时环境目录(jreSDK 中的目录或 Java™ 2 运行时环境的顶级目录)。 若要使用 PostgreSQL 更新客户端证书固定方案的客户端根 CA 证书,请使用以下说明:

  1. cacerts检查 Java 密钥存储,查看它是否已包含所需的证书。 可以使用以下命令列出 Java 密钥存储中的证书:

    keytool -list -v -keystore ..\lib\security\cacerts > outputfile.txt
    

    如果客户端的 Java 密钥存储中不存在必要的证书,您可以在输出中进行检查,请按照以下说明继续操作:

  2. 创建自定义密钥存储的备份副本。

  3. 下载证书文件,并将其保存在本地,可在其中引用它们。

  4. 生成包含所有所需根 CA 证书的组合 CA 证书存储。 以下示例演示如何为 PostgreSQL Java 用户使用 DefaultJavaSSLFactory。

    keytool -importcert -alias PostgreSQLServerCACert  -file "DigiCertGlobalRootG2.crt.pem" -keystore truststore -storepass password -noprompt
    
    keytool -importcert -alias PostgreSQLServerCACert2  -file "Microsoft ECC Root Certificate Authority 2017.crt.pem" -keystore truststore -storepass password  -noprompt
    
    ...
    

更新 Azure 应用服务中的根 CA 证书

对于连接到 Azure Database for PostgreSQL 灵活服务器实例的 Azure 应用服务,存在两种更新客户端证书的可能方案。 方案取决于将 SSL 与部署到 Azure 应用服务的应用程序配合使用的方式。

  • 在 Azure Database for PostgreSQL 灵活服务器实例中发生更改之前,在平台级别将新证书添加到应用服务。 如果在应用程序中使用应用服务平台中包含的 SSL 证书,则无需执行任何作。 有关详细信息,请参阅 Azure 应用服务文档中的 Azure 应用服务中的“添加和管理 TLS/SSL 证书 ”。
  • 如果在代码中显式包含 SSL 证书文件的路径,则需要下载新证书并更新代码以使用它。

在使用 Azure Kubernetes 服务的客户端时更新根 CA 证书。

如果尝试使用 Azure Kubernetes 服务(AKS)中托管的应用程序连接到 Azure Database for PostgreSQL,则它类似于从专用客户的主机环境进行访问。 请参阅 AKS 文档中的详细说明

更新 Windows 上 .NET (Npgsql)用户的根 CA 证书

对于连接到 Azure Database for PostgreSQL 灵活服务器实例的 Windows 上的 .NET(Npgsql)用户,请确保 所有 根 CA 证书都包含在受信任的根证书颁发机构下的 Windows 证书存储中。 Azure 标准根 CA 列表由 Windows 更新维护。 如果未包含 建议的配置 中列出的任何证书,请导入缺少的证书。

如何将 TLS 与证书验证配合使用

某些将 PostgreSQL 用于其数据库服务的应用程序框架在安装过程中默认不启用 TLS。 Azure Database for PostgreSQL 实例强制实施 TLS 连接,但如果应用程序未针对 TLS 进行配置,则应用程序可能会失败。 请查阅应用程序文档,了解如何启用 TLS 连接。

使用 PSQL

以下示例演示如何使用 PSQL 命令行接口连接到服务器。 要使用sslmode=verify-fullsslmode=verify-ca连接字符串设置来强制 TLS 证书验证。 将本地证书文件路径传递给 sslrootcert 参数。

 psql "sslmode=verify-full sslrootcert=<path-of-pem-file> host=mydemoserver.postgres.database.azure.com dbname=postgres user=myadmin"

测试 TLS 连接

在尝试从客户端应用程序访问已启用 TLS 的服务器之前,请确保可以通过 PSQL 访问它。 如果建立了 TLS 连接,应会看到类似于以下示例的输出:

psql (14.5)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

还可以加载 sslinfo 扩展 ,然后调用 ssl_is_used() 该函数来确定是否正在使用 TLS。 如果连接使用 TLS,该函数将 t 返回。 否则,它将返回 f

以编程方式获取 Java 密钥存储中受信任的证书的列表

默认情况下,Java 将受信任的证书存储在位于 cacerts 客户端上的 Java 安装文件夹中的特殊文件中。 以下示例读取 cacerts 并将其加载到 KeyStore 对象中:

private KeyStore loadKeyStore() {
    String relativeCacertsPath = "/lib/security/cacerts".replace("/", File.separator);
    String filename = System.getProperty("java.home") + relativeCacertsPath;
    FileInputStream is = new FileInputStream(filename);
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    String password = "changeit";
    keystore.load(is, password.toCharArray());

    return keystore;
}

默认密码 cacertschangeit,但它在实际客户端上应有所不同。 管理员建议在 Java 安装后立即更改密码。 加载 KeyStore 对象后,可以使用 PKIXParameters 类读取存在的证书。

public void whenLoadingCacertsKeyStore_thenCertificatesArePresent() {
    KeyStore keyStore = loadKeyStore();
    PKIXParameters params = new PKIXParameters(keyStore);
    Set<TrustAnchor> trustAnchors = params.getTrustAnchors();
    List<Certificate> certificates = trustAnchors.stream()
      .map(TrustAnchor::getTrustedCert)
      .collect(Collectors.toList());

    assertFalse(certificates.isEmpty());
}