VPC 中的 AWS Lambda 在 NAT 之后没有互联网访问权限

Posted

技术标签:

【中文标题】VPC 中的 AWS Lambda 在 NAT 之后没有互联网访问权限【英文标题】:AWS Lambda in VPC doesn't have internet access behind NAT 【发布时间】:2017-07-20 12:29:56 【问题描述】:

我的问题是,我在带有 IGW 的 VPC 内的 NAT 后面运行的 Lambda 函数无法访问 Internet 上的任何内容。

我要做的是创建一个 VPC,它具有:

互联网网关; 2 个私有子网(PrivateAPrivateB)分别位于可用区 AB; 1 个公共子网 (PublicA) 在可用区 A PublicA 子网中的 NAT 网关 PrivateAPrivateB 有一个路由表,将 0.0.0.0/0 路由到 NAT 网关。 PublicA 有一个路由表,将 0.0.0.0/0 路由到 Internet 网关。 私有子网和公共子网都具有允许所有入口和出口流量的访问控制列表。

那部分很有效。

接下来,我想在 VPC 中创建一个 Lambda 函数。我将它放入PrivateAPrivateB 并为其分配一个允许所有出口和入口流量的安全组。

以下是重现该问题的独立示例(整个模板)。我已经阅读了 Internet 上所有可能的文档和文章,因此如果有人能指出我正确的方向,我将不胜感激。


  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": 

    "Vpc": 
      "Type": "AWS::EC2::VPC",
      "Properties": 
        "CidrBlock": "10.0.0.0/16",
        "EnableDnsSupport": true,
        "EnableDnsHostnames": true,
        "InstanceTenancy": "default"
      
    ,

    "InternetGateway": 
      "Type": "AWS::EC2::InternetGateway"
    ,

    "VpcGatewayAttachment": 
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": 
        "VpcId":  "Ref": "Vpc" ,
        "InternetGatewayId":  "Ref": "InternetGateway" 
      
    ,

    "ElasticIP":
      "Type": "AWS::EC2::EIP",
      "Properties": 
        "Domain": "vpc"
      
    ,

    "NatGateway": 
      "Type": "AWS::EC2::NatGateway",
      "DependsOn": [ "VpcGatewayAttachment" ],
      "Properties": 
        "AllocationId":  "Fn::GetAtt": [ "ElasticIP", "AllocationId" ] ,
        "SubnetId":  "Ref": "SubnetAPublic" 
      
    ,

    "SubnetAPublic": 
      "Type": "AWS::EC2::Subnet",
      "Properties": 
        "AvailabilityZone":  "Fn::Select" : [ "0",  "Fn::GetAZs" : ""  ] ,
        "CidrBlock": "10.0.0.0/19",
        "MapPublicIpOnLaunch": true,
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "SubnetAPrivate": 
      "Type": "AWS::EC2::Subnet",
      "Properties": 
        "AvailabilityZone":  "Fn::Select" : [ "0",  "Fn::GetAZs" : ""  ] ,
        "CidrBlock": "10.0.64.0/19",
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "SubnetBPrivate": 
      "Type": "AWS::EC2::Subnet",
      "Properties": 
        "AvailabilityZone":  "Fn::Select" : [ "1",  "Fn::GetAZs" : ""  ] ,
        "CidrBlock": "10.0.96.0/19",
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "RouteTablePublic": 
      "Type": "AWS::EC2::RouteTable",
      "Properties": 
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "RouteTablePrivate": 
      "Type": "AWS::EC2::RouteTable",
      "Properties": 
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "RouteTableAssociationAPublic": 
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": 
        "SubnetId":  "Ref": "SubnetAPublic" ,
        "RouteTableId":  "Ref": "RouteTablePublic" 
      
    ,

    "RouteTableAssociationAPrivate": 
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": 
        "SubnetId":  "Ref": "SubnetAPrivate" ,
        "RouteTableId":  "Ref": "RouteTablePrivate" 
      
    ,

    "RouteTableAssociationBPrivate": 
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": 
        "SubnetId":  "Ref": "SubnetBPrivate" ,
        "RouteTableId":  "Ref": "RouteTablePrivate" 
      
    ,

    "RouteTablePrivateInternetRoute": 
      "Type": "AWS::EC2::Route",
      "DependsOn": [ "VpcGatewayAttachment" ],
      "Properties": 
        "RouteTableId":  "Ref": "RouteTablePrivate" ,
        "DestinationCidrBlock": "0.0.0.0/0",
        "NatGatewayId":  "Ref": "NatGateway" 
      
    ,

    "RouteTablePublicInternetRoute": 
      "Type": "AWS::EC2::Route",
      "DependsOn": [ "VpcGatewayAttachment" ],
      "Properties": 
        "RouteTableId":  "Ref": "RouteTablePublic" ,
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId":  "Ref": "InternetGateway" 
      
    ,

    "NetworkAclPublic": 
      "Type": "AWS::EC2::NetworkAcl",
      "Properties": 
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "NetworkAclPrivate": 
      "Type": "AWS::EC2::NetworkAcl",
      "Properties": 
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "SubnetNetworkAclAssociationAPublic": 
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties":
        "SubnetId":  "Ref": "SubnetAPublic" ,
        "NetworkAclId":  "Ref": "NetworkAclPublic" 
      
    ,

    "SubnetNetworkAclAssociationAPrivate": 
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties":
        "SubnetId":  "Ref": "SubnetAPrivate" ,
        "NetworkAclId":  "Ref": "NetworkAclPrivate" 
      
    ,

    "SubnetNetworkAclAssociationBPrivate": 
      "Type": "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties": 
        "SubnetId":  "Ref": "SubnetBPrivate" ,
        "NetworkAclId":  "Ref": "NetworkAclPrivate" 
      
    ,

    "NetworkAclEntryInPublicAllowAll": 
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": 
        "NetworkAclId":  "Ref": "NetworkAclPublic" ,
        "RuleNumber": 99,
        "Protocol": -1,
        "RuleAction": "allow",
        "Egress": false,
        "CidrBlock": "0.0.0.0/0"
      
    ,

    "NetworkAclEntryOutPublicAllowAll": 
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": 
        "NetworkAclId":  "Ref": "NetworkAclPublic" ,
        "RuleNumber": 99,
        "Protocol": -1,
        "RuleAction": "allow",
        "Egress": true,
        "CidrBlock": "0.0.0.0/0"
      
    ,

    "NetworkAclEntryInPrivateAllowVpc": 
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": 
        "NetworkAclId":  "Ref": "NetworkAclPrivate" ,
        "RuleNumber": 99,
        "Protocol": -1,
        "RuleAction": "allow",
        "Egress": false,
        "CidrBlock": "0.0.0.0/16"
      
    ,

    "NetworkAclEntryOutPrivateAllowVpc": 
      "Type": "AWS::EC2::NetworkAclEntry",
      "Properties": 
        "NetworkAclId":  "Ref": "NetworkAclPrivate" ,
        "RuleNumber": 99,
        "Protocol": -1,
        "RuleAction": "allow",
        "Egress": true,
        "CidrBlock": "0.0.0.0/0"
      
    ,

    "LambdasSecurityGroup": 
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": 
        "GroupDescription": "Lambdas security group",
        "SecurityGroupEgress": [
           "CidrIp": "0.0.0.0/0", "IpProtocol": "-1" 
        ],
        "SecurityGroupIngress": [
           "CidrIp": "0.0.0.0/0", "IpProtocol": "-1" 
        ],
        "VpcId":  "Ref": "Vpc" 
      
    ,

    "LambdaFunctionExecutionRole": 
      "Type": "AWS::IAM::Role",
      "Properties": 
        "AssumeRolePolicyDocument": 
          "Version": "2012-10-17",
          "Statement": [
            
              "Effect": "Allow",
              "Principal":  "Service": "lambda.amazonaws.com" ,
              "Action": "sts:AssumeRole"
            
          ]
        ,
        "ManagedPolicyArns": [
          "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
          "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
        ]
      
    ,

    "LambdaFunction": 
      "Type": "AWS::Lambda::Function",
      "Properties": 
        "Handler": "index.lambda_handler",
        "Runtime": "python2.7",
        "Role": 
          "Fn::GetAtt": ["LambdaFunctionExecutionRole", "Arn"]
        ,
        "Code": 
          "ZipFile": 
            "Fn::Join": ["\n", [
              "import urllib2",
              "def lambda_handler(event, context):",
              "\tresponse = urllib2.urlopen('http://python.org/')",
              "\treturn response.read()"
            ]]
          
        ,
        "VpcConfig": 
          "SecurityGroupIds": [
             "Fn::GetAtt": [ "LambdasSecurityGroup", "GroupId"] 
          ],
          "SubnetIds": [
             "Ref": "SubnetAPrivate" ,
             "Ref": "SubnetBPrivate" 
          ]
        
      
    
  

【问题讨论】:

您是否测试过私有子网中的EC2实例是否可以访问互联网? 【参考方案1】:

连接失败的原因在于“NetworkAclEntryInPrivateAllowVpc”和“NetworkAclEntryOutPrivateAllowVpc”的 ACL 配置。

如果您将 CIDR 块从“0.0.0.0/16”打开到“0.0.0.0/0”,Lambda 可以访问互联网。

我对 NAT 不太了解,但似乎 NAT 流量被该 ACL 规则阻止。

【讨论】:

哈哈,我整天都在和它作斗争,并没有注意到像那个错字这样简单的事情。应该是/0。它解决了这个问题,谢谢。将在真正的堆栈上进行尝试。

以上是关于VPC 中的 AWS Lambda 在 NAT 之后没有互联网访问权限的主要内容,如果未能解决你的问题,请参考以下文章

AWS Lambda + NAT 网关的替代方案

一个 VPC 终端节点用于 AWS 中的多项服务

如何从账户 A 中的 Lambda(VPC 中的 Lambda)调用账户 B 中的 AWS Lambda 函数(VPC 中的这个 Lambda)

从 VPC 中的 Lambda 访问 AWS S3

AWS ECS:VPC 终端节点和 NAT 网关

AWS Lambda 无法访问同一 VPC 中的 EC2 端口