service: ${env:APP_NAME}-admin frameworkVersion: '>=2.0.0 <4.0.0' plugins: - serverless-s3-sync - serverless-baseline-invalidate-cloudfront custom: s3Sync: - bucketNameKey: S3Bucket localDir: .dist/ cloudfrontInvalidate: - distributionIdKey: 'CDNDistributionId' items: - '/*' # domain: # local: "local-admin.baselinejs.com" # staging: "staging-admin.baselinejs.com" # prod: "admin.baselinejs.com" provider: name: aws runtime: nodejs20.x profile: ${env:AWS_PROFILE} stage: ${opt:stage} deploymentMethod: direct deploymentPrefix: ${self:service}-${sls:stage} stackTags: AppName: ${env:APP_NAME} Stage: ${opt:stage} Region: ${opt:region} Product: Baseline # The "Resources" your "Functions" use. Raw AWS CloudFormation goes in here. resources: Description: ${env:APP_NAME} ${opt:stage} Resources: ## Specifying the S3 Bucket WebsiteS3Bucket: Type: AWS::S3::Bucket Properties: OwnershipControls: Rules: - ObjectOwnership: BucketOwnerPreferred PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false ## Specifying the policies to make sure all files inside the Bucket are available to CloudFront WebsiteS3BucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: WebsiteS3Bucket PolicyDocument: Statement: - Sid: PublicReadGetObject Effect: Allow Principal: Service: cloudfront.amazonaws.com Action: - s3:GetObject Resource: !Join - '' - - 'arn:aws:s3:::' - !Ref WebsiteS3Bucket - /* Condition: StringEquals: AWS:SourceArn: !Join [ '', [ 'arn:aws:cloudfront::', !Ref AWS::AccountId, ':distribution/', !Ref WebsiteCloudFrontDistribution, ], ] CloudfrontResponsePolicy: Type: AWS::CloudFront::ResponseHeadersPolicy Properties: ResponseHeadersPolicyConfig: Name: ${self:service}-${sls:stage}-no-cache-headers CustomHeadersConfig: Items: - Header: 'Cache-Control' Override: true Value: 'no-cache' # OAC Role for the Cloudfront distribution to block direct S3 Access WebsiteCloudFrontDistributionOriginAccessControl: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: ${self:service}-${sls:stage}-cloudfront-oac OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4 ## Specifying the CloudFront Distribution to serve your Web Application WebsiteCloudFrontDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: HttpVersion: http2 Origins: - DomainName: !GetAtt WebsiteS3Bucket.RegionalDomainName ## An identifier for the origin which must be unique within the distribution Id: !GetAtt WebsiteS3Bucket.RegionalDomainName OriginAccessControlId: !Ref WebsiteCloudFrontDistributionOriginAccessControl S3OriginConfig: OriginAccessIdentity: '' Enabled: true ## [Custom Domain] Add the domain alias # Aliases: # - ${self:custom.domain.${opt:stage}} DefaultRootObject: 'index.html' ## Since the Single Page App is taking care of the routing we need to make sure ever path is served with index.html ## The only exception are files that actually exist e.h. app.js, reset.css CustomErrorResponses: - ErrorCode: 403 ResponseCode: 200 ResponsePagePath: '/index.html' DefaultCacheBehavior: AllowedMethods: - GET - HEAD CachedMethods: - HEAD - GET Compress: true DefaultTTL: 1800 MinTTL: 0 ## The origin id defined above TargetOriginId: !GetAtt WebsiteS3Bucket.RegionalDomainName ## Defining if and how the QueryString and Cookies are forwarded to the origin which in this case is S3 ForwardedValues: QueryString: false Cookies: Forward: none ## The protocol that users can use to access the files in the origin. To allow HTTP use `allow-all` ViewerProtocolPolicy: redirect-to-https CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 ResponseHeadersPolicyId: !Ref CloudfrontResponsePolicy ## The certificate to use when viewers use HTTPS to request objects. ViewerCertificate: CloudFrontDefaultCertificate: true ## [Custom Domain] Stop using the cloudfront default certificate, uncomment below and add ACM Certificate ARN # MinimumProtocolVersion: TLSv1.2_2021 # SslSupportMethod: sni-only # AcmCertificateArn: arn:aws:acm:us-east-1:xxxxxxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # ARN of the AWS certificate ## Uncomment the following section in case you want to enable logging for CloudFront requests # Logging: # IncludeCookies: 'false' # Bucket: mylogs.s3.amazonaws.com # Prefix: myprefix ## In order to print out the hosted domain via `serverless info` we need to define the DomainName output for CloudFormation Outputs: AdminCloudFrontUrl: Description: The Admin URL Value: 'Fn::GetAtt': [WebsiteCloudFrontDistribution, DomainName] AdminCloudFrontDistributionId: Description: CloudFront Distribution Id Value: Ref: WebsiteCloudFrontDistribution CDNDistributionId: Description: CloudFront Distribution Id for serverless-cloudfront-invalidate Value: Ref: WebsiteCloudFrontDistribution S3Bucket: Description: S3 Bucket Value: Ref: WebsiteS3Bucket