title: How can I restrict access to an S3 website to Cloudfront?
body: <p>I want to put a Cloudfront CDN in front of a <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html" rel="nofollow noreferrer">S3 website bucket</a> for a static website, and restrict read access of the bucket to the Cloudfront distribution. Pretty common, and <a href="https://aws.amazon.com/de/premiumsupport/knowledge-center/cloudfront-serve-static-website/" rel="nofollow noreferrer">documented by AWS</a> and other sources. But for some reason I can’t get it to work.</p>
  <p>And I’m not the first one to stumble upon this. (<a href="https://stackoverflow.com/questions/14278698/restrict-access-to-website-hosted-on-s3">1</a>, <a href="https://stackoverflow.com/questions/55710926/restrict-amazon-s3-website-endpoint-to-cloudfront">2</a>, <a href="https://stackoverflow.com/questions/44952189/restrict-access-to-s3-hosted-website-without-whitelisting-ips">3</a>). I’ve tried the solutions posted there, but again, no luck.</p>
  <p>My setup, as a Cloudformation template, looks as follows:</p>
  <pre><code>AWSTemplateFormatVersion: &quot;2010-09-09&quot;
  
  Parameters:
    s3BucketName:
      Type: String
    domainName:
      Type: String
    certificateArn:
      Type: String
    bucketAuthHeader:
      Type: String
  
  Resources:
    cloudfrontDistribution:
      Type: AWS::CloudFront::Distribution
      Properties:
        DistributionConfig:
           Enabled: true
           PriceClass: PriceClass_100
           Origins:
             - Id: !Sub &quot;ID-${s3BucketName}&quot;
               DomainName: !Sub &quot;${s3BucketName}.s3-website.eu-central-1.amazonaws.com&quot;
               CustomOriginConfig:
                 OriginProtocolPolicy : http-only
               OriginCustomHeaders:
                 - HeaderName: User-Agent
                   HeaderValue: !Ref bucketAuthHeader
           DefaultCacheBehavior:
             AllowedMethods:
               - GET
               - HEAD
               - OPTIONS
             CachedMethods:
               - GET
               - HEAD
               - OPTIONS
             DefaultTTL: 600
             ForwardedValues:
                 QueryString: false
             TargetOriginId: !Sub &quot;ID-${s3BucketName}&quot;
             ViewerProtocolPolicy: redirect-to-https
  
    s3Bucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: !Ref s3BucketName
        AccessControl: Private
        PublicAccessBlockConfiguration:
          BlockPublicAcls: true
          BlockPublicPolicy: true
          IgnorePublicAcls: true
          RestrictPublicBuckets: true
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: _errors/404/index.html
      DeletionPolicy: Delete
  
    s3BucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref s3BucketName
        PolicyDocument:
          Version: 2012-10-17
          Id: &quot;Cloudfront Bucket Access&quot;
          Statement:
            - Sid: &quot;Cloudfront Bucket Access via Referer&quot;
              Effect: Allow
              Principal: &quot;*&quot;
              Action: &quot;s3:GetObject&quot;
              Resource:  !Sub &quot;arn:aws:s3:::${s3BucketName}/*&quot;
              Condition:
                StringEquals:
                  aws:UserAgent:
                    - !Ref bucketAuthHeader
  </code></pre>
  <p>However, when applying this, I cannot access files via Cloudfront, I always get a 403. I also tried tweaking values in <code>PublicAccessBlockConfiguration</code> and <code>AccessControl</code> and tried uploading bucket content with <code>aws s3 sync … --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers</code>.</p>
  <p>But I always end up with <em>either</em> public S3 content, <em>or</em> content being unavailable via Cloudfront as well.</p>
  <p>Does anybody have an idea what else I could try?</p>