为什么在 Java 中尝试连接到 RDS PostgreSQL 数据库时出现 SocketTimeoutException?

Why do I get a SocketTimeoutException when trying to connect to a RDS PostgreSQL DB in Java?

我有一个 Spring 应用程序,我想在 AWS 上托管,我已经为配置苦苦挣扎了几天。

我有一个 EC2 实例,并且能够使用 SSH 连接到它。我还在 AWS 中设置了一个 Postgres RDS 数据库,但是我无法使用我 IDE 中的代码连接到它,所以我还没有将应用程序上传到 EC2 实例。

我认为问题出在我的安全组上,因为我的 application.properties 按照 AWS 文档和其他指南的建议出现。

我一直在努力了解安全组的来龙去脉,但过程很艰难。我认为在实际生产环境中准确使用我的 SG 非常重要,但我只是尝试将此应用程序用作演示。

任何允许连接到 RDS 数据库的松散配置现在都适合我。

application.properties

spring.datasource.url=jdbc:postgresql://myEndpoint:myPort/myAppName
spring.datasource.username=myDbUsername
spring.datasource.password=myDbPassword
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgresPlusDialect
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
spring.session.jdbc.initialize-schema=always
spring.session.store-type=jdbc
spring.session.jdbc.table-name=spring_session
server.servlet.session.timeout=30m

我尝试了多种 SG 配置,这里有 2 个例子:


RDS 配置 1:

Public accessibility: Yes
VPC Security Groups: launch-wizard-1 (sg-id-1) / Active

sg-id-1

Inbound rules:
rule 1 -- IP version: IPv4, Type: SSH, Protocol: TCP, Port range: MySSHPort, Source: 0.0.0.0/0
rule 2 -- IP version: IPv4, Type: Custom TCP, Protocol: TCP, Port range: MyLocalPort, Source: 0.0.0.0/0

Outbound rules:
rule 1 -- IP version: IPv4, Type: All traffic, Protocol: All, Port range: All, Destination: 0.0.0.0/0

RDS 配置 2:

Public accessibility: Yes
VPC Security Groups: default (sg-id-2) / Active

sg-id-2

Inbound rules:
rule 1 -- Type: PostgreSQL, Protocol: TCP, Port range: 5432, Source: sg-id
rule 2 -- Type: All traffic, Protocol: All, Port range: All, Source: sg-id

Outbound rules:
rule 1 -- IP version: IPv4, Type: All traffic, Protocol: All, Port range: All, Destination: 0.0.0.0/0

当我尝试连接 RDS 上设置的任一安全组时,连接超时并显示 SocketTimeoutException

这是什么原因造成的?


编辑:它终于连接上了。最终允许访问的安全组配置为:

Inbound rules:
rule 1 -- Type: PostgreSQL, Protocol: TCP, Port range: 5432, Source: 0.0.0.0/0

Outbound rules:
N/A

我还向 Internet 网关添加了一个子网路由 table,我认为这是必要的,尽管它最初不允许访问,因为 SG 入站规则上的源仍然不正确。

A SocketTimeoutException 表示您的应用程序无法从端点(在本例中是数据库)获得响应。

一定是您的 RDS 配置有问题,您可以检查以下几点。


1.安全组 (SG) 入站和出站规则

就您的 SG 配置而言,安全组是有状态的。

这意味着如果您创建允许流量进入的入站规则,则无论任何出站规则如何,都会自动允许该流量退出。

因此,public PostgreSQL RDS 数据库的最佳配置为:

Inbound rules:
rule 1 -- Type: PostgreSQL, Protocol: TCP, Port range: 5432, Source: 0.0.0.0/0

Outbound rules:
N/A

如果您的入站规则不允许 PostgreSQL 流量通过,您的请求将永远不会到达数据库 - 安全组在实例级别应用。


2。 “Public 辅助功能”RDS 属性

如果安全组设置正确,请仔细检查 RDS 实例在“网络与安全”中的“Public 可访问性”属性是否设置为“是”。

这将为 RDS 实例分配一个 public IP 地址用于外部访问,public IP 地址是 public 数据库的要求。


3.子网类型

如果你的 SGS 没问题并且你的数据库有 public IP 但你没有 Internet Gateway,就好像你买了宽带连接到互联网但是你的网络电缆已拔掉(缺少互联网网关)。

为了使 RDS 实例可以public访问,您还需要在数据库的子网中创建一个 Internet Gateway。创建后,您需要将 Internet 绑定的流量定向到 Internet 网关。

为此,请设置子网的路由 table 以将前往 0.0.0.0/0(互联网绑定 IPv4 流量作为目的地)的所有数据路由到互联网网关 ID(目标)。

这将使您的子网 public,因为该子网现在与路由 table 相关联,该路由具有到互联网网关的路由。

public 子网是 public 数据库的另一个要求,因为这将确保您的 VPC 和互联网之间可以进行通信。

没有 Internet 网关的 私有 子网将不允许外部访问。


4. DNS 主机名和 DNS 解析 VPC 属性

如果您仍然无法访问您的数据库public盟友,请确保 DNS hostnames & DNS resolution VPC attributes are enabled RDS 实例所在的 VPC。


5.网络 ACL

检查您是否没有创建任何处于默认状态的network ACLs或与子网关联的具有阻止规则的NACL。

默认创建的 NACL 像防火墙一样阻止所有入站和出站流量,无论安全组设置如何,除非您添加明确允许它们的规则。

您的 VPC 将附带一个默认 NACL,它允许所有入站和出站 IPv4 流量 - 使用那个。


6.身份验证

确保您的用户名和密码/IAM 身份验证令牌/Kerberos 凭据 100% 正确。


以上是一个非常全面的列表,希望其中一个建议允许您从外部连接到数据库并排除您的 Java 代码不正确。

然后您可以将 RDS 实例设为私有,仅接受来自您的 EC2 实例安全组的流量,并从您的子网中删除互联网网关以将其设为私有,applying the security at all layers 安全原则AWS 架构完善的框架中的支柱。