提问者:小点点

从VPC境内的Ec2实例连接到RDS实例


背景:

我有一个具有 2 个私有子网的自定义 VPC,其中包含一个位于美国西部 2 区域内的 Postgres RDS 实例,以及一个包含美国西部 2 区域内 EC2 实例的公有子网。

专用子网ACL:

    < li >允许端口5432上的所有入站IPv4流量

RDS 实例安全组:

    < li >允许端口5432上的所有入站IPv4流量

公有子网 ACL:

  • 允许所有端口上的所有入站/出站流量

公共子网在其路由表中有一个互联网网关

EC2实例安全组:

  • 允许来自端口22上本地IP的入站SSH流量
  • 允许端口5432、443和80上的所有IPv4出站流量

在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


共2个答案

匿名用户

您是否检查过 VPC 的 DNS 主机名是否已启用?这更可能是由于无法解析同一子网中的 DNS(知道 RDS 的安全组欢迎来自任何地方的 Postgres 流量)。

除此之外,我还建议将 EC2 的安全组列入 RDS 安全组的安全组,即 Postgres 的端口。您可以看下图:

匿名用户

通常,网络访问控制列表(NACL)应保留其默认“允许所有入站”

NACL是有状态的,这意味着它们需要允许双向流量。这与安全组不同,后者是无状态的,允许返回流量发出以响应允许的入站流量。安全组可以配置为零出站规则,但仍允许用户连接到资源并接收响应。

您的场景的正确安全配置应该是:

  • 亚马逊 EC2 实例 (EC2-SG) 上的安全组,允许从您的 IP 地址进行入站 SSH 访问(端口 22)
  • 亚马逊 RDS 数据库 (DB-SG) 上的一个安全组,它允许从 EC2-SG 进行入站后显式登录 (端口 5432)

也就是说,DB-SG应该特别引用允许入站访问的EC2-SG。这是最安全的配置,因为数据库只能从与EC2-SG关联的EC2实例访问。如果该实例被替换为另一个EC2实例,如果它与EC2-SG关联,它仍然能够连接。

请注意,EC2-SG不需要安全组中的任何出站规则,因为它可以自动响应任何入站请求。但是,通常建议保留默认出站规则,以便实例上运行的软件可以访问Internet(例如,安装psycopg2库)。由于您自己安装了该软件,因此通常可以信任实例具有对Internet的出站访问权限。