背景:
我有一个具有 2 个私有子网的自定义 VPC,其中包含一个位于美国西部 2 区域内的 Postgres RDS 实例,以及一个包含美国西部 2 区域内 EC2 实例的公有子网。
专用子网ACL:
RDS 实例安全组:
公有子网 ACL:
公共子网在其路由表中有一个互联网网关
EC2实例安全组:
在SSH进入EC2实例后,我导出与RDS实例的Postgres凭据关联的环境变量(例如PGDATABASE=testdb,PGUSER=foo_user,PGHOST=identifier.cluster-foo.us-west-2.RDS.amazonaws.com,PGPASSWORD=bar),并使用python版本3.7.10运行以下python脚本:
import psycopg2
try:
conn = psycopg2.connect(connect_timeout=10)
cur = conn.cursor()
cur.execute("""SELECT now()""")
query_results = cur.fetchall()
print(query_results)
except Exception as e:
print("Database connection failed due to {}".format(e))
我收到以下超时错误:
Database connection failed due to connection to server at "foo-endpoint" (10.0.102.128), port 5432 failed: timeout expired
connection to server at "foo-endpoint (10.0.101.194), port 5432 failed: timeout expired
您是否检查过 VPC 的 DNS 主机名是否已启用?这更可能是由于无法解析同一子网中的 DNS(知道 RDS 的安全组欢迎来自任何地方的 Postgres 流量)。
除此之外,我还建议将 EC2 的安全组列入 RDS 安全组的安全组,即 Postgres 的端口。您可以看下图:
通常,网络访问控制列表(NACL)应保留其默认“允许所有入站”
NACL是有状态的,这意味着它们需要允许双向流量。这与安全组不同,后者是无状态的,允许返回流量发出以响应允许的入站流量。安全组可以配置为零出站规则,但仍允许用户连接到资源并接收响应。
您的场景的正确安全配置应该是:
EC2-SG
) 上的安全组,允许从您的 IP 地址进行入站 SSH 访问(端口 22)DB-SG
) 上的一个安全组,它允许从 EC2-SG
进行入站后显式登录 (端口 5432)也就是说,DB-SG
应该特别引用允许入站访问的EC2-SG
。这是最安全的配置,因为数据库只能从与EC2-SG
关联的EC2实例访问。如果该实例被替换为另一个EC2实例,如果它与EC2-SG
关联,它仍然能够连接。
请注意,EC2-SG不需要安全组中的任何出站规则,因为它可以自动响应任何入站请求。但是,通常建议保留默认出站规则,以便实例上运行的软件可以访问Internet(例如,安装psycopg2库)。由于您自己安装了该软件,因此通常可以信任实例具有对Internet的出站访问权限。