Как обеспечить доступ c APIG к лямбде внутри VP C? - PullRequest
0 голосов
/ 27 января 2020

У меня небольшое веб-приложение, развернутое как лямбда aws, которое корректно работает при тестировании через консоль управления лямбда. Однако выполнение теста через консоль 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 недавно добавлено), чтобы разрешить лямбда-вызов. Ошибка начала возникать после того, как я переместил лямбду в VP C.

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"

Ответы [ 2 ]

0 голосов
/ 18 февраля 2020

Единственное, о чем я могу думать, это то, что исходный код шлюза API Arn должен заканчиваться путем к ресурсу. В вашем случае это заканчивается /.

. Я бы добавил * в конце, чтобы позволить любому пути ресурса вызывать лямбду. Вы можете изменить его на указанный c путь, как только он заработает.

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}/*/*/*"

надеюсь, это поможет. удачи.

0 голосов
/ 18 февраля 2020

В "squashLambdaRole" попробуйте добавить "apigateway.amazon aws .com" в список участников службы + присоединить управляемую политику AWS с именем "AWSLambdaRole". Это решило мою проблему, но я не понял, почему: /

...