Search code examples
amazon-web-servicesaws-cloudformationserverlessamazon-route53

AWS Route 53 message forbidden while trying to add A record to cloud front


I am deploying a React.js application using the server less framework on cloudfront. The architecture is very simple, I have an S3 bucket and a CloudFront CDN. CloudFormation ends without any error setting up my configuration and I'm able to visit my react page using the CloudFront Distribution domain name using https and default certificate.

Now I bought a domain in Route 53 and I would like to link it to my CloudFront. I tried everything but I did not succeed. Can anyone please give me some hint? Action I already tried:

  1. Adding the certificate's are (after creating it) on my resources.CloudFrontDistribution.ViewerCertificate.AcmCertificateArn
  2. Adding manually an A record to point to my CloudFront. This generates the following JSON error on my browser: {"message":"Forbidden"}
  3. Manually adding the certificate through AWS Console on my CloudFront

None of those action gave me any hint about how to solve or even debug the problem.

This is my current serverless.yml:

service: my-app-react

provider:
  name: aws
  runtime: nodejs12.x
  region: eu-south-1
  memorySize: 512
  timeout: 6
  logRetentionInDays: 7

plugins:
  - serverless-s3-sync

custom:
  bucketName: my-app-react-33333
  s3Sync:
    - bucketName: ${self:custom.bucketName}
      localDir: build/
  domains:
    dev:
      domainName: <my-domain>
      certificateName: <my-domain>

resources:
  Resources:
    ReactAppBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.bucketName}
        AccessControl: PublicRead
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: index.html
    S3AccessPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket:
          Ref: ReactAppBucket
        PolicyDocument:
          Statement:
            - Sid: PublicReadGetObject
              Effect: Allow
              Principal: "*"
              Action:
                - s3:GetObject
              Resource:
                - arn:aws:s3:::${self:custom.bucketName}/*
    CloudFrontDistribution:
      Type: AWS::CloudFront::Distribution
      Properties:
        DistributionConfig:
          Enabled: true
          Origins:
            - DomainName: ${self:custom.bucketName}.s3.eu-south-1.amazonaws.com
              Id: ReactApp
              CustomOriginConfig:
                HTTPPort: 80
                HTTPSPort: 443
                OriginProtocolPolicy: https-only 
          DefaultRootObject: index.html
          CustomErrorResponses:
            - ErrorCode: 404
              ResponseCode: 200
              ResponsePagePath: /index.html
          DefaultCacheBehavior:
            AllowedMethods:
              - HEAD
              - GET
              - DELETE
              - OPTIONS
              - PATCH
              - POST
              - PUT
            TargetOriginId: ReactApp
            ForwardedValues:
              QueryString: false
              Cookies:
                Forward: none
            ViewerProtocolPolicy: redirect-to-https
          ViewerCertificate:
            AcmCertificateArn: <my-certificate-arn>
            SslSupportMethod: sni-only
            MinimumProtocolVersion: TLSv1.2_2021


Solution

  • Oh, now I think I may know your issue. Cluodfront distributions can only use ACM certs created in us-east-1. See Requirements for using SSL/TLS certificates with CloudFront.

    I didn't pick up on that before, but it is likely your issue. You don't have to have your distribution or any other resources there, just the certificates.

    When I create certs using cloudformation, I set up the certificate handler templates in us-east-1 and the rest of the resource templates in my local region. With terraform, as another example, I have a separate provider just for these resources.