我使用 S3 網站端點作為 CloudFront 分佈的來源。為什麼會收到「403 存取遭拒」錯誤?

上次更新日期:2022 年 5 月 13 日

我使用 Amazon Simple Storage Service (Amazon S3) 儲存貯體作為 Amazon CloudFront 分佈的來源。我如何對「403 存取遭拒」錯誤進行疑難排解?

簡短描述

要對「存取遭拒」錯誤進行疑難排解,請先確定分佈的原始網域名稱是 S3 網站端點還是 S3 REST API 端點。然後,如果您的分發使用網站端點,請檢閱疑難排解部分。

解決方案

確定分佈原始網域名稱的端點類型

  1. 開啟 CloudFront 主控台
  2. 選擇您的 CloudFront 分佈。然後,選擇分佈設定
  3. 選擇來源和來源群組索引標籤。
  4. 檢閱原始網域名稱和路徑下的網域名稱。根據網域名稱的格式確定端點類型:

Rest API 端點使用以下格式:

DOC-EXAMPLE-BUCKET.s3.amazonaws.com

網站端點使用下列格式:

DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com

注意:視乎 AWS 區域,端點格式可以使用破折號格式 (s3-website-Region) 或點格式 (s3-website.Region)。如果您的分佈使用 REST API 端點,請參閲 我正在使用 S3 REST API 端點作為我的 CloudFront 分佈的來源。為什麼會收到「403 存取遭拒」錯誤?

如果您的分佈使用網站端點,請驗證以下區段中的要求以避免「存取遭拒」錯誤。

確認儲存貯體中的物件未由 AWS Key Management Service (AWS KMS) 加密

CloudFront 分佈不支援 AWS KMS 加密的物件。您必須從要使用分佈提供服務的 S3 物件中移除 KMS 加密。使用 AES-256 來加密您的物件,而不是使用 AWS KMS 加密。

確定物件是否採用 AWS KMS 加密

若要檢查儲存貯體中的物件是否採用 KMS 加密:

使用 Amazon S3 主控台檢視物件的屬性。檢閱加密對話方塊。如果選取了 AWS-KMS,則該物件為 KMS 加密。

-或-

使用 AWS Command Line Interface (AWS CLI) 執行 head-object 命令。如果命令以 aws:kms 的形式傳回 ServerSideEncryption,則該物件為 KMS 加密。
注意:如果您在執行 AWS CLI 命令時收到錯誤,請確保您使用的是最新版 AWS CLI

變更物件的加密設定

若要使用 Amazon S3 主控台變更物件的加密設定,請參閲使用 AWS KMS (SSE-KMS) 指定伺服器端加密

若要使用 AWS CLI 變更物件的加密設定,請首先確認物件的儲存貯體沒有預設加密。如果儲存貯體沒有預設加密,則執行以下命令,以複製物件本身,進而刪除物件的加密。將 DOC-EXAMPLE-BUCKET 取代為您的儲存貯體名稱:

aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html

警告:複製物件本身即可移除 storage-classwebsite-redirect-location 的設定。若要在新物件中維持這些設定,請務必在複製請求中明確指定這些值。

確認 s3: GetObject 動作的儲存貯體政策中沒有明確的「拒絕」

您的儲存貯體政策不得有拒絕陳述式會封鎖 s3:GetObject 動作的公開讀取存取權。

如果儲存貯體政策中有 s3:GetObject 的明確允許語句,請確認沒有衝突的明確拒絕語句。明確拒絕語句將始終覆寫明確允許語句。

若要檢閱 s3:GetObject 的儲存貯體政策,請執行下列動作:

  1. Amazon S3 主控台開啟 S3 儲存貯體。
  2. 選擇許可索引標籤。
  3. 選擇儲存貯體政策
  4. 檢閱儲存貯體政策,以了解包含 "Action": "s3:GetObject" 或 "Action": "s3:*" 的語句。
  5. 修改儲存貯體政策,以移除或編輯阻止對 s3:GetObject 的公有讀取存取權的語句。

例如,以下政策包含適用於對 s3:GetObject 的公有存取的明確允許語句。不過,該政策還包含一個 s3:GetObject 存取的明確拒絕陳述式,除非請求來自特定的 Amazon Virtual Private Cloud (Amazon VPC)。必須修改此政策才能允許 s3:GetObject 動作。

