
service: tab-media # Important: this must be unique in AWS Cloudformation!
frameworkVersion: ">=1.14.0 <2.0.0"

provider:
  name: aws
  runtime: nodejs12.x
  region: us-west-2
  stage: ${env:SLS_STAGE, self:custom.stageDefault}
  # Let's be conservative and prevent any unexpected changes
  # to the stack. See:
  # https://github.com/gladly-team/tab/issues/582
  # Example to update policy:
  #   aws cloudformation set-stack-policy --stack-name tab-media-dev --region us-west-2 --stack-policy-body \
  #   '{"Statement":[
  #     {"Effect":"Allow","Principal":"*","Action":"Update:Modify","Resource":"LogicalResourceId/WebAppCloudFrontDistribution"}
  #   ]}'
  stackPolicy:
    - Effect: Deny
      Principal: "*"
      Action: "Update:*"
      Resource: "*"

custom:
  stageDefault: dev
  s3Bucket: ${env:DEPLOYMENT_MEDIA_S3_BUCKET_NAME}
  cloudfrontMediaName: TabMedia
  cloudfrontMediaDomainAlias: ${env:DEPLOYMENT_MEDIA_CLOUDFRONT_DOMAIN_ALIAS}
  SSLCertificateARN: ${env:SSL_CERTIFICATE_ARN}

resources:
  Resources:

    # S3 Bucket
    TabMediaBucket:
      Type: AWS::S3::Bucket
      DeletionPolicy: Retain
      UpdateReplacePolicy: Retain
      Properties:
        BucketName: ${self:custom.s3Bucket}
        AccessControl: PublicRead
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: error.html

    # Bucket policy (public read)
    TabS3BucketPolicy:
      Type: AWS::S3::BucketPolicy
      DeletionPolicy: Retain
      UpdateReplacePolicy: Retain
      Properties:
        Bucket:
          Ref: TabMediaBucket
        PolicyDocument:
          Statement:
            - Sid: PublicReadGetObject
              Effect: Allow
              Principal: "*"
              Action:
                - s3:GetObject
              Resource: arn:aws:s3:::${self:custom.s3Bucket}/*

    # Serve media through Cloudfront.
    WebAppCloudFrontDistribution:
      Type: AWS::CloudFront::Distribution
      DeletionPolicy: Retain
      UpdateReplacePolicy: Retain
      Properties:
        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distributionconfig.html
        DistributionConfig:
          Origins:
            # Media S3 bucket.
            - DomainName: ${self:custom.s3Bucket}.s3.amazonaws.com
              # An identifier for the origin. This must be unique within the distribution.
              Id: ${self:custom.cloudfrontMediaName}
              CustomOriginConfig:
                HTTPPort: 80
                HTTPSPort: 443
                # HTTP only is required for S3 buckets that are configured as
                # website endpoints:
                # https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginProtocolPolicy 
                OriginProtocolPolicy: http-only
          Enabled: true
          Aliases:
            - ${self:custom.cloudfrontMediaDomainAlias}
          # Note: this is only for Cloudfront caching, not browser caching. 
          # For browser caching, we must still set Cache-Control headers
          # on the origin server (S3). This isn't yet automated for media
          # uploads; we set Cache-Control manually via the AWS CLI:
          # https://stackoverflow.com/a/29280730/1332513
          DefaultCacheBehavior:
            # Cache media files for a long time.
            DefaultTTL: 31536000 # one year
            MinTTL: 31536000 # one year
            MaxTTL: 63072000 # two years
            AllowedMethods:
              - HEAD
              - GET
              - OPTIONS
            TargetOriginId: ${self:custom.cloudfrontMediaName}
            ForwardedValues:
              QueryString: false
              Cookies:
                Forward: none
            # The protocol that users can use to access the files in the origin.
            # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-defaultcachebehavior.html#cfn-cloudfront-defaultcachebehavior-viewerprotocolpolicy
            ViewerProtocolPolicy: allow-all
          # The certificate to use when viewers use HTTPS to request objects.
          # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distributionconfig-viewercertificate.html
          ViewerCertificate:
            AcmCertificateArn: ${self:custom.SSLCertificateARN}
            SslSupportMethod: sni-only
