Created
June 20, 2023 10:17
-
-
Save bshelling/ddc51269da2c0cdc6e141bdfb1602d61 to your computer and use it in GitHub Desktop.
Cloudformation Template for a email subscription backend
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Transform: AWS::Serverless-2016-10-31 | |
Globals: | |
Function: | |
Runtime: nodejs18.x | |
Description: "Full stack email subscription application for kiosks architected by B.Shelling" | |
Parameters: | |
ROOTDOMAIN: | |
Type: "String" | |
Default: "kiosk.com" | |
CLIENTDOMAIN: | |
Type: "String" | |
Default: "kiosk.site.com" | |
APIDOMAIN: | |
Type: "String" | |
Default: "kioskapi.site.com" | |
RECAPSECRET: | |
Type: "String" | |
Default: "" | |
STAGENAME: | |
Type: "String" | |
Default: "dev" | |
BUCKETNAME: | |
Type: "String" | |
Default: "kiosk-test-bshelling" | |
TABLENAME: | |
Type: "String" | |
Default: "kioskTable" | |
ORIGINURL: | |
Type: "String" | |
Default: "*" | |
Resources: | |
# Bucket creation for web assets | |
KioskSiteBucket: | |
Type: AWS::S3::Bucket | |
Properties: | |
BucketName: !Ref BUCKETNAME | |
# Hosted Zone for application's domain | |
KioskSiteHostedZone: | |
Type: AWS::Route53::HostedZone | |
Properties: | |
HostedZoneConfig: | |
Comment: 'Hosted zone for kiosk application' | |
Name: !Ref ROOTDOMAIN | |
# Auto-generated certificate for domain - *note DomainValidationOptions property is key to the DNS validation being automated | |
KioskSiteCert: | |
Type: AWS::CertificateManager::Certificate | |
Properties: | |
DomainName: !Sub '*.${ROOTDOMAIN}' | |
DomainValidationOptions: | |
- DomainName: !Sub '*.${ROOTDOMAIN}' | |
HostedZoneId: !Ref KioskSiteHostedZone | |
ValidationMethod: DNS | |
# IAM Policy | |
KioskExecutionPolicy: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- apigateway.amazonaws.com | |
Action: | |
- 'sts:AssumeRole' | |
Policies: | |
- PolicyName: 'KioskExecutionRole' | |
PolicyDocument: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Action: 'lambda:InvokeFunction' | |
Resource: '*' | |
# Cloudfront distribution for web assets hosted in s3 | |
KioskSiteDistribution: | |
Type: AWS::CloudFront::Distribution | |
Properties: | |
DistributionConfig: | |
Aliases: | |
- !Ref CLIENTDOMAIN | |
CNAMEs: | |
- !Ref CLIENTDOMAIN | |
DefaultRootObject: index.html | |
ViewerCertificate: | |
AcmCertificateArn: !Ref KioskSiteCert | |
SslSupportMethod: sni-only | |
Enabled: True | |
PriceClass: PriceClass_100 | |
DefaultCacheBehavior: | |
ForwardedValues: | |
QueryString: false | |
AllowedMethods: | |
- GET | |
- HEAD | |
ViewerProtocolPolicy: redirect-to-https | |
TargetOriginId: KioskSiteOrigin | |
Origins: | |
- Id: KioskSiteOrigin | |
DomainName: !Sub '${KioskSiteBucket}.s3.${AWS::Region}.amazonaws.com' | |
OriginAccessControlId: !Ref KioskSiteOAC | |
S3OriginConfig: | |
OriginAccessIdentity: "" | |
# Api for function execution | |
KioskRestApi: | |
Type: AWS::Serverless::Api | |
Properties: | |
StageName: !Ref STAGENAME | |
DefinitionBody: | |
openapi: 3.0.0 | |
info: | |
version: 1.0 | |
title: Kiosk API | |
servers: | |
- url: !Sub 'https://${APIDOMAIN}' | |
paths: | |
/send: | |
options: | |
description: Options method | |
responses: | |
'200': | |
description: 'Cors configuration' | |
headers: | |
Access-Control-Allow-Origin: | |
schema: | |
type: string | |
Access-Control-Allow-Methods: | |
schema: | |
type: string | |
Access-Control-Allow-Headers: | |
schema: | |
type: string | |
x-amazon-apigateway-integration: | |
type: aws_proxy | |
httpMethod: OPTIONS | |
credentials: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${KioskExecutionPolicy}' | |
uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${KioskFunction}/invocations' | |
responses: | |
default: | |
statusCode: 200 | |
responseParameters: | |
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization'" | |
method.response.header.Access-Control-Allow-Methods: "'POST,OPTIONS'" | |
method.response.header.Access-Control-Allow-Origin: !Sub "'https://${KioskSiteRecordSet}'" | |
post: | |
description: Validate recaptcha and send email subscription | |
x-amazon-apigateway-integration: | |
type: aws_proxy | |
httpMethod: POST | |
credentials: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${KioskExecutionPolicy}' | |
uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${KioskFunction}/invocations' | |
responses: | |
default: | |
statusCode: 200 | |
'500': | |
statusCode: 500 | |
responseTemplates: | |
application/json: '{"message": "Something is messed up "}' | |
# Custom api domain name | |
KioskApiDomainName: | |
Type: AWS::ApiGatewayV2::DomainName | |
Properties: | |
DomainName: !Ref APIDOMAIN | |
DomainNameConfigurations: | |
- EndpointType: REGIONAL | |
CertificateArn: !Ref KioskSiteCert | |
KioskApiMapping: | |
Type: AWS::ApiGatewayV2::ApiMapping | |
Properties: | |
ApiId: !Ref KioskRestApi | |
DomainName: !Ref APIDOMAIN | |
Stage: !Ref STAGENAME | |
# Record Set for domain - alias target is the application's cloudfront distribution | |
KioskSiteRecordSet: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
AliasTarget: | |
DNSName: !GetAtt KioskSiteDistribution.DomainName | |
EvaluateTargetHealth: true | |
HostedZoneId: Z2FDTNDATAQYW2 | |
Name: !Ref CLIENTDOMAIN | |
HostedZoneId: !Ref KioskSiteHostedZone | |
Type: A | |
KioskApiRecordSet: | |
Type: AWS::Route53::RecordSet | |
Properties: | |
AliasTarget: | |
DNSName: !GetAtt KioskApiDomainName.RegionalDomainName | |
EvaluateTargetHealth: true | |
HostedZoneId: !GetAtt KioskApiDomainName.RegionalHostedZoneId | |
Name: !Ref APIDOMAIN | |
HostedZoneId: !Ref KioskSiteHostedZone | |
Type: A | |
# Function Role to allow write permissions to db table | |
KioskDbTableRole: | |
Type: AWS::IAM::Role | |
Properties: | |
Description: 'Allow db table writes from send function' | |
AssumeRolePolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- lambda.amazonaws.com | |
Action: | |
- 'sts:AssumeRole' | |
Path: / | |
Policies: | |
- PolicyName: dbpolicy | |
PolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Action: 'dynamodb:PutItem' | |
Resource: !GetAtt KioskSiteDbTable.Arn | |
# Send function for validating recaptcha and dynamodb storage | |
KioskFunction: | |
Type: AWS::Serverless::Function | |
Properties: | |
Handler: index.send | |
CodeUri: src/functions/send/ | |
Role: !GetAtt KioskDbTableRole.Arn | |
Environment: | |
Variables: | |
RECAPSECRET: !Ref RECAPSECRET | |
ORIGINURL: !Ref ORIGINURL | |
TABLENAME: !Ref TABLENAME | |
Events: | |
SendKiosk: | |
Type: Api | |
Properties: | |
Path: /send | |
Method: post | |
RestApiId: !Ref KioskRestApi | |
Metadata: | |
BuildMethod: makefile | |
# Bucket policy to only allow traffic from distribution - explicit | |
KioskSiteBucketPolicy: | |
Type: AWS::S3::BucketPolicy | |
Properties: | |
Bucket: !Ref KioskSiteBucket | |
PolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Action: | |
- 's3:GetObject' | |
Effect: Allow | |
Principal: | |
Service: 'cloudfront.amazonaws.com' | |
Condition: | |
StringEquals: | |
"AWS:SourceArn": !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${KioskSiteDistribution}' | |
Resource: !Sub 'arn:aws:s3:::${KioskSiteBucket}/*' | |
KioskSiteCachePolicy: | |
Type: AWS::CloudFront::CachePolicy | |
Properties: | |
CachePolicyConfig: | |
DefaultTTL: 3600 | |
MaxTTL: 7200 | |
MinTTL: 3600 | |
Name: KioskDefaultCachePolicy | |
ParametersInCacheKeyAndForwardedToOrigin: | |
EnableAcceptEncodingGzip: true | |
CookiesConfig: | |
CookieBehavior: none | |
HeadersConfig: | |
HeaderBehavior: none | |
QueryStringsConfig: | |
QueryStringBehavior: none | |
KioskSiteOAC: | |
Type: AWS::CloudFront::OriginAccessControl | |
Properties: | |
OriginAccessControlConfig: | |
Description: !Sub 'Kiosk to S3 OAC' | |
Name: !Sub 'KioskSiteOAC' | |
OriginAccessControlOriginType: s3 | |
SigningBehavior: always | |
SigningProtocol: sigv4 | |
# Kiosk Database for storing form submissions | |
KioskSiteDbTable: | |
Type: AWS::DynamoDB::Table | |
Properties: | |
AttributeDefinitions: | |
- AttributeName: lastname | |
AttributeType: S | |
- AttributeName: email | |
AttributeType: S | |
BillingMode: PAY_PER_REQUEST | |
TableClass: STANDARD | |
TableName: !Ref TABLENAME | |
KeySchema: | |
- AttributeName: email | |
KeyType: HASH | |
- AttributeName: lastname | |
KeyType: RANGE | |
# Outputs of all key resources | |
# If an external domain is used apply the nameservers from the output to the external domain registrar | |
Outputs: | |
KioskSiteApiUrl: | |
Description: 'Kiosk API Url' | |
Value: !Sub '${KioskRestApi}.execute-api.${AWS::Region}.amazonaws.com/${STAGENAME}' | |
KioskSiteExecution: | |
Description: 'Kiosk API Url' | |
Value: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${KioskExecutionPolicy}' | |
KioskRecordSet: | |
Description: '' | |
Value: !Sub 'https://${KioskApiRecordSet}' | |
KioskSiteCertArn: | |
Description: 'Kiosk Site Cert Arn' | |
Value: !Sub '${KioskSiteCert}' | |
KioskSiteNS: | |
Description: 'Nameservers for kiosk applicaiton hosted zone' | |
Value: !Join | |
- ',' | |
- !GetAtt KioskSiteHostedZone.NameServers | |
KioskSiteDomainName: | |
Description: 'Kiosk Distribution Domain Name' | |
Value: !GetAtt KioskSiteDistribution.DomainName | |
KioskSiteContentBucket: | |
Description: 'Kiosk Asset Bucket Name' | |
Value: !GetAtt KioskSiteBucket.DomainName | |
KioskSiteDatabase: | |
Description: 'Kiosk Data Table Name' | |
Value: !Ref KioskSiteDbTable | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment