Aws lambda 如何让公共APIG访问VPC内的lambda?

Aws lambda 如何让公共APIG访问VPC内的lambda?,aws-lambda,amazon-cloudformation,aws-api-gateway,amazon-vpc,Aws Lambda,Amazon Cloudformation,Aws Api Gateway,Amazon Vpc,我有一个作为aws lambda部署的小型web应用程序,通过lambda管理控制台进行测试时,该应用程序可以正确运行。但是,通过apig控制台运行测试会导致此错误: Sun Jan 26 21:43:30 UTC 2020 : Execution failed due to configuration error: Invalid permissions on Lambda function 但是,apig具有执行权限: apiGatewayRole: DependsOn:

我有一个作为aws lambda部署的小型web应用程序,通过lambda管理控制台进行测试时,该应用程序可以正确运行。但是,通过apig控制台运行测试会导致此错误:

Sun Jan 26 21:43:30 UTC 2020 : Execution failed due to configuration error: Invalid permissions on Lambda function
但是,apig具有执行权限:

  apiGatewayRole:
    DependsOn:
      - squashApp
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "apigateway.amazonaws.com"
            Action: "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
      Policies:
        - PolicyName: "API_Service_Role_Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Action: "lambda:InvokeFunction"
                Resource: !GetAtt "squashApp.Arn"
                Effect: "Allow"
  lambdaApiGatewayInvoke:
    Type: "AWS::Lambda::Permission"
    Properties:
      Action: "lambda:InvokeFunction"
      FunctionName: !GetAtt "squashApp.Arn"
      Principal: "apigateway.amazonaws.com"
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/"
以前,权限足以(IAM策略最近添加)允许lambda调用。在我将lambda移动到VPC内后,错误开始出现

squashApp:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          GO_ENV: production
          DB_HOST: !GetAtt "squashRDS.Endpoint.Address"
          DB_PORT: !GetAtt "squashRDS.Endpoint.Port"
          DB_USER_NAME: !Sub "${rdsUser}"
          DB_USER_PASS: !Sub "${rdsPassword}"
      Code:
        S3Bucket: '${lambdaHandoffBucket}'
        S3Key: !Sub 'functions/${lambdaVersion}/${lambdaHash}' # TODO make parameter
      Handler: 'app'
      Role: !GetAtt "squashLambdaRole.Arn"
      Runtime: 'go1.x'
      Timeout: 2
      FunctionName: !Ref "lambdaFunctionName"
      VpcConfig:
        SecurityGroupIds:
          - !Ref "lambdaSecurtiyGroup"
        SubnetIds:
          - !Ref "privateSubnet1"
          - !Ref "privateSubnet2"
  vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.192.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
  privateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref vpc
      CidrBlock: 10.192.21.0/24
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Ref "PrimaryAZ"
      Tags:
        - Key: Name
          Value: !Sub ${apiGatewayStageName} Private Subnet (AZ1)
  privateSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref vpc
      CidrBlock: 10.192.30.0/24
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Ref "SecondaryAZ"

  privateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref vpc
  privateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref privateRouteTable1
      SubnetId: !Ref privateSubnet1
  privateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref vpc
  privateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref privateRouteTable1
      SubnetId: !Ref privateSubnet1
  noIngressSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "no-ingress-sg"
      GroupDescription: "Security group with no ingress rule"
      VpcId: !Ref vpc
完整的云形成资源部分:

Resources:
  apiGateway:
    Type: "AWS::ApiGateway::RestApi"
    Properties:
      Name: "SquashAPI"
      Description: "Squash Box Ladder"

  apiGatewayRootMethod:
    Type: "AWS::ApiGateway::Method"
    Properties:
      AuthorizationType: "NONE"
      # This can be ANY | GET| POST | etc and references the api http method as seen by a client
      HttpMethod: "ANY"
      Integration:
        # This must be post or the integration between gateway and lambda fails
        IntegrationHttpMethod: "POST"
        Type: "AWS_PROXY"
        Uri: !Sub
          - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
          - lambdaArn: !GetAtt "squashApp.Arn"
      ResourceId: !GetAtt "apiGateway.RootResourceId"
      RestApiId: !Ref "apiGateway"

  apiGatewayCatchAllProxy:
    Type: AWS::ApiGateway::Resource
    Properties:
      PathPart: "{proxy+}"
      RestApiId: !Ref "apiGateway"
      ParentId: !GetAtt "apiGateway.RootResourceId"

  apiGatewayCatchAllMethod:
    Type: "AWS::ApiGateway::Method"
    Properties:
      AuthorizationType: "NONE"
      HttpMethod: "ANY"
      Integration:
        # This must be post or the integration between gateway and lambda fails
        IntegrationHttpMethod: "POST"
        Type: "AWS_PROXY"
        Uri: !Sub
          - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
          - lambdaArn: !GetAtt "squashApp.Arn"
      ResourceId: !Ref "apiGatewayCatchAllProxy"
      RestApiId: !Ref "apiGateway"

  apiGatewayDeployment:
    Type: "AWS::ApiGateway::Deployment"
    DependsOn:
      - "apiGatewayRootMethod"
      - "apiGatewayCatchAllMethod"
    Properties:
      RestApiId: !Ref "apiGateway"
      StageName: !Ref "apiGatewayStageName"

  squashApp:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          GO_ENV: production
          DB_HOST: !GetAtt "squashRDS.Endpoint.Address"
          DB_PORT: !GetAtt "squashRDS.Endpoint.Port"
          DB_USER_NAME: !Sub "${rdsUser}"
          DB_USER_PASS: !Sub "${rdsPassword}"
      Code:
        S3Bucket: '${lambdaHandoffBucket}'
        S3Key: !Sub 'functions/${lambdaVersion}/${lambdaHash}' # TODO make parameter
      Handler: 'app'
      Role: !GetAtt "squashLambdaRole.Arn"
      Runtime: 'go1.x'
      Timeout: 2
      FunctionName: !Ref "lambdaFunctionName"
      VpcConfig:
        SecurityGroupIds:
          - !Ref "lambdaSecurtiyGroup"
        SubnetIds:
          - !Ref "privateSubnet1"
          - !Ref "privateSubnet2"

  lambdaSecurtiyGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: For Lambda Application
      VpcId: !Ref vpc

  lambdaEgres:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
      GroupId: !Ref lambdaSecurtiyGroup
      IpProtocol: tcp
      FromPort: !GetAtt "squashRDS.Endpoint.Port"
      ToPort: !GetAtt "squashRDS.Endpoint.Port"
      CidrIp: !GetAtt 'vpc.CidrBlock'

  lambdaApiGatewayInvoke:
    Type: "AWS::Lambda::Permission"
    Properties:
      Action: "lambda:InvokeFunction"
      FunctionName: !GetAtt "squashApp.Arn"
      Principal: "apigateway.amazonaws.com"
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/"

  squashLambdaRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action:
              - "sts:AssumeRole"
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
      Policies:
        - PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Effect: "Allow"
                Resource:
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*"
          PolicyName: "lambda"

  lambdaLogGroup:
    Type: "AWS::Logs::LogGroup"
    Properties:
      LogGroupName: !Sub "/aws/lambda/${lambdaFunctionName}"
      RetentionInDays: 14
  apiGatewayRole:
    DependsOn:
      - squashApp
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "apigateway.amazonaws.com"
            Action: "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
      Policies:
        - PolicyName: "API_Service_Role_Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Action: "lambda:InvokeFunction"
                Resource: !GetAtt "squashApp.Arn"
                Effect: "Allow"
  apiGwAccountConfig:
    Type: "AWS::ApiGateway::Account"
    Properties:
      CloudWatchRoleArn: !GetAtt "apiGatewayRole.Arn"
  squashRDS:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.t2.micro
      AllocatedStorage: 20
      StorageType: "gp2"
      Engine: "postgres"
      MasterUsername: !Sub "${rdsUser}"
      MasterUserPassword: !Sub "${rdsPassword}"
      DBSubnetGroupName: !Ref "rdsSubnetGroup"
      VPCSecurityGroups:
        - !Ref rdsSecurityGroup
    DeletionPolicy: Snapshot

  rdsSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: For RDS Instance
      VpcId: !Ref vpc
      Tags:
        - Key: Name
          Value: RDS-SecurityGroup

  rdsSubnetGroup:
    Type: "AWS::RDS::DBSubnetGroup"
    Properties:
      DBSubnetGroupName: "RDS Subnet Group"
      DBSubnetGroupDescription: Subnet including the RDS into the VPC
      SubnetIds:
        - !Ref "privateSubnet1"
        - !Ref "privateSubnet2"

  rdsIngres:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref rdsSecurityGroup
      IpProtocol: tcp
      FromPort: !GetAtt "squashRDS.Endpoint.Port"
      ToPort: !GetAtt "squashRDS.Endpoint.Port"
      CidrIp: !GetAtt 'vpc.CidrBlock'

  vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.192.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
  privateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref vpc
      CidrBlock: 10.192.21.0/24
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Ref "PrimaryAZ"
  privateSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref vpc
      CidrBlock: 10.192.30.0/24
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Ref "SecondaryAZ"

  privateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref vpc
  privateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref privateRouteTable1
      SubnetId: !Ref privateSubnet1
  privateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref vpc
  privateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref privateRouteTable1
      SubnetId: !Ref privateSubnet1

  noIngressSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "no-ingress-sg"
      GroupDescription: "Security group with no ingress rule"
      VpcId: !Ref vpc

Outputs:
  apiGatewayInvokeURL:
    Value: !Sub "https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}"

  lambdaArn:
    Value: !GetAtt "squashApp.Arn"
在“squashLambdaRole”中,尝试在服务主体列表中添加“apigateway.amazonaws.com”,并附加一个名为“AWSLambdaRole”的AWS托管策略。
它解决了我的问题,但我不明白为什么:/

我唯一能想到的是,API网关源Arn应该以资源路径结尾。在您的例子中,它以
/
结尾

我会在末尾添加一个
*
,以允许任何资源路径调用lambda。一旦工作正常,您可以将其更改为特定路径

lambdaApiGatewayInvoke:
  Type: "AWS::Lambda::Permission"
  Properties:
    Action: "lambda:InvokeFunction"
    FunctionName: !GetAtt "squashApp.Arn"
    Principal: "apigateway.amazonaws.com"
    SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/*"

希望这有帮助。祝你好运。

还不确定,但我认为问题在于函数中缺少基于资源的策略来允许api网关服务。