Sửa lỗi AWS CloudFront 403 ERROR trên S3 Origin — OAC Bucket Policy Chưa Được Cấu Hình

intermediate☁️ AWS2026-04-28| AWS CloudFront + S3, OAC (Origin Access Control), mọi region, AWS Console / AWS CLI v2

Error Message

403 ERROR: The request could not be satisfied. Request blocked. We can't connect to the server for this app or website at this time.
#cloudfront#s3#oac#bucket-policy#403

Chuyện gì đang xảy ra

Bạn đã thiết lập một CloudFront distribution trỏ đến một S3 bucket, chọn Origin Access Control (OAC) làm phương thức truy cập, và bây giờ mọi request đều gặp lỗi này:

403 ERROR: The request could not be satisfied.
Request blocked. We can't connect to the server for this app or website at this time.

Không có gì tải được. Truy cập trực tiếp S3 vẫn hoạt động bình thường khi bucket ở chế độ public — nhưng CloudFront không thể kết nối được.

OAC đã thay thế Origin Access Identity (OAI) cũ hơn từ năm 2022. OAC bảo mật hơn, nhưng yêu cầu một bucket policy cụ thể mà hầu hết các hướng dẫn bỏ qua hoặc làm sai. Nếu không có policy này, S3 sẽ coi mọi request từ CloudFront là ẩn danh và trả về 403. Chỉ vậy thôi. Đó là toàn bộ vấn đề.

Nguyên nhân gốc rễ

Khi OAC được gắn vào, CloudFront ký các request tới S3 bằng SigV4. S3 cần một bucket policy rõ ràng nêu rằng: "chỉ cho phép s3:GetObject khi request đến từ đúng CloudFront distribution này." Không có policy thì không có quyền truy cập — dù OAC đã được cấu hình đúng ở phía CloudFront.

Các lỗi phổ biến dẫn đến tình trạng này:

  • OAC đã được thiết lập trong CloudFront nhưng bucket policy chưa bao giờ được cập nhật
  • Policy vẫn tham chiếu đến một OAI (arn:aws:iam::cloudfront:user/...) thay vì điều kiện OAC
  • Block Public Access đang được bật nhưng không có policy nào cấp quyền truy cập cho CloudFront
  • Policy sử dụng sai ARN của CloudFront distribution

Bước 1 — Xác nhận distribution đang dùng OAC

Mở CloudFront console → distribution của bạn → tab Origins → nhấp vào S3 origin → kiểm tra Origin access. Mục này phải hiển thị Origin access control settings (recommended) kèm tên OAC. Không phải "Public", không phải OAI.

Qua CLI:

aws cloudfront get-distribution-config --id YOUR_DISTRIBUTION_ID \
  --query 'DistributionConfig.Origins.Items[0].S3OriginConfig'

Nếu OriginAccessIdentity trống và OAC xuất hiện dưới OriginAccessControlId, nghĩa là OAC đang hoạt động.

Bước 2 — Kiểm tra bucket policy hiện tại

aws s3api get-bucket-policy --bucket YOUR_BUCKET_NAME --query Policy --output text | python3 -m json.tool

Output trống? Đó là câu trả lời của bạn. Nếu bạn thấy một principal như arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ..., policy vẫn đang trỏ đến OAI — sẽ không hoạt động với OAC.

Bước 3 — Áp dụng bucket policy OAC đúng

Cách khắc phục là tạo bucket policy cấp s3:GetObject cho service principal của CloudFront, giới hạn trong distribution cụ thể của bạn.

Trước tiên, lấy ARN của distribution:

aws cloudfront get-distribution --id YOUR_DISTRIBUTION_ID \
  --query 'Distribution.ARN' --output text

Trông như thế này: arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE

Tạo file policy:

cat > bucket-policy.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontOAC",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
        }
      }
    }
  ]
}
EOF

Áp dụng policy:

aws s3api put-bucket-policy \
  --bucket YOUR_BUCKET_NAME \
  --policy file://bucket-policy.json

Bước 4 — Giữ nguyên Block Public Access

Đừng tắt Block Public Access để "sửa" lỗi 403. Đó là cách làm sai. OAC được tạo ra chính xác để bạn có thể giữ cả bốn cờ Block Public Access ở trạng thái BẬT trong khi CloudFront vẫn phục vụ nội dung.

Kiểm tra:

aws s3api get-public-access-block --bucket YOUR_BUCKET_NAME

Cả bốn cờ phải là true. Nếu bạn đã tắt chúng, hãy bật lại — policy OAC đã xử lý quyền truy cập mà không cần public access.

Bước 5 — Xóa cache CloudFront

CloudFront có thể đã cache lại response 403. Buộc làm mới cache:

aws cloudfront create-invalidation \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --paths "/*"

Kiểm tra trạng thái (thường hoàn thành trong 30–60 giây):

aws cloudfront list-invalidations \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --query 'InvalidationList.Items[0].Status'

Xác nhận kết quả

Chạy lệnh curl nhanh để kiểm tra response headers:

curl -I https://YOUR_CLOUDFRONT_DOMAIN/your-file.html

Bạn sẽ thấy HTTP/2 200 với x-cache: Miss from cloudfront ở lần truy cập đầu tiên, rồi Hit from cloudfront ở các lần tiếp theo.

Hãy thử truy cập một đường dẫn mà bạn biết là không tồn tại. S3 sẽ trả về 404, không phải 403. Lỗi 404 trên các file không tồn tại xác nhận policy đang hoạt động đúng — và không bị cấp quyền quá mức.

Thích dùng giao diện hơn CLI? Dùng phím tắt trên console

AWS Console có một phím tắt tích hợp giúp bỏ qua toàn bộ việc viết JSON thủ công. Vào CloudFront distribution → Origins → chỉnh sửa S3 origin → kéo xuống phần OAC → nhấp "Copy policy". Sau đó mở S3 → Permissions → Bucket Policy → dán vào và lưu lại. AWS tự động tạo ra policy chính xác cho distribution của bạn.

Các trường hợp đặc biệt cần kiểm tra

  • Cấu hình đa vùng: S3 bucket ở ap-southeast-1, CloudFront edge ở us-east-1? Hãy đảm bảo hành vi ký của OAC được đặt thành Sign requests (recommended) — không phải "Do not sign".
  • Object được mã hóa bằng SSE-KMS: KMS key do khách hàng quản lý yêu cầu thêm một bước. CloudFront cần quyền kms:Decrypt trong KMS key policy. OAC hỗ trợ điều này, nhưng bạn phải thêm vào một cách tường minh.
  • Statement OAI còn sót lại: Nếu policy OAI cũ vẫn còn đó, hãy xóa nó đi. Có cả statement OAI lẫn OAC trong cùng một policy không làm hỏng gì, nhưng sẽ gây nhầm lẫn cho mọi người trong team — kể cả chính bạn sau này.

Related Error Notes