{
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [
    {
      "Sid": "Allow-OAI-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EAF5XXXXXXXXX"
      },
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Allow-Public-Access-To-Bucket",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ]
    },
    {
      "Sid": "Access-to-specific-VPCE-only",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:sourceVpce": "vpce-1a2b3c4d"
        }
      }
    }
  ]
}

如果儲存貯體政策授權公開讀取存取,請確認擁有儲存貯體的 AWS 帳戶還擁有物件

若儲存貯體政策允許公開讀取存取物件,則擁有儲存貯體的 AWS 帳戶還必須擁有物件。對於具有預設物件擁有權設定的現有 Amazon S3 儲存貯體,物件擁有者是將物件上傳到儲存貯體的 AWS Identity and Access Management (IAM) 身分的 AWS 帳戶。

注意:物件擁有權要求適用於儲存貯體政策授予的公有讀取存取權。它不適用於由物件的存取控制清單 (ACL) 授予的公有讀取存取權。

確認儲存貯體和物件具備相同的擁有者

使用以下步驟檢查儲存貯體和物件是否具有相同的擁有者。您還可以使用 Amazon S3 主控台來檢查儲存貯體和物件擁有者。擁有者可在相應儲存貯體或物件的許可索引標籤中找到。

  1. 執行如下 AWS CLI 命令,以獲取儲存貯體擁有者的 S3 正式 ID:
aws s3api list-buckets --query Owner.ID
  • 執行如下命令以取得物件擁有者的 S3 正式 ID:
  • aws s3api list-objects --bucket DOC-EXAMPLE-BUCKET --prefix index.html
    此範例顯示了單一物件,但您可以使用 list 命令來檢查多個物件。
  • 如果正式 ID 不相符,則儲存貯體和物件具有不同的擁有者。
  • 更新物件擁有權

    儲存貯體擁有者可以使用 S3 物件擁有權管理物件的擁有權。預設情況下,所有新的 S3 儲存貯體都會啟用強制執行儲存貯體擁有者設定。若要更新現有儲存貯體,請參閱設定現有儲存貯體的物件擁有權。開啟強制執行儲存貯體擁有者設定時,儲存貯體擁有者就是儲存貯體內所有物件的擁有者。此外,當強制執行儲存貯體擁有者設定開啟時,儲存貯體上的任何 ACL 及其物件都會停用。

    最佳實務是儲存貯體擁有者在所有儲存貯體上使用強制執行儲存貯體擁有者設定,並透過 IAM 和儲存貯體政策管理許可。

    若要移除儲存貯體的 ACL 並取得儲存貯體中所有物件的擁有權,請執行下列命令:

    aws s3api put-bucket-ownership-controls --bucket example-bucket --ownership-controls 'Rules=[{ObjectOwnership=BucketOwnerEnforced}]'
    如果您不想停用 S3 儲存貯體上的 ACL,也可以依照下列步驟將物件的擁有者變更為儲存貯體擁有者:
    1. 從物件擁有者的帳戶中,執行此命令,以擷取指派給物件的 ACL 許可:
    aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name
  • 如果物件擁有 bucket-owner-full-control ACL 許可,則跳至步驟 3。如果物件未擁有 bucket-owner-full-control ACL 許可,則從物件擁有者的帳戶執行以下命令。將 DOC-EXAMPLE-BUCKET 取代為您的儲存貯體名稱。
  • aws s3api put-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name --acl bucket-owner-full-control
  • 從儲存貯體擁有者的帳戶,執行如下命令,以複製物件本身,進而變更物件的擁有者。將 DOC-EXAMPLE-BUCKET 取代為您的儲存貯體名稱。
  • aws s3 cp s3://DOC-EXAMPLE-BUCKET/index.html s3://DOC-EXAMPLE-BUCKET/index.html

    確認要求的物件存在於儲存貯體中

    如果使用者未擁有 S3:ListBucket 許可,則使用者會收到缺失物件的「存取遭拒」錯誤,而非「404 找不到」錯誤。執行 head-object AWS CLI 命令來檢查儲存貯體中是否存在物件。

    注意:確認傳送至 CloudFront 的物件請求與 S3 物件名稱完全相符。S3 物件名稱區分大小寫。如果請求沒有正確的物件名稱,則 Amazon S3 會回應為「缺失物件」。若要識別 CloudFront 從 Amazon S3 請求的物件,請使用伺服器存取日誌記錄

    如果儲存貯體中存在物件,則「存取遭拒」錯誤不會遮罩「404 找不到」錯誤。確認其他組態需求,以解決「存取遭拒」錯誤。

    如果儲存貯體中沒有物件,則「存取遭拒」錯誤會遮罩「404 找不到」錯誤。解決與遺失物件相關的問題。

    注意:啟動公有 s3:ListBucket 存取權並非安全最佳實務。啟用公有 s3:ListBucket 存取允許使用者查看並列出儲存貯體中的所有物件。即使使用者沒有下載物件的許可,這也會向使用者公開物件中繼資料詳細資訊 (例如,金鑰和大小)。

    確認已關閉儲存貯體的 Amazon S3 區塊公開存取

    確認沒有任何 Amazon S3 Block Public Access 設定套用於儲存貯體。這些設定可覆寫允許公有讀取存取的許可。Amazon S3 Block Public Access 設定可套用至個別的儲存貯體或 AWS 帳戶。

    確認儲存貯體中的物件可公開存取

    使用網站端點的分佈僅支援可公開存取的內容。要確定 S3 儲存貯體中的物件是否可公開存取,請在 Web 瀏覽器中開啟物件的 URL。或者,您可以在 URL 上執行 curl 命令。

    例如:

    http://DOC-EXAMPLE-BUCKET.s3-website-us-east-1.amazonaws.com/index.html

    如果 Web 瀏覽器或 curl 命令傳回「存取遭拒」錯誤,則無法公有存取該物件。

    若要允許公有讀取存取權:

    建立允許對儲存貯體中所有物件進行公有讀取存取的儲存貯體政策。

    -或-

    使用 Amazon S3 主控台允許對物件的公有讀取存取權

    如果已開啟申請者付款,請確認請求包含 request-payer 參數

    如果針對儲存貯體開啟申請者付款,則不允許匿名存取儲存貯體。其他帳戶的使用者在傳送請求至儲存貯體時,必須指明 request-payer 參數。否則,這些使用者會收到「存取遭拒」錯誤。

    如果您使用推薦者標題來限制 CloudFront 對 S3 來源的存取,請檢閱自訂標題

    如果您使用推薦者標題來限制 CloudFront 對 S3 網站端點來源的存取,請檢查 S3 儲存貯體政策中設定的秘密值或字符。然後,確認機密值或字符與 CloudFront 來源自訂標頭上的值相符。

    如果您在儲存貯體政策中使用明確拒絕陳述式,則請確認還有一個可根據推薦者標題授權存取的允許陳述式。您無法僅使用明確拒絕語句來授予存取權。

    例如,當請求包含字串 "aws:Referer":"MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER" 時,以下儲存貯體政策可授權存取 S3 來源。
    CloudFront 來源自訂標頭必須是:

    • Header: Referer
    • Value: MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER
    {
      "Version":"2012-10-17",
      "Id":"http referer policy example",
      "Statement":[
        {
          "Sid":"Allow get requests originating from my CloudFront with referer header",
          "Effect":"Allow",
          "Principal":"*",
          "Action":"s3:GetObject",
          "Resource":"arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
          "Condition":{
            "StringLike":{"aws:Referer":"MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER"}
          }
        }
      ]
    }

    注意:範例儲存貯體政策授予對儲存貯體的公有 (匿名) 存取權,因為主體為萬用字元值 ("Principal":"*")。但是,由於條件陳述式,只有當請求包含「推薦者」標題並且標題值與儲存貯體政策中的值相符時,才會授權存取 S3 來源。

    確認您組織的管理帳戶沒有附加明確的「拒絕」服務控制政策 (SCP)

    服務控制政策 (SCP) 是一種組織政策,可用來管理組織中的許可。使用您組織在 AWS Organizations 中的管理帳戶,檢查是否有連接至組織根目錄、組織單位 (OU) 或直接連接到 AWS 帳戶的拒絕政策 (適用於 s3:GetObject 動作)。