How to grant CloudFront access to an S3 website endpoint

0

I've created an S3 bucket and enabled static website hosting feature.

I've also created a CloudFront distribution and set the origin as an S3 website endpoint instead of an S3 regional endpoint since the CloudFront console suggested to do so.

Enter image description here

However, when I tried to access the distribution, it returned an 403 response indicates that access to bucket is denied.

You can reproduce my configuration my launching a CloudFormation stack with the following template.

AWSTemplateFormatVersion: "2010-09-09"
Description: Using CloudFront distribution

Rules:
  TestVirginia:
    Assertions:
      - AssertDescription: Only us-east-1 is allowed
        Assert:
          Fn::Equals:
            - us-east-1
            - Ref: AWS::Region

Resources:
  # S3
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::Sub: ${AWS::StackName}-s3bucket-${AWS::Region}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - BucketKeyEnabled: true
            ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      WebsiteConfiguration:
        IndexDocument: index.html

  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket:
        Ref: S3Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudfront.amazonaws.com
            Action:
              - s3:GetObject
            Resource:
              - Fn::Sub: ${S3Bucket.Arn}/*
            Condition:
              StringEquals:
                aws:SourceArn:
                  Fn::Sub: arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${Distribution}

  # CloudFront
  NoCachePolicy:
    Type: AWS::CloudFront::CachePolicy
    Properties:
      CachePolicyConfig:
        Name:
          Fn::Sub: ${AWS::StackName}-NoCachePolicy
        Comment: CloudFront no-cache policy
        DefaultTTL: 0
        MinTTL: 0
        MaxTTL: 0
        ParametersInCacheKeyAndForwardedToOrigin:
          EnableAcceptEncodingBrotli: false
          EnableAcceptEncodingGzip: false
          CookiesConfig:
            CookieBehavior: none
          HeadersConfig:
            HeaderBehavior: none
          QueryStringsConfig:
            QueryStringBehavior: none

  Distribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: CloudFront distribution
        Enabled: true
        Origins:
          - Id:
              Ref: S3Bucket
            DomainName:
              Fn::Select:
                - 1
                - Fn::Split:
                    - http://
                    - Fn::GetAtt: S3Bucket.WebsiteURL
            CustomOriginConfig:
              OriginProtocolPolicy: http-only
        DefaultCacheBehavior:
          CachePolicyId:
            Ref: NoCachePolicy
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          Compress: true
          TargetOriginId:
            Ref: S3Bucket
          ViewerProtocolPolicy: allow-all

Outputs:
  DistributionDnsName:
    Description: CloudFront distribution DNS name
    Value:
      Fn::GetAtt: Distribution.DomainName

How can I grant access for S3 bucket?

  • Thank you both for the very helpful answer.

    I finally figured out that I can only grant access to S3 website endpoint by enabling public access for S3 bucket.

    @@ -22,6 +22,11 @@ Resources:
               - BucketKeyEnabled: true
                 ServerSideEncryptionByDefault:
                   SSEAlgorithm: AES256
    +      PublicAccessBlockConfiguration:
    +        BlockPublicAcls: false
    +        BlockPublicPolicy: false
    +        IgnorePublicAcls: false
    +        RestrictPublicBuckets: false
           WebsiteConfiguration:
             IndexDocument: index.html
     
    @@ -34,16 +39,11 @@ Resources:
             Version: "2012-10-17"
             Statement:
               - Effect: Allow
    -            Principal:
    -              Service: cloudfront.amazonaws.com
    +            Principal: "*"
                 Action:
                   - s3:GetObject
                 Resource:
                   - Fn::Sub: ${S3Bucket.Arn}/*
    -            Condition:
    -              StringEquals:
    -                aws:SourceArn:
    -                  Fn::Sub: arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${Distribution}
  • A better way is to use S3 origin type, attach an OAC, and disable website hosting for S3 to suppress the warning.

    @@ -22,8 +22,6 @@ Resources:
               - BucketKeyEnabled: true
                 ServerSideEncryptionByDefault:
                   SSEAlgorithm: AES256
    -      WebsiteConfiguration:
    -        IndexDocument: index.html
     
       S3BucketPolicy:
         Type: AWS::S3::BucketPolicy
    @@ -66,6 +64,17 @@ Resources:
               QueryStringsConfig:
                 QueryStringBehavior: none
     
    +  OriginAccessControl:
    +    Type: AWS::CloudFront::OriginAccessControl
    +    Properties:
    +      OriginAccessControlConfig:
    +        Name:
    +          Fn::Sub: ${AWS::StackName}-OriginAccessControl
    +        Description: Origin access control for S3
    +        OriginAccessControlOriginType: s3
    +        SigningBehavior: always
    +        SigningProtocol: sigv4
    +
       Distribution:
         Type: AWS::CloudFront::Distribution
         Properties:
    @@ -76,13 +85,11 @@ Resources:
               - Id:
                   Ref: S3Bucket
                 DomainName:
    -              Fn::Select:
    -                - 1
    -                - Fn::Split:
    -                    - http://
    -                    - Fn::GetAtt: S3Bucket.WebsiteURL
    -            CustomOriginConfig:
    -              OriginProtocolPolicy: http-only
    +              Fn::GetAtt: S3Bucket.RegionalDomainName
    +            OriginAccessControlId:
    +              Ref: OriginAccessControl
    +            S3OriginConfig:
    +              OriginAccessIdentity: ""
             DefaultCacheBehavior:
2 Answers
2
Accepted Answer

This is the CloudFormation template that I've used - it creates a CloudFront Origin Access Control identity to connect to the S3 bucket:

  S3BucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Statement:
        - Action: 's3:GetObject'
          Effect: Allow
          Resource: !Sub 'arn:aws:s3:::${S3Bucket}/*'
          Principal:
            Service: cloudfront.amazonaws.com
          Condition:
            StringEquals:
              AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}

  CloudFrontOriginAccessControl:
    Type: AWS::CloudFront::OriginAccessControl
    Properties:
      OriginAccessControlConfig:
        Description: !Sub ${AWS::StackName} Origin Access Control
        Name: !Ref AWS::StackName
        OriginAccessControlOriginType: s3
        SigningBehavior: always
        SigningProtocol: sigv4

  CloudFrontDistribution:
    Type: 'AWS::CloudFront::Distribution'
    Properties:
      DistributionConfig:
        Comment: DistributionNameGoesHere
        DefaultRootObject: index.html
        Enabled: true
        HttpVersion: http2
        Origins:
        - DomainName: !GetAtt S3Bucket.RegionalDomainName
          Id: s3origin
          OriginPath: /static
          S3OriginConfig:
            OriginAccessIdentity: ''
          OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
        PriceClass: 'PriceClass_All'
        DefaultCacheBehavior:
          AllowedMethods:
          - GET
          - HEAD
          - OPTIONS
          TargetOriginId: s3origin
          ViewerProtocolPolicy: redirect-to-https
          ForwardedValues:
            QueryString: 'false'
            Cookies:
              Forward: none
profile pictureAWS
EXPERT
answered 7 months ago
profile pictureAWS
EXPERT
reviewed 7 months ago
  • Thanks for the help. I works if I change its origin type to S3 (the S3 regional endpoint) and attach an OAC to it.

    But CloudFront console is warning me to switch to S3 website endpoint with the following message:

    This S3 bucket has static web hosting enabled. If you plan to use this distribution as a website, we recommend using the S3 website endpoint rather than the bucket endpoint.

    When I follow the suggestion, OAC is no longer working. Is there a way to grant access with the distribution origin configured as suggested S3 website endpoint or the CloudFront console is suggesting nonsense?

  • You don't need to enable website hosting in S3 to make this work. In my experience if you run this template it may take a little while for things to work correctly. If you deploy it and go to CloudFront and get "access denied" and the URL has changed to a S3 URL (rather than CloudFront) then just wait.

0

Here is a great official troubleshooting guide that you may find helpful. It describes how to troubleshoot the most common scenarios where a user receives a 403 error from a CloudFront distribution with an S3 website endpoint as the origin.

AWS
Max
answered 7 months ago
  • Thanks for the guide! Very helpful, but unable to find answers there.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions