CloudFront 分发无法访问网站静态资产的 S3 存储桶

CloudFront 分发无法访问网站静态资产的 S3 存储桶

问题

我正在尝试部署一个托管我的静态网站资产的 S3 存储桶和一个 cloudfront 分发版来访问它,但该分发版仍然返回一个裸 xml 文件,出现“访问被拒绝”错误:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>5N0Z412GZ0VGV79E</RequestId>
  <HostId>GkpQbOpKeDiaCdFJM7kDq6ouWL/dvdijNu7NseC7KeIIogNabowVrDcfjPZ0xajKpDTx3SmgoEI=</HostId>
</Error>

作为本文档页面蓝色通知警报中显示,我尚未将存储桶设为网站端点,这样我可以使用 OAC 来限制对其内容的访问。

奇怪的是,从 Web 控制台检查分发来源时我看到了这个蓝色警报,但可复制策略与我在给定链接的存储桶权限中找到的策略相同。

在此处输入图片描述

我在部署期间没有遇到任何错误,所以这一定是一个愚蠢的配置错误,但一周以来它一直让我头疼,我不知道哪里出了问题。

Bucket 和对象所有者对应

由于我的网站资产是从不同的项目/管道上传到存储桶的,所以我遵循检查存储桶和对象所有者是否不同但实际上对应的指南:

> aws s3api list-buckets --query Owner.ID
"3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72"

> aws s3api list-objects --bucket my-test-bucket --prefix index.html
{
    "Contents": [
        {
            "Key": "index.html",
            "LastModified": "2023-01-20T11:05:38+00:00",
            "ETag": "\"52f2df5ddf8c35391f3f15a7614def58\"",
            "Size": 325,
            "StorageClass": "STANDARD",
            "Owner": {
                "ID": "3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72"
            }
        }
    ]
}

CloudFormation 模板

Resources:

  BucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    DependsOn:
      - AppBucket
      - CloudFrontDistribution
    Properties:
      Bucket: !Ref AppBucket
      PolicyDocument:
        Id: MyPolicy
        Version: '2012-10-17'
        Statement:
          Sid: PolicyForCloudFrontPrivateContent
          Action: s3:GetObject
          Effect: Allow
          Principal:
            Service: cloudfront.amazonaws.com
          Condition:
            StringEquals:
              AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
          Resource: !Sub arn:aws:s3:::${AppBucket}/*

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    DependsOn:
      - AppBucket
      - DefaultCachePolicy
      - DistributionOAC
    Properties:
      DistributionConfig:
        Enabled: true
        Origins:
          - Id: AppBucket
            DomainName: !GetAtt AppBucket.DomainName
            OriginPath: /*
            S3OriginConfig: {}
            OriginAccessControlId: !Ref DistributionOAC
        DefaultRootObject: index.html
        DefaultCacheBehavior:
          ViewerProtocolPolicy: redirect-to-https
          TargetOriginId: AppBucket
          CachePolicyId: !Ref DefaultCachePolicy

  DistributionOAC:
    Type: AWS::CloudFront::OriginAccessControl
    Properties: 
      OriginAccessControlConfig: 
          Name: ExampleOAC
          OriginAccessControlOriginType: s3
          SigningBehavior: always
          SigningProtocol: sigv4

  AppBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: 'test-spa-stack-bucket-app'
      PublicAccessBlockConfiguration:
        BlockPublicAcls : false
        BlockPublicPolicy : false
        IgnorePublicAcls : false
        RestrictPublicBuckets : false
              
  DefaultCachePolicy:
    Type: AWS::CloudFront::CachePolicy
    Properties: 
      CachePolicyConfig: 
        Name: test-cache-policy
        DefaultTTL: 10
        MaxTTL: 10
        MinTTL: 1
        ParametersInCacheKeyAndForwardedToOrigin: 
            CookiesConfig: 
              CookieBehavior: none
            EnableAcceptEncodingBrotli: true
            EnableAcceptEncodingGzip: true
            HeadersConfig: 
              HeaderBehavior: none
            QueryStringsConfig: 
              QueryStringBehavior: none

答案1

我遇到了同样的错误。就我而言,我已将 Distribution 上的默认根对象(常规 > 设置)设置为 /index.html,还将源路径(源 > 我的 s3 源)设置为 /index.html。我只需在 Distribution 上将对象设置为 index.html,它就会开始按预期响应。

这帮助我发现了问题。

答案2

好的,我找到了YouTube 视频它可从云控制台运行,然后我通过 CloudFormation 堆栈模板复制它。

我认为我的问题可能是由以下任一配置引起的:

  • 存储桶加密:我在某处读到(抱歉,我找不到确切的页面),如果使用与 SSE-S3 不同的任何方式加密,CloudFront 分发版将无法(直接)读取存储桶对象,而且由于我省略了该配置,因此它可能确实回退到了不兼容的配置上
  • 对象所有权:这里我也忘了添加cuket owner enforced策略
  • 分发接受的 http 版本:这里我接受了 v.2

工作模板

Resources:
  BucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    DependsOn:
      - AppBucket
      - CloudFrontDistribution
    Properties:
      Bucket: !Ref AppBucket
      PolicyDocument:
        Id: PolicyForCloudFrontPrivateContent
        Version: '2008-10-17'
        Statement:
          Sid: AllowCloudFrontServicePrincipal
          Action: s3:GetObject
          Effect: Allow
          Principal:
            Service: cloudfront.amazonaws.com
          Condition:
            StringEquals:
              AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
          Resource: !Sub arn:aws:s3:::${AppBucket}/*

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    DependsOn:
      - AppBucket
      - DistributionOAC
      - LogsBucket
    Properties:
      DistributionConfig:
        Enabled: true
        HttpVersion: http2
        Origins:
          - Id: AppBucket
            DomainName: !GetAtt AppBucket.DomainName
            S3OriginConfig: {}
            OriginAccessControlId: !Ref DistributionOAC
        DefaultRootObject: index.html
        DefaultCacheBehavior:
          Compress: true
          ViewerProtocolPolicy: allow-all
          TargetOriginId: AppBucket
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6   # default CachingOptimized
        Logging:
          Bucket: !GetAtt LogsBucket.DomainName
          IncludeCookies: true
          Prefix: distribution/

  AppBucket:
    Type: 'AWS::S3::Bucket'
    DependsOn:
      - LogsBucket
    Properties:
      BucketName: 'test-spa-stack-bucket-app'
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      PublicAccessBlockConfiguration:
        BlockPublicAcls : true
        BlockPublicPolicy : true
        IgnorePublicAcls : true
        RestrictPublicBuckets : true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LoggingConfiguration:
        DestinationBucketName: !Ref LogsBucket
        LogFilePrefix: app/

  DistributionOAC:
    Type: AWS::CloudFront::OriginAccessControl
    Properties: 
      OriginAccessControlConfig: 
          Name: test-spa-distribution-oac
          OriginAccessControlOriginType: s3
          SigningBehavior: always
          SigningProtocol: sigv4


  LogsBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: 'test-spa-stack-bucket-logs'
      PublicAccessBlockConfiguration:
        BlockPublicAcls : true
        BlockPublicPolicy : true
        IgnorePublicAcls : true
        RestrictPublicBuckets : true
      AccessControl: LogDeliveryWrite
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
        - ServerSideEncryptionByDefault:
            SSEAlgorithm: 'AES256'

相关内容