繁体   English   中英

ApiGatewayV2 如何通过 CloudFormation 设置“执行角色”

[英]ApiGatewayV2 how to set the "Execution Role" via CloudFormation

我正在尝试通过 API 网关设置 websockets。 当我尝试建立连接时,我在 CloudWatch 日志中收到错误“ Execution failed due to configuration error: Invalid permissions on Lambda function ”。

我在我的 CloudFormation 中创建了AWS::IAM::Role资源,并将其作为Role附加到我的AWS::Lambda::Function资源中。 但我想我需要将它附加到AWS::ApiGatewayV2::Integration ,但我不知道该怎么做。

当我查看 AWS 控制台时,我发现没有选择执行角色:

AWS 控制台截图

但我看不到如何在 CloudFormation 中添加角色。 我错过了什么?

完整的 CloudFormation:

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Website S3 Hosted, API Gateway Backend
Parameters:
  DomainName:
    Type: String
    Description: The DNS name of an Amazon Route 53 hosted zone e.g. server.com
    AllowedPattern: '(?!-)[a-zA-Z0-9-.]{1,63}(?<!-)'
    ConstraintDescription: must be a valid DNS zone name.
  DiscordToken:
    Type: String
  DiscordChannelID:
    Type: String
  HostedZoneId:
    Type: String
  SSLARN:
    Description: Cloudfront SSL ARN (us-east-1)
    Type: String

Mappings:
  APIRegionMap:
    us-east-1:
      APIHostedZoneId: Z1UJRXOUMOOFQ8
    us-east-2:
      APIHostedZoneId: ZOJJZC49E0EPZ
    us-west-1:
      APIHostedZoneId: Z2MUQ32089INYE
    us-west-2:
      APIHostedZoneId: Z2OJLYMUO9EFXC

Resources:

  # SSL

  SSL:
    Type: AWS::CertificateManager::Certificate
    Properties: 
      DomainName: !Ref DomainName
      DomainValidationOptions: 
        - DomainName: !Join ['.', ['api', !Ref DomainName]]
          HostedZoneId: !Ref HostedZoneId
      SubjectAlternativeNames: 
        - !Join ['.', ['*', !Ref DomainName]]
      ValidationMethod: DNS

  # DynamoDB Tables

  SocketTable: 
    Type: AWS::DynamoDB::Table
    Properties: 
      AttributeDefinitions: 
        - 
          AttributeName: connectionId
          AttributeType: S
      KeySchema: 
        - 
          AttributeName: connectionId
          KeyType: HASH
      BillingMode: PAY_PER_REQUEST
      TableName: clients

  # Lambda Items

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: '/'
      Policies:
      - PolicyName: execution
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource: '*'
          - Effect: Allow
            Action:
            - s3:GetObject
            - s3:PutObject
            - s3:ListBucket
            Resource: '*'
            Resource: '*'
          - Effect: Allow
            Action:
            - lambda:InvokeFunction
            Resource: '*'
          - Effect: Allow
            Action:
            - execute-api:Invoke
            - execute-api:ManageConnections
            Resource: '*'

  LambdaFunctionSocketServer:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: exports.handler = function (event, context, callback) { callback(null, event); };
      Handler: index.handler
      MemorySize: 1024
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: nodejs12.x
      Timeout: 900
      Environment:
        Variables:
          DBTable: !Ref SocketTable
          DiscordToken: !Ref DiscordToken
          DiscordChannelID: !Ref DiscordChannelID

  # API Gateway Items

  WebSocketLoggingRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: apigateway.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: '/'
      Policies:
      - PolicyName: execution
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:DescribeLogGroups
            - logs:DescribeLogStreams
            - logs:PutLogEvents
            - logs:GetLogEvents
            - logs:FilterLogEvents
            Resource: '*'

  WebSocketAPI:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: !Join ['-', !Split ['.', !Join ['.', ['ws', !Ref DomainName]]]]
      ProtocolType: WEBSOCKET
      RouteSelectionExpression: "$request.body.action"

  WebSocketInteg:
    Type: AWS::ApiGatewayV2::Integration
    DependsOn:
      - LambdaFunctionSocketServer
    Properties:
      ApiId: !Ref WebSocketAPI
      Description: WebSocket Integration
      IntegrationType: AWS_PROXY
      IntegrationUri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunctionSocketServer.Arn}/invocations'

  WebSocketConnectRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketAPI
      RouteKey: $connect
      AuthorizationType: NONE
      OperationName: ConnectRoute
      Target: !Join ['/', ['integrations', !Ref WebSocketInteg]]

  WebSocketDisconnectRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketAPI
      RouteKey: $disconnect
      AuthorizationType: NONE
      OperationName: DisconnectRoute
      Target: !Join ['/', ['integrations', !Ref WebSocketInteg]]

  WebSocketSendRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketAPI
      RouteKey: sendmessage
      AuthorizationType: NONE
      OperationName: SendRoute
      Target: !Join ['/', ['integrations', !Ref WebSocketInteg]]

  WebSocketDeployment:
    Type: AWS::ApiGatewayV2::Deployment
    DependsOn:
      - WebSocketConnectRoute
      - WebSocketSendRoute
      - WebSocketDisconnectRoute
    Properties:
      ApiId: !Ref WebSocketAPI

  WebSocketLogGroup:
    Type: AWS::Logs::LogGroup
    Properties: 
      LogGroupName: !Join ['.', ['ws', !Ref DomainName]]
      RetentionInDays: 3
  
  WebSocketStage:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      StageName: Prod
      Description: Prod Stage
      DeploymentId: !Ref WebSocketDeployment
      ApiId: !Ref WebSocketAPI

  WebSocketDomain:
    Type: 'AWS::ApiGatewayV2::DomainName'
    Properties:
      DomainName: !Join ['.', ['ws', !Ref DomainName]]
      DomainNameConfigurations:
        - EndpointType: REGIONAL
          CertificateArn: !Ref SSL

  WebSocketMapping:
    Type: 'AWS::ApiGatewayV2::ApiMapping'
    DependsOn:
      - WebSocketDeployment
    Properties:
      DomainName: !Ref WebSocketDomain
      ApiId: !Ref WebSocketAPI
      Stage: !Ref WebSocketStage

  # Website items
  
  WebsiteBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Delete
    DependsOn:
      - WebSocketDeployment
    Properties:
      BucketName:
        Ref: DomainName
      AccessControl: PublicRead
      WebsiteConfiguration:
        IndexDocument: index.html
        ErrorDocument: 404.html
      Tags:
      - Key: Name
        Value: !Join ['_', ['WebsiteBucket', !Ref 'AWS::StackName']]
      - Key: Domain
        Value: !Ref DomainName
    DeletionPolicy: Retain

  WWWBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Delete
    DependsOn:
      - WebSocketDeployment
    Properties:
      BucketName: !Join ['.', ['www', !Ref DomainName]]
      AccessControl: PublicRead
      WebsiteConfiguration:
        RedirectAllRequestsTo:
          HostName: !Ref WebsiteBucket
      Tags:
      - Key: Name
        Value: !Join ['_', ['WWWBucket', !Ref 'AWS::StackName']]
      - Key: Domain
        Value: !Ref DomainName

  ImageBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Delete
    DependsOn:
      - WebSocketDeployment
    Properties:
      BucketName: !Join ['.', ['images', !Ref DomainName]]
      AccessControl: Private
      Tags:
      - Key: Name
        Value: !Join ['_', ['ImageBucket', !Ref 'AWS::StackName']]
      - Key: Domain
        Value: !Ref DomainName
    DeletionPolicy: Retain

  WebsiteBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref WebsiteBucket
      PolicyDocument:
        Statement:
        - Action:
          - s3:GetObject
          Effect: Allow
          Resource: !Join ['', ['arn:aws:s3:::', !Ref WebsiteBucket, '/*']]
          Principal: '*'
  
  WWWBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref WWWBucket
      PolicyDocument:
        Statement:
        - Action:
          - s3:GetObject
          Effect: Allow
          Resource: !Join ['', ['arn:aws:s3:::', !Ref WWWBucket, '/*']]
          Principal: '*'

  WebsiteCloudfront:
    Type: AWS::CloudFront::Distribution
    DependsOn:
    - WebsiteBucket
    Properties:
      DistributionConfig:
        Comment: !Ref DomainName
        Origins:
        - DomainName: !Select [2, !Split ["/", !GetAtt WebsiteBucket.WebsiteURL]]
          Id: S3Origin
          CustomOriginConfig:
            HTTPPort: '80'
            HTTPSPort: '443'
            OriginProtocolPolicy: http-only
        Enabled: true
        HttpVersion: 'http2'
        DefaultRootObject: index.html
        Aliases:
        - !Ref DomainName
        - !Join ['.', ['www', !Ref DomainName]]
        DefaultCacheBehavior:
          DefaultTTL: 60
          MaxTTL: 60
          MinTTL: 60
          AllowedMethods:
          - GET
          - HEAD
          Compress: true
          TargetOriginId: S3Origin
          ForwardedValues:
            QueryString: true
            Cookies:
              Forward: none
          ViewerProtocolPolicy: redirect-to-https
        PriceClass: PriceClass_All
        ViewerCertificate:
          AcmCertificateArn: !Ref SSLARN
          SslSupportMethod: sni-only
        CustomErrorResponses:
          - ErrorCode: 404
            ResponseCode: 200
            ResponsePagePath: /index.html

  CloudfrontDNSRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneName:
        Fn::Join: ['', [!Ref DomainName, '.']]
      Comment: Cloudfront zone records.
      RecordSets:
      - Name: !Ref DomainName
        Type: A
        AliasTarget:
          HostedZoneId: Z2FDTNDATAQYW2
          DNSName: !GetAtt [WebsiteCloudfront, DomainName]
      - Name: !Join ['.', ['www', !Ref DomainName]]
        Type: A
        AliasTarget:
          HostedZoneId: Z2FDTNDATAQYW2
          DNSName: !GetAtt [WebsiteCloudfront, DomainName]

  WebsocketDNSRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneName:
        Fn::Join: ['', [!Ref DomainName, '.']]
      Comment: Websocket zone records.
      RecordSets:
      - Name: !Join ['.', ['ws', !Ref DomainName]]
        Type: A
        AliasTarget:
          HostedZoneId:
            Fn::FindInMap:
            - APIRegionMap
            - Ref: AWS::Region
            - APIHostedZoneId
          DNSName: !GetAtt [WebSocketDomain, RegionalDomainName]

Outputs:
  S3WebsiteURL:
    Value: !GetAtt WebsiteBucket.WebsiteURL
    Description: URL for website hosted on S3

我认为您只需要添加一个AWS::Lambda::Permission以允许网关调用 function。

OnConnectPermission:
  Type: AWS::Lambda::Permission
  DependsOn:
    - WebSocketAPI
  Properties:
    Action: lambda:InvokeFunction
    FunctionName: !Ref LambdaFunctionSocketServer
    Principal: apigateway.amazonaws.com

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM