AWS design high availability program architecture - APIGateway SQS Cloudformation

Dependency: This article requires an understanding of the basics of AWS architecture design

If you want to process API requests asynchronously or add queues to your application architecture, you're in the right place.

This article describes how to integrate Amazon API Gateway as a proxy for SQS (Simple Queue Service).

Create an IAM Lambda execution role

additional strategy

AWSLambdaVPCAccessExecutionRole
AWSLambdaRole
SecretsManagerReadWrite
AmazonSSMFullAccess
AmazonS3FullAccess
CloudWatchFullAccess

trust relationship

{
    
    
    "Version": "2012-10-17",
    "Statement": [
        {
    
    
            "Effect": "Allow",
            "Principal": {
    
    
                "Service": [
                    "secretsmanager.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Create an IAM APIGateway SQS role

additional strategy

AWSLambdaVPCAccessExecutionRole
AWSLambdaRole
AWSLambdaSQSExecutionRole
AmazonAPIGatewayPushToCloudWatchLogs
AmazonAPIGatewayAdministrator
SecretsManagerReadWrite

trust relationship

{
    
    
    "Version": "2012-10-17",
    "Statement": [
        {
    
    
            "Effect": "Allow",
            "Principal": {
    
    
                "Service": [
                    "apigateway.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Create the APIGateway SQS lambda

AWSTemplateFormatVersion: 2010-09-09
Parameters:
    Environment:
        Type: String
        Default: DEV
    SubProjectName:
        Description: The name of the sub project
        Type: String
        #TODO:
        Default: your-subsystem-name
    EnvironmentName:
        Type: String
        #TODO:
        Default: d
    CustomerName:
        Description: The name of the customer
        Type: String
        #TODO:
        Default: your-company-name
    ProjectName:
        Description: The name of the project
        Type: String
        #TODO:
        Default: your-project-name
    ProjectType:
        Type: String
        #TODO:
        Default: iot
    HostedZoneName:
        Description: The name of route53 hosted
        Type: String
        #TODO:
        Default: dev.xxxx.cn
    Certificate:
        Type: String
        #TODO:
        Default: xxxx-xxxx-xxx-xxx-xxxx
    SQSKmsMasterKeyId:
        Type: String
        #TODO:
        Default: xxxx-xxxx-xxx-xxx-xxxx
    S3BktName:
        Type: String
        #TODO:
        Default: xxxx-xxxx-d-s3
    BaseLayerS3FileName:
        Type: String
        #TODO:
        Default: xxxxxxxxxxxxxx
    LambdaSubnetIds:
        Description: The subnet ids of the lambda service
        Type: List<AWS::EC2::Subnet::Id>
        #TODO:
        Default: subnet-xxxxxxxxxx,subnet-xxxxxxxxxx
    LambdaSecurityGroups:
        Description: security groups for lambda
        Type: List<AWS::EC2::SecurityGroup::Id>
        #TODO:
        Default: sg-xxxxxxxxxx
Resources:
    #create apigateway
    APIGateway:
        Type: AWS::ApiGateway::RestApi
        Properties:
            Description: API Endpoint to receive JSON payloads and queue in SQS
            Name: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-${
    
    EnvironmentName}-agw
            DisableExecuteApiEndpoint: true
            Parameters:
                endpointConfigurationTypes: REGIONAL
                ignore: documentation
            EndpointConfiguration:
                Types:
                    - REGIONAL
            Tags:
                - Key: ApplName
                  Value: your-app-name
    ProdDeployment:
        Type: AWS::ApiGateway::Deployment
        DependsOn:
            - PostMethod
            - CapPostMethod
        Properties:
            RestApiId: !Ref APIGateway
    ProdStage:
        Properties:
            DeploymentId: !Ref ProdDeployment
            RestApiId: !Ref APIGateway
            StageName: !Ref EnvironmentName
        Type: AWS::ApiGateway::Stage
    V1Resource:
        Type: AWS::ApiGateway::Resource
        Properties:
            ParentId: !GetAtt APIGateway.RootResourceId
            PathPart: v1
            RestApiId: !Ref APIGateway
    #create api mapping
    ApiDomainName:
        Type: 'AWS::ApiGateway::DomainName'
        Properties:
            RegionalCertificateArn: !Sub arn:aws-cn:acm:${
    
    AWS::Region}:${
    
    AWS::AccountId}:certificate/${
    
    Certificate}
            DomainName: !Sub ${
    
    ProjectName}${
    
    ProjectType}.${
    
    HostedZoneName}
            EndpointConfiguration:
                Types:
                    - REGIONAL
    ApiPathMapping:
        Type: 'AWS::ApiGateway::BasePathMapping'
        Properties:
            DomainName: !Ref ApiDomainName
            RestApiId: !Ref APIGateway
            Stage: !Ref ProdStage
    #create api route53 record
    Rount53DNSRecord:
        Type: AWS::Route53::RecordSet
        Properties:
            HostedZoneName: !Sub ${
    
    HostedZoneName}.
            Comment: ApiGateway subsystem DNS.
            Name: !Sub ${
    
    ProjectName}${
    
    ProjectType}.${
    
    HostedZoneName}.
            Type: A
            AliasTarget:
                HostedZoneId: !GetAtt 'ApiDomainName.RegionalHostedZoneId'
                DNSName: !GetAtt 'ApiDomainName.RegionalDomainName'
    #create lambda base layer
    LambdaBaseLayer:
        Type: AWS::Lambda::LayerVersion
        Properties:
            LayerName: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-sqs-layerbase-${
    
    EnvironmentName}-lambda
            Description: SQS lambda base layer
            Content:
                S3Bucket: !Ref S3BktName
                S3Key: !Ref BaseLayerS3FileName
            CompatibleRuntimes:
                - nodejs14.x
            LicenseInfo: MIT
    #create syb-system 
    Queue:
        Type: AWS::SQS::Queue
        Properties:
            DelaySeconds: 0
            MaximumMessageSize: 262144
            MessageRetentionPeriod: 1209600
            KmsMasterKeyId: !Ref SQSKmsMasterKeyId
            QueueName: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-${
    
    SubProjectName}-${
    
    EnvironmentName}-sqs
            ReceiveMessageWaitTimeSeconds: 0
            VisibilityTimeout: 30
            Tags:
                - Key: ApplName
                  Value: your-app-name
    PolicySQS:
        Type: AWS::SQS::QueuePolicy
        Properties:
            PolicyDocument:
                Statement:
                    - Action: SQS:*
                      Effect: Allow
                      Principal: '*'
                      Resource: !GetAtt Queue.Arn
                Version: '2012-10-17'
            Queues:
                - !Ref Queue
    PostMethod:
        Type: AWS::ApiGateway::Method
        Properties:
            AuthorizationType: CUSTOM
            # Optional if SignatureAuthorizer is used
            AuthorizerId: !Ref SignatureAuthorizer
            # AuthorizationType: NONE
            HttpMethod: POST
            Integration:
                Credentials: !Sub arn:aws-cn:iam::${
    
    AWS::AccountId}:role/${
    
    CustomerName}-${
    
    ProjectName}-agw-sqs-${
    
    EnvironmentName}-iamr
                IntegrationHttpMethod: POST
                IntegrationResponses:
                    - StatusCode: '200'
                PassthroughBehavior: NEVER
                RequestParameters:
                    integration.request.header.Content-Type: "'application/x-www-form-urlencoded'"
                RequestTemplates:
                    application/json: Action=SendMessage&MessageBody=$input.body
                Type: AWS
                Uri: !Sub arn:aws-cn:apigateway:${
    
    RegionName}:sqs:path/${
    
    AWS::AccountId}/${
    
    CustomerName}-${
    
    ProjectName}-${
    
    SubProjectName}-${
    
    EnvironmentName}-sqs
            MethodResponses:
                - ResponseModels:
                      application/json: Empty
                  StatusCode: '200'
            ResourceId: !Ref EnqueueResource
            RestApiId: !Ref APIGateway
    EnqueueResource:
        Properties:
            ParentId: !Ref V1Resource
            PathPart: !Ref SubProjectName
            RestApiId: !Ref APIGateway
        Type: AWS::ApiGateway::Resource
    #signature(optional)
    SignatureAuthorizer:
        Type: 'AWS::ApiGateway::Authorizer'
        Properties:
            AuthorizerCredentials: !Sub arn:aws-cn:iam::${
    
    AWS::AccountId}:role/${
    
    CustomerName}-${
    
    ProjectName}-agw-sqs-${
    
    EnvironmentName}-iamr
            AuthorizerResultTtlInSeconds: '300'
            AuthorizerUri: !Join
                - ''
                - - 'arn:aws-cn:apigateway:'
                  - !Ref 'AWS::Region'
                  - ':lambda:path/2015-03-31/functions/'
                  - !GetAtt
                    - SignatureLambdaFunction
                    - Arn
                  - /invocations
            Type: REQUEST
            IdentitySource: method.request.header.Auth
            Name: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-signature-${
    
    EnvironmentName}-authorizer
            RestApiId: !Ref APIGateway
    SignatureLambdaFunction:
        Type: AWS::Lambda::Function
        Properties:
            FunctionName: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-signature-${
    
    EnvironmentName}-lambda
            Description: signature lambda
            Code:
                ZipFile: |
                    exports.handler = async (event) =>  {
                        const defaultAllowAllPolicy = {"principalId": "user","policyDocument": {"Version": "2012-10-17","Statement": [{"Action": "execute-api:Invoke","Effect": "Allow","Resource": "*"}]}};
                        return defaultAllowAllPolicy;
                    };
            Handler: index.handler
            Role: !Sub arn:aws-cn:iam::${
    
    AWS::AccountId}:role/${
    
    CustomerName}-${
    
    ProjectName}-agw-sqs-${
    
    EnvironmentName}-iamr
            Runtime: nodejs14.x
            Environment:
                Variables:
                    # Signature secrets using the Secrets Manager API
                    SECRETS_MANAGER_NAME: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-${
    
    EnvironmentName}-secrets-manager
                    LOG_LEVEL: DEBUG
            Tags:
                - Key: ApplName
                  Value: your-app-name
    #trigger lambda
    LambdaFunction:
        Type: AWS::Lambda::Function
        Properties:
            FunctionName: !Sub ${
    
    CustomerName}-${
    
    ProjectName}-${
    
    SubProjectName}-${
    
    EnvironmentName}-lambda
            Description: sqs rais lambda
            Code:
                ZipFile: |
                    exports.handler = function(event, context) {
                        console.log('Empty lambda need to be replaced!');
                    };
            Handler: index.handler
            Layers:
                - Ref: LambdaBaseLayer
            Role: !Sub arn:aws-cn:iam::${
    
    AWS::AccountId}:role/${
    
    CustomerName}-${
    
    ProjectName}-agw-sqs-${
    
    EnvironmentName}-iamr
            Runtime: nodejs14.x
            Timeout: 900
            # MemorySize: 512
            VpcConfig: 
                SecurityGroupIds: !Ref LambdaSecurityGroups
                SubnetIds: !Ref LambdaSubnetIds
            Environment:
                Variables:
                    # database secrets using the Secrets Manager API
                    SECRETS_MANAGER_NAME: !Join [ '-', [ !Ref CustomerName, !Ref ProjectName, !Ref EnvironmentName, 'secrets-manager' ] ]
                    LOG_LEVEL: DEBUG
            Tags:
                - Key: ApplName
                  Value: your-app-name
    LambdaFunctionEventSourceMapping:
        Type: AWS::Lambda::EventSourceMapping
        Properties:
            BatchSize: 10
            Enabled: true
            EventSourceArn: !GetAtt Queue.Arn
            FunctionName: !GetAtt LambdaFunction.Arn

Question: Request Application/xml

1. "Integration Request"

1. Add HTTP headers

Content-Type : 'application/x-www-form-urlencoded'

2. Add a mapping template

1) Add application/xml

Action=SendMessage&MessageBody={"body" : $input.json('$')}

2) Add application/json

Action=SendMessage&MessageBody={"body" : $input.json('$')}

2. "Integrated Response"

1.200 Add application/xml to the mapping template of the response

#set($inputParam=$input.path('$'))
$inputParam.body
## 这里可以加入你自己的XML格式

3. "Method Response"

1,200 Response body adding application/xml

保存即可

Issue: Use of authorized parties

1. Standard OAuth application

方法请求中选择授权方,新建Lambda,在Lambda中获取Head ->Authrization,编码验证令牌。

2. Parameter signature

参数列表+Head[签名]字段,客户端签名,服务器验证签名。 私钥

3. Security control

WAF控制进站,限制访问的源

4. Body signature

Signator does not support body parameter passing [I don’t know what the designer thinks]
If you want to verify the signature after parsing the body, the current feasible solution is:

ApiGateway: 开放接口集成
Signater: 微服务或身份验证(body除外)
Lambda:验证签名,放置队列SQS(不限制启动数量、性能要求高)
SQS:削峰
Lambda:订阅SQS(限制启动数量)
RDS或S3等持久化

Guess you like

Origin blog.csdn.net/black0707/article/details/124986343