Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CloudFormation Stack
AWSTemplateFormatVersion: 2010-09-09
Parameters:
stackID:
Type: String
AllowedPattern: '^[a-zA-Z0-9-]+$'
DomainName:
Type: String
AllowedPattern: '.*'
route53HostedZoneId:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9.]+$'
CertificateArn:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9./:-]+$'
Resources:
apiGateway:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: my-api
Description: My API
BinaryMediaTypes:
- '*/*'
apiGatewayDeployment:
Type: 'AWS::ApiGateway::Deployment'
DependsOn:
- apiGatewayGETMethod
Properties:
RestApiId: !Ref apiGateway
StageName: prod
lambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
Code:
ZipFile: |
def handler(event,context):
return {
'body': 'Hello there {0}'.format(event['requestContext']['identity']['sourceIp']),
'headers': {
'Content-Type': 'text/plain'
},
'statusCode': 200
}
Description: My function
FunctionName: !Sub '${stackID}'
Handler: prodserver.handler
MemorySize: 128
Role: !GetAtt lambdaIAMRole.Arn
Runtime: nodejs12.x
Timeout: 10
Layers:
- >-
arn:aws:lambda:us-east-1:378688096774:layer:kerrpopovich2020-deps-layer:15
lambdaApiGatewayInvoke:
Type: 'AWS::Lambda::Permission'
DependsOn:
- apiGatewayLambdaResource
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !GetAtt lambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/*'
lambdaIAMRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
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/${stackID}:*
PolicyName: lambda
s3AccessIAMRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- s3.amazonaws.com
- apigateway.amazonaws.com
Policies:
- PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
PolicyName: s3
lambdaLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/lambda/${stackID}'
RetentionInDays: 90
apiGatewayGETMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
ResourceId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
s3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Ref stackID
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
PolicyDocument:
Id: MyS3BucketPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: 's3:GetObject'
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref s3Bucket
- /*
Bucket: !Ref s3Bucket
apiGatewayAssetsResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
ParentId: !GetAtt
- apiGateway
- RootResourceId
PathPart: assets
apiGatewayAssetsItemsResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
PathPart: '{item}'
ParentId: !Ref apiGatewayAssetsResource
OptionsMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
ResourceId: !Ref apiGatewayAssetsItemsResource
RestApiId: !Ref apiGateway
HttpMethod: OPTIONS
Integration:
IntegrationResponses:
- StatusCode: 200
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
method.response.header.Access-Control-Allow-Origin: "'*'"
ResponseTemplates:
application/json: ''
PassthroughBehavior: WHEN_NO_MATCH
RequestTemplates:
application/json: '{"statusCode": 200}'
Type: MOCK
MethodResponses:
- StatusCode: 200
ResponseModels:
application/json: 'Empty'
ResponseParameters:
method.response.header.Access-Control-Allow-Headers: false
method.response.header.Access-Control-Allow-Methods: false
method.response.header.Access-Control-Allow-Origin: false
apiGatewayAssetsItemsResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
ResourceId: !Ref apiGatewayAssetsItemsResource
RestApiId: !Ref apiGateway
AuthorizationType: NONE
HttpMethod: GET
RequestParameters:
method.request.path.item: true
Integration:
Type: AWS
Credentials: !GetAtt s3AccessIAMRole.Arn
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
integration.request.path.item: 'method.request.path.item'
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:s3:path/${stackID}/{item}
IntegrationResponses:
- StatusCode: 200
ResponseTemplates: {"application/json": "", "image/jpg": ""}
MethodResponses:
- StatusCode: 200
ResponseModels: { "application/json": "Empty", "image/jpg": "Empty" }
apiGatewayLambdaResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
PathPart: '{proxy+}'
ParentId: !GetAtt
- apiGateway
- RootResourceId
apiGatewayLambdaResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
RestApiId: !Ref apiGateway
ResourceId: !Ref apiGatewayLambdaResource
HttpMethod: ANY
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
MethodResponses:
- StatusCode: 200
ResponseModels: { "application/json": "Empty" }
domainNameResource:
Type: 'AWS::ApiGateway::DomainName'
Properties:
CertificateArn: !Ref CertificateArn
DomainName: !Ref DomainName
basePathMapping:
Type: 'AWS::ApiGateway::BasePathMapping'
DependsOn:
- apiGatewayDeployment
Properties:
DomainName: !Ref DomainName
RestApiId: !Ref apiGateway
Stage: prod
domainRecordSet:
Type: 'AWS::Route53::RecordSet'
Properties:
AliasTarget:
DNSName: !GetAtt domainNameResource.DistributionDomainName
HostedZoneId: !GetAtt domainNameResource.DistributionHostedZoneId
Type: A
HostedZoneId: !Ref route53HostedZoneId
Name: !Ref DomainName
Outputs:
apiGatewayInvokeURL:
Value: !Sub >-
https://${DomainName}
lambdaArn:
Value: !GetAtt lambdaFunction.Arn
@PatNeedham

This comment has been minimized.

Copy link
Owner Author

PatNeedham commented May 30, 2020

image
image

Making it more flexible so this template can be used for multiple projects. Those previously hard-coded values are now parameters

@PatNeedham

This comment has been minimized.

Copy link
Owner Author

PatNeedham commented Jun 21, 2020

image

The tld and subdomain parameters were only used in combination with each other. Replacing them with DomainName makes it possible to now have a url without a subdomain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.