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

上次更新日期: 2021 年 2 月 17 日

我使用 Amazon Simple Storage Service (Amazon S3) 儲存貯體作為 Amazon CloudFront 分佈的來源。我使用 S3 靜態網站端點作為原始網域名稱。為甚 CloudFront 會從 Amazon S3 傳回「403 存取遭拒」錯誤?

簡短描述

要對「存取遭拒」錯誤進行疑難排解,請確定分佈的原始網域名稱是 S3 網站端點還是 S3 REST API 端點。遵循以下步驟以確定端點類型:

  1. 開啟 CloudFront 主控台
  2. 選擇 CloudFront 分佈,然後選擇 Distribution Settings (分佈設定)。
  3. 選擇 Origins and Origin Groups (來源和來源群組) 標籤。
  4. 檢閱 Origin Domain Name and Path (原始網域名稱和路徑) 下的網域名稱,然後根據網域名稱的格式確定端點類型。

REST API 端點會使用此格式:

DOC-EXAMPLE-BUCKET.s3.amazonaws.com

注意:確保遵循 命名 Amazon S3 儲存貯體的規則

網站端點會使用此格式:

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

注意:取決於 AWS 區域,端點格式可能使用 Dash 格式 (s3-website-Region) 或 Dot 格式 (s3-website.Region)。

如果您的分佈使用的是 REST API 端點,請參閱我使用 S3 REST API 端點作為 CloudFront 分佈的來源。為什麼會收到「403 存取遭拒」錯誤?

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

  • 儲存貯體中的物件必須可公開存取。
  • 儲存貯體中的物件無法透過 AWS Key Management Service (AWS KMS) 加密。
  • 儲存貯體政策必須允許存取 s3:GetObject。
  • 如果儲存貯體政策授權公開讀取存取,則擁有儲存貯體的 AWS 帳戶還必須擁有物件。
  • 儲存貯體中必須存在請求的物件。
  • 儲存貯體上必須停用 Amazon S3 Block Public Access。
  • 如果啟用 Requester Pays (申請者付款),則請求必須包括 request-payer 參數。
  • 如果您使用推薦者標題來限制 CloudFront 對 S3 來源的存取,請檢閱自訂標題。

注意:如果您不想允許公開 (匿名) 存取您的 S3 物件,則變更您的設定,以使用 S3 REST API 端點作為分佈的來源。然後,設定分佈和 S3 儲存貯體,以限制使用原始存取身分 (OAI) 進行存取。如需指示,請參閱 如何使用 CloudFront 為託管在 Amazon S3 上的靜態網站提供服務? 中的使用 REST API 端點作為 OAI 有限存取的來源

解決方案

儲存貯體中的物件必須可公開存取

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

以下為 S3 物件的範例 URL:

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

如果 Web 瀏覽器或 curl 命令傳回「存取遭拒」錯誤,則物件並非可公開存取。

透過以下一種方式,允許公開存取物件:

儲存貯體中的物件不能進行 AWS KMS 加密

CloudFront 分佈不支援 AWS KMS 加密的物件。您必須從您想要使用分佈提供服務的 S3 物件中刪除 KMS 加密。

注意:不要使用 AWS KMS 加密,請使用 AES-256 加密您的物件

使用以下其中一種方式,檢查您儲存貯體中的物件是否為 KMS 加密:

若要使用 Amazon S3 主控台變更物件的加密設定,請參閱如何在 S3 物件中新增加密?

若要使用 AWS CLI 變更物件的加密設定,請先驗證物件的儲存貯體沒有預設加密。如果儲存貯體沒有愈合加密,則執行以下命令,以複製物件本身,進而刪除物件的加密:

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

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

儲存貯體政策必須允許存取 s3:GetObject

若要一起使用分佈與 S3 端點,儲存貯體政策不得包含會封鎖公開讀取存取 s3:GetObject 動作的拒絕陳述式。

即使您的儲存貯體政策中包含 s3:GetObject 的明確允許陳述式,請確認不存在衝突的明確拒絕陳述式。明確拒絕陳述式始終會覆寫明確允許陳述式。

遵循以下步驟,以檢閱 s3:GetObject 的儲存貯體政策:

1.    從 Amazon S3 主控台開啟 S3 儲存貯體。

2.    選擇 Permissions (許可) 標籤。

3.    選擇 Bucket Policy (儲存貯體政策)。

4.    檢閱含有 "Action": "s3:GetObject""Action": "s3:*" 陳述式的儲存貯體政策。

以下範例政策包含可公開存取 s3:GetObject 的明確允許陳述式。不過,s3:GetObject 還有一個可封鎖存取的明確拒絕陳述式,除非請求來自特定的 Amazon Virtual Private Cloud (Amazon VPC)。

{
    "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"
                }
            }
        }
    ]
  }

5.    修改儲存貯體政策以刪除或編輯可封鎖公開讀取存取 s3:GetObject 的陳述式。

注意:CloudFront 在錯誤快取最小 TTL 中的指定的時間內快取「存取遭拒」錯誤的結果。預設值為一分鐘。從儲存貯體中刪除拒絕陳述式後,您可以對分佈執行失效,以從快取中刪除物件。

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

若儲存貯體政策允許公開讀取存取物件,則擁有儲存貯體的 AWS 帳戶還必須擁有物件。建立儲存貯體或物件的 AWS Identity and Access Management (IAM) 身分的帳戶擁有該儲存貯體或物件。

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

遵循以下步驟,以檢查儲存貯體和物件是否具有相同的擁有者:

1.    執行此 AWS CLI 命令,以獲取儲存貯體擁有者的 S3 正式 ID:

aws s3api list-buckets --query Owner.ID

2.    執行此命令,以獲取物件擁有者的 S3 正式 ID:

注意:此範例說明單一物件,不過您可使用清單命令檢查數個物件。

aws s3api list-objects --bucket DOC-EXAMPLE-BUCKET --prefix index.html

3.    如果正式 ID 不相符,則儲存貯體和物件的擁有者不同。

注意:您可以使用 Amazon S3 主控台檢查儲存貯體和物件擁有者。擁有者位於其各自儲存貯體或物件的 Permissions (標籤) 中。

遵循以下步驟,以將物件的擁有者變更為儲存貯體擁有者:

1.    從物件擁有者的帳戶中,執行此命令,以擷取指派給物件的 ACL 許可:

aws s3api get-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name

2.    如果物件擁有 bucket-owner-full-control ACL 許可,則跳至步驟 3。如果物件未擁有 bucket-owner-full-control ACL 許可,則從物件擁有者的帳戶執行此命令:

aws s3api put-object-acl --bucket DOC-EXAMPLE-BUCKET --key object-name --acl bucket-owner-full-control

3.    從儲存貯體擁有者的帳戶,執行此命令,以複製物件本身,進而變更物件的擁有者:

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 Block Public Access

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

如果啟用 Requester Pays (申請者付款),則請求必須包括 request-payer 參數

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

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

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

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

例如,當請求包含字符串 "aws:Referer":"MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER"時,以下儲存貯體政策可授權存取 S3 來源:

{
  "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"}
      }
    }
  ]
}

利用此範例儲存貯體政策,CloudFront 來源自訂標題必須:

  • 標題:推薦者
  • 值: MY_SECRET_TOKEN_CONFIGURED_ON_CLOUDFRONT_ORIGIN_CUSTOM_HEADER

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