AWS 设计高可用程序架构——APIGateway SQS Cloudformation

依赖:本文需要了解AWS 架构设计基础知识

如果您想异步处理 API 请求或在应用程序架构中添加队列,那么您来对地方了。

本文介绍如何将 Amazon API Gateway 集成为 SQS(简单队列服务)的代理。

创建IAM Lambda执行角色

附加策略

AWSLambdaVPCAccessExecutionRole
AWSLambdaRole
SecretsManagerReadWrite
AmazonSSMFullAccess
AmazonS3FullAccess
CloudWatchFullAccess

信任关系

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

创建IAM APIGateway SQS角色

附加策略

AWSLambdaVPCAccessExecutionRole
AWSLambdaRole
AWSLambdaSQSExecutionRole
AmazonAPIGatewayPushToCloudWatchLogs
AmazonAPIGatewayAdministrator
SecretsManagerReadWrite

信任关系

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

创建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

问题:Request Application/xml

一、“集成请求”

1.添加HTTP 标头

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

2.添加映射模板

1)添加application/xml

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

2)添加application/json

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

二、“集成响应”

1.200 响应的映射模板添加application/xml

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

三、“方法响应”

1,200响应正文添加application/xml

保存即可

问题:授权方的使用

一、标准的OAuth应用

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

二、参数签名

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

三、安全控制

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

四、Body签名

Signator 不支持Body传参【也不知道设计者怎么想的】
如果要Body解析后验证签名,目前可行的方案是:

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

猜你喜欢

转载自blog.csdn.net/black0707/article/details/124986343