AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: A endpoint hosted by an API Gateway which invokes SQS, consumed by lambda function and persisted in a dynamoDB table. Resources: ########################################################################## # HTTP API - Entrypoint # ########################################################################## HttpApi: Type: AWS::Serverless::HttpApi Properties: AccessLogSettings: DestinationArn: !GetAtt ApiGatewayAccessLogs.Arn Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }' DefinitionBody: "Fn::Transform": Name: "AWS::Include" Parameters: Location: "api.yaml" Auth: DefaultAuthorizer: AuthorizerFunction Authorizers: AuthorizerFunction: FunctionArn: !GetAtt GatewayAuthorizerFunction.Arn AuthorizerPayloadFormatVersion: 2.0 EnableFunctionDefaultPermissions: true EnableSimpleResponses: true ########################################################################## # SQS Queues # ########################################################################## # SQS queue for request buffering BufferingQueue: Type: AWS::SQS::Queue Properties: QueueName: BufferingQueue SqsManagedSseEnabled: true RedrivePolicy: deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn maxReceiveCount: 5 # SQS DLQ DeadLetterQueue: Type: AWS::SQS::Queue Properties: QueueName: DeadLetterQueue SqsManagedSseEnabled: true ########################################################################## # Lambda Function - Gateway Handler # ########################################################################## SqsHandlerFunction: Type: AWS::Serverless::Function DependsOn: SqsHandlerLambdaExecutionRole Properties: FunctionName: SQSHandlerFunction Description: Lambda to be invoked by the SQS Queue CodeUri: lambda/sqs-handler/ Handler: index.lambda_handler Runtime: python3.10 Timeout: 3 MemorySize: 128 Role: !GetAtt SqsHandlerLambdaExecutionRole.Arn Layers: [ !Sub "arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:32", ] Events: SQSEvent: Type: SQS Properties: Queue: !GetAtt BufferingQueue.Arn BatchSize: 10 ########################################################################## # Lambda Function - Gateway Authorizer # ########################################################################## GatewayAuthorizerFunction: Type: AWS::Serverless::Function Properties: FunctionName: GatewayAuthorizerFunction Description: Lambda to be invoked by API Gateway for authorization CodeUri: lambda/authorizer/ Handler: index.lambda_handler Runtime: python3.10 Timeout: 3 MemorySize: 128 Role: !GetAtt AuthorizerLambdaExecutionRole.Arn Layers: [ !Sub "arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:32", ] ########################################################################## # DynamoDB Table # ########################################################################## EventTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: eventId AttributeType: S BillingMode: PAY_PER_REQUEST KeySchema: - AttributeName: eventId KeyType: HASH TableName: EventTable SSESpecification: SSEEnabled: true ########################################################################## # Roles # ########################################################################## ApiGatewayRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - apigateway.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: CustomPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "sqs:SendMessage" - "sqs:GetQueueUrl" - "sqs:SendMessageBatch" Resource: !GetAtt BufferingQueue.Arn - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:DescribeLogGroups" - "logs:DescribeLogStreams" - "logs:PutLogEvents" - "logs:GetLogEvents" - "logs:FilterLogEvents" Resource: !GetAtt ApiGatewayAccessLogs.Arn SqsHandlerLambdaExecutionRole: Type: "AWS::IAM::Role" DependsOn: EventTable Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: CustomPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "dynamodb:List*" - "dynamodb:DescribeReservedCapacity*" - "dynamodb:DescribeLimits" - "dynamodb:DescribeTimeToLive" - "dynamodb:Get*" - "dynamodb:PutItem" Resource: !GetAtt EventTable.Arn - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "*" - Effect: Allow Action: - "sqs:ReceiveMessage" - "sqs:DeleteMessage" - "sqs:GetQueueAttributes" Resource: !GetAtt BufferingQueue.Arn - Effect: Allow Action: - "sqs:SendMessage" Resource: !GetAtt DeadLetterQueue.Arn AuthorizerLambdaExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: CustomPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "*" - Effect: Allow Action: - "secretsmanager:GetSecretValue" Resource: [!Ref BasicAuthUsername, !Ref BasicAuthPassword] ########################################################################## # Cloudwatch Logs # ########################################################################## ApiGatewayAccessLogs: Type: AWS::Logs::LogGroup Properties: LogGroupName: Http-ApiGw-Access-Logs RetentionInDays: 1 ########################################################################## # Secrets - Generated for Endpoint Auth # ########################################################################## BasicAuthUsername: Type: AWS::SecretsManager::Secret Properties: Description: Username to be used in basic auth Name: endpoint/username GenerateSecretString: ExcludeCharacters: "" ExcludeLowercase: false ExcludeNumbers: false ExcludePunctuation: false ExcludeUppercase: false GenerateStringKey: UserName IncludeSpace: false PasswordLength: 32 RequireEachIncludedType: true SecretStringTemplate: !Sub '{"UserName": "REPLACED"}' BasicAuthPassword: Type: AWS::SecretsManager::Secret Properties: Description: Password to be used in basic auth Name: endpoint/password GenerateSecretString: ExcludeCharacters: "" ExcludeLowercase: false ExcludeNumbers: false ExcludePunctuation: false ExcludeUppercase: false GenerateStringKey: Password IncludeSpace: false PasswordLength: 32 RequireEachIncludedType: true SecretStringTemplate: !Sub '{"Password": "REPLACED"}' ########################################################################## # Outputs # ########################################################################## Outputs: HttpApiEndpoint: Description: "Http API endpoint" Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com"