配置“DataSource”以使用 SSL/TLS 加密连接到 Digital Ocean 上的托管 Postgres 服务器

Configure a `DataSource` to connect to a managed Postgres server on Digital Ocean with SSL/TLS encryption

我正在尝试 managed database service on DigitalOcean.com, having created a Postgres instance

Digital Ocean 默认要求远程连接使用 SSL (actually TLS) 加密。

如何配置 JDBC DataSource 实现以提供与此类数据库服务器的连接?

此问题类似于 ,但添加了 SSL/TLS 加密和远程使用托管数据库的特定元素。

获得DataSource实施

通常是您的 JDBC driver provides an implementation of javax.sql.DataSource.

有关更多详细信息,请参阅 类似问题。

PGSimpleDataSource

如果使用来自 jdbc.postgresql.org, you can use the org.postgresql.ds.PGSimpleDataSource class 的 JDBC 驱动程序作为您的 DataSource 实现。

实例化 PGSimpleDataSource 类型的对象,然后调用 setter 方法以提供连接到数据库服务器所需的所有信息。 DigitalOcean 网站上的网页列出了您的特定数据库实例的所有这些信息。

基本上是这样的:

PGSimpleDataSource dataSource = new PGSimpleDataSource();

dataSource.setServerName( "your-server-address-goes-here" );
dataSource.setPortNumber( your-port-number-goes-here );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );

多个服务器名称和端口号

不幸的是,setServerNamesetPortNumber 方法的单数版本已弃用。虽然很烦人,但我们应该使用这些方法的复数形式(setServerNames & setPortNumbers),每个方法都接受一个数组。我们用我们的服务器地址填​​充一对单元素数组 String[]int[],并使用数组文字 port number

  • { “你的服务器地址在这里” }
  • { 这里是你的端口号 }
PGSimpleDataSource dataSource = new PGSimpleDataSource();

String[] serverAddresses = { "your-server-address-goes-here" };
dataSource.setServerNames( serverAddresses );
int[] serverPortNumbers = { your-port-number-goes-here };
dataSource.setPortNumbers( serverPortNumbers );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );

SSL/TLS加密

最后,我们需要为问题中提到的 SSL/TLS 加密添加信息。

具有讽刺意味的是,调用setSsl( true )

你会认为我们会调用 setSsl 方法并传递 true。但不是。虽然违反直觉,但将其设置为 true 会导致您的连接尝试失败。我不知道为什么会这样。但是反复试验让我避免了那个电话。

CA 证书

为了让您的客户端 Java 应用启动 SSL/TLS 连接,JDBC 驱动程序必须能够访问 CA 证书 由 Digital Ocean 使用。在您的 Digital Ocean 管理页面上,单击 Download CA certificate link 下载一个小文本文件。该文件将被命名为 ca-certificate.crt.

我们需要将该文件的文本作为字符串提供给我们的 JDBC 驱动程序。执行以下操作将文件加载到文本字符串中。

// Get CA certificate used in TLS connections.
Path path = Paths.get( "/Users/basilbourque/Downloads/ca-certificate.crt" );
String cert = null;
try
{
    cert = Files.readString( path , StandardCharsets.UTF_8 );
    System.out.println( "cert = " + cert );
}
catch ( IOException ex )
{
    throw new IllegalStateException( "Unable to load the TLS certificate needed to make database connections." );
}
Objects.requireNonNull( cert );
if ( cert.isEmpty() ) {throw new IllegalStateException( "Failed to load TLS cert." ); }

通过调用 DataSource::setSslCert. Note that we are not calling setSslRootCert 将该 CA 证书文本传递给您的 JDBC 驱动程序。不要混淆这两个名称相似的方法。

dataSource.setSslCert( cert );

正在测试连接

最后,我们可以使用配置好的DataSource对象来连接数据库。该代码将如下所示:

// Test connection
try (
        Connection conn = dataSource.getConnection() ;
        // …
)
{
    System.out.println( "DEBUG - Postgres connection made. " + Instant.now() );
    // …
}
catch ( SQLException e )
{
    e.printStackTrace();
}

完整的示例代码

把所有这些放在一起,看到这样的东西。

// Get CA certificate used in TLS connections.
Path path = Paths.get( "/Users/basilbourque/Downloads/ca-certificate.crt" );
String cert = null;
try
{
    cert = Files.readString( path , StandardCharsets.UTF_8 );
    System.out.println( "cert = " + cert );
}
catch ( IOException ex )
{
    throw new IllegalStateException( "Unable to load the TLS certificate needed to make database connections." );
}
Objects.requireNonNull( cert );
if ( cert.isEmpty() ) {throw new IllegalStateException( "Failed to load TLS cert." ); }

// PGSimpleDataSource configuration
PGSimpleDataSource dataSource = new PGSimpleDataSource();

String[] serverAddresses = { "your-server-address-goes-here" };
dataSource.setServerNames( serverAddresses );
int[] serverPortNumbers = { your-port-number-goes-here };
dataSource.setPortNumbers( serverPortNumbers );
dataSource.setSslCert( cert );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );

// Test connection
try (
Connection conn = dataSource.getConnection() ;
// …
)
{
System.out.println( "DEBUG - Postgres connection made. " + Instant.now() );
// …
}
catch ( SQLException e )
{
e.printStackTrace();
}

可信来源

在 DigitalOcean.com 上创建 Postgres 实例时,您将能够限制传入的连接请求。您可以指定 Postgres 服务器期望的单个 IP 地址,即 Digital Ocean 术语中的“可信来源”。任何试图连接到您的 Postgres 服务器的黑客都将被忽略,因为它们来自其他 IP 地址。

提示:在该 IP 地址编号的数据输入字段内单击,网页会自动检测并提供您的网络浏览器当前使用的 IP 地址。如果您 运行 您的 Java 代码来自同一台计算机,请使用相同的 IP 号码作为您的单一可信来源。

否则,输入计算机的 IP 地址 运行 您的 Java JDBC 代码。

其他问题

我没有详细说明,例如用于管理您的 CA 证书文件的适当安全协议,或者例如通过从 JNDI server rather than hard-coding 获取 DataSource 对象来外部化您的连接信息。但希望上面的示例可以帮助您入门。