启用 VPC 的 Lambda 函数无法在同一 VPC 中启动/访问 EC2

Posted

技术标签:

【中文标题】启用 VPC 的 Lambda 函数无法在同一 VPC 中启动/访问 EC2【英文标题】:VPC-enabled Lambda function cannot launch/access EC2 in the same VPC 【发布时间】:2019-12-31 20:58:00 【问题描述】:

我有一个启用 VPC 的 Lambda 函数,它尝试使用启动模板启动 EC2。 EC2 启动步骤 (run_instances) 失败并出现以下一般网络错误。

调用调用 API 操作失败并显示以下消息:网络错误

我可以直接从启动模板成功启动实例,所以我认为启动模板一切正常。我在启动模板中配置了以下内容

亚马逊机器映像 ID 实例类型 密钥对 我在使用特定(VPC、子网、安全组)组合之前创建的网络接口 (ENI)。 IAM 角色

Lambda 函数包含以下代码-

import json
import boto3
import time

def lambda_handler(event, context):
    ec2_cl = boto3.client('ec2')
    launch_temp = "LaunchTemplateId": "<<Launch Template ID>>"
    resp_ec2_launch = ec2_cl.run_instances(MaxCount=1, MinCount=1, LaunchTemplate=launch_temp, SubnetId="<<Subnet ID>>")

关于 Lambda 函数的一些事情-

我在 run_instances() 调用中使用了子网,因为这不是默认的 vpc/子网。 使用启动模板中使用的相同(VPC、子网、安全组)组合设置该功能 执行角色设置为与启动模板中使用的 IAM 角色相同 您看到的功能只需要访问 EC2,不需要 Internet 访问 我将 run_instances() 替换为 describe_instance_status(使用直接从启动模板创建的实例 ID)并得到相同的错误。

该错误是网络错误,因此我假设一切都很好(至少到目前为止)授予 IAM 角色的权限。如果 IAM 角色错过了任何政策,我确信会有不同的错误。

有人可以指出我可能缺少什么吗?

【问题讨论】:

boto 需要公共互联网,因此如果您的 lambda 在私有 vpc 中,您需要一个 nat 网关。 @Lamanus- 感谢您的回复。我不知道 boto3 默认需要访问互联网。我的 Lambda 代码无法访问 Internet,因此假设不需要 Internet 访问。我将尝试为我的 Lambda 提供 Internet 访问。 【参考方案1】:

问题似乎在于您的 AWS Lambda 函数能够访问 Internet,因为 Amazon EC2 API 端点位于 Internet 上。

如果 Lambda 函数附加到 VPC,则它可以自动访问 Internet。

如果 Lambda 函数附加到 VPC 并且需要 Internet 访问权限,则配置应为:

仅将 Lambda 函数附加到私有子网 在公共子网中启动 NAT 网关 配置私有子网上的路由表以通过 NAT 网关发送 Internet 绑定流量 (0.0.0.0/0)

【讨论】:

感谢您的回复。正在启动的 EC2 在 VPC 内。你能告诉我为什么你说EC2 API端点在互联网上吗?我的理解是它在 VPC 内。 所有 AWS API 调用的端点都在 Internet 上(请参阅 AWS Service Endpoints - AWS General Reference)。这意味着,例如,可以从 Internet 上的任何位置请求启动 Amazon EC2 实例。这与启动实例的位置无关。如果您希望完全 VPC 内调用AWS,则需要VPC Endpoint。 谢谢。创建 EC2 VPC 终端节点后,是否应该将其包含在其他位置(启动模板或 run_instances API)?我创建了一个 EC2 VPC 端点并测试了 Lambda 函数,但它失败并出现相同的网络错误,因此出现了问题。我可能需要在某处提及 EC2 VPC 端点。【参考方案2】:

您的 VPC 似乎没有 Internet 网关,但它有一个用于 EC2 的 VPC 端点。

因此,为了尝试重现您的情况,我执行了以下操作:

创建了一个新的 VPC,只有一个子网,但没有 Internet 网关 向子网添加了 EC2 的 VPC 端点 创建了一个 Lambda 函数,它将调用 DescribeInstances()将 Lambda 函数附加到子网 在 VPC Endpoint 和 Lambda 函数上打开了安全组,以允许来自任何地方的所有流量(嘿,这只是一个测试!)

我的 Lambda 函数:

import json
import boto3

def lambda_handler(event, context):
    ec2 = boto3.client('ec2',region_name='ap-southeast-2')
    print(ec2.describe_instances())

结果: Lambda 函数成功收到来自 EC2 的响应,其中包含区域中的实例列表。无需代码或更改。

【讨论】:

感谢您抽出宝贵时间回复。我的 Lambda 需要访问 VPC 中的 EC2,所以我不明白为什么应该允许来自任何地方的流量。不对外开放就不能实现吗? 要进行run_instances() 调用,Lambda 函数需要能够访问 Internet 上的 EC2 Endpoint(不是在 VPC 中)。因此,它要么需要访问 Internet(通过 NAT 网关),要么需要通过 EC2 的 VPC 端点访问。

以上是关于启用 VPC 的 Lambda 函数无法在同一 VPC 中启动/访问 EC2的主要内容,如果未能解决你的问题,请参考以下文章

从 VPC 中的 Lambda 访问 AWS S3

AWS Lambda 无法调用没有 VPC 的另一个 AWS Lambda - NodeJs

从没有 VPC 的 Lambda 连接到公共 Redshift 数据库

允许 VPC 中的 Lambda 访问同一 VPC 中的 Elasticsearch 域

当 lambda 在 vpc 中时,无法从 lambda 运行 Fargate 任务

AWS Lambda + NAT 网关的替代方案