S3 'Access Denied' Khi Truy Cập URL Công Khai: Block Public Access Đang Chặn Bạn
Bạn upload một file ảnh lên S3, set ACL thành public-read, copy URL ra trình duyệt — và nhận về một trang XML lạnh lùng: 'Access Denied'. Đây là một trong những tình huống gây bực bội nhất khi mới làm việc với S3, và nguyên nhân gần như luôn nằm ở cơ chế Block Public Access hoạt động ở nhiều tầng độc lập nhau.
TL;DR — Tóm Tắt Nhanh
| Tầng kiểm soát | Vị trí | Ghi đè ACL object? |
|---|---|---|
| Block Public Access (Account) | S3 Console → Account settings | Có — chặn toàn bộ |
| Block Public Access (Bucket) | S3 Console → Bucket → Permissions | Có — chặn bucket đó |
| Bucket Policy | Bucket → Permissions → Bucket policy | Phụ thuộc nội dung policy |
| Object ACL | Object → Permissions | Chỉ có hiệu lực nếu các tầng trên cho phép |
Block Public Access Hoạt Động Như Thế Nào
Nhiều người hình dung S3 permission như một lớp duy nhất: set object thành public là xong. Thực tế, AWS áp dụng mô hình phân tầng — mỗi tầng có thể độc lập chặn truy cập công khai, bất kể các tầng bên dưới cấu hình gì.
- Account-level Block Public Access: Cài đặt toàn tài khoản, áp dụng cho mọi bucket. Nếu bật ở đây, không bucket nào trong account có thể public — dù bucket policy hay ACL có cho phép.
- Bucket-level Block Public Access: Áp dụng riêng cho từng bucket. Có 4 cờ độc lập, mỗi cờ kiểm soát một loại truy cập khác nhau.
- Bucket Policy: Nếu Block Public Access không chặn, bucket policy được đánh giá tiếp theo.
- Object ACL: Tầng cuối cùng — chỉ có tác dụng khi tất cả các tầng trên đã cho phép.
Hãy hình dung Block Public Access như một công tắc tổng ở bảng điện — dù bạn đã bật từng ổ cắm riêng lẻ (ACL object), nếu công tắc tổng ngắt, không ổ cắm nào hoạt động.
Điểm quan trọng: BlockPublicAcls và IgnorePublicAcls là hai cờ khác nhau. BlockPublicAcls ngăn việc đặt ACL public mới, còn IgnorePublicAcls khiến AWS bỏ qua mọi ACL public đã tồn tại khi đánh giá truy cập. Nếu IgnorePublicAcls đang bật, object ACL public-read của bạn hoàn toàn vô hiệu.
Chẩn Đoán S3 Access Denied — Từng Bước
Bước 1: Kiểm tra Block Public Access ở cấp Account
Đây là tầng bị bỏ qua nhiều nhất. Khi tạo tài khoản AWS mới, Block Public Access được bật mặc định ở cấp account — nghĩa là mọi cấu hình public ở bucket hay object đều bị vô hiệu hóa ngay lập tức. Kiểm tra trạng thái hiện tại:
aws s3control get-public-access-block \
--account-id 123456789012
Nếu output trả về bất kỳ cờ nào là true, đó là nguyên nhân gốc rễ. Để tắt toàn bộ ở cấp account (chỉ làm nếu bạn hiểu rõ tác động):
aws s3control put-public-access-block \
--account-id 123456789012 \
--public-access-block-configuration \
BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
Bước 2: Kiểm tra Block Public Access ở cấp Bucket
Ngay cả khi cấp account đã thông, bucket vẫn có thể có cờ riêng. Bucket-level settings ghi đè lên ACL và bucket policy của chính bucket đó:
aws s3api get-public-access-block \
--bucket ten-bucket-cua-ban
Nếu IgnorePublicAcls là true, ACL public-read trên object của bạn đang bị bỏ qua hoàn toàn. Tắt cờ này ở cấp bucket:
aws s3api put-public-access-block \
--bucket ten-bucket-cua-ban \
--public-access-block-configuration \
BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
Bước 3: Xác nhận Object ACL thực sự là public-read
Sau khi các tầng Block Public Access đã được gỡ, kiểm tra xem ACL trên object có thực sự được set đúng không — đặc biệt nếu object được upload trước khi bạn thay đổi cấu hình bucket:
aws s3api get-object-acl \
--bucket ten-bucket-cua-ban \
--key duong-dan/ten-file.jpg
Tìm trong output một grant có Grantee.URI là http://acs.amazonaws.com/groups/global/AllUsers và Permission là READ. Nếu không có, set lại:
aws s3api put-object-acl \
--bucket ten-bucket-cua-ban \
--key duong-dan/ten-file.jpg \
--acl public-read
Bước 4: Kiểm tra Bucket Policy có đang chặn không
Nếu bucket có một policy với Deny statement — kể cả Deny có điều kiện — nó có thể ghi đè Allow từ ACL. Explicit Deny luôn thắng trong mô hình IAM của AWS:
aws s3api get-bucket-policy \
--bucket ten-bucket-cua-ban
Tìm bất kỳ "Effect": "Deny" nào áp dụng cho s3:GetObject với Principal là * hoặc anonymous users. Nếu RestrictPublicBuckets đang bật, AWS cũng sẽ chặn mọi cross-account và anonymous access dù bucket policy có Allow.
Trường Hợp Thực Tế: Misdiagnosis Phổ Biến Nhất
Tình huống điển hình: bạn vào S3 Console, tắt Block Public Access ở bucket, set ACL object thành public-read, thử lại URL — vẫn 'Access Denied'. Bạn kiểm tra lại bucket settings, mọi thứ trông đúng. Bạn bắt đầu nghi ngờ CloudFront, nghi ngờ cache, nghi ngờ đủ thứ.
Nguyên nhân thực tế: Block Public Access ở cấp account vẫn đang bật. Console S3 khi bạn vào bucket chỉ hiển thị bucket-level settings — account-level settings nằm ở một trang hoàn toàn khác: S3 Console → Block Public Access settings for this account. Hai trang này trông giống nhau nhưng kiểm soát hai tầng độc lập.
Đây là lý do bước 1 phải luôn là account-level — không phải bucket-level.
Cách Tiếp Cận Được Khuyến Nghị: Dùng Bucket Policy Thay Vì ACL
AWS hiện khuyến nghị sử dụng bucket policy để cấp quyền public thay vì ACL object, đặc biệt sau khi S3 Object Ownership mặc định chuyển sang BucketOwnerEnforced trên các bucket mới — chế độ này vô hiệu hóa ACL hoàn toàn. Nếu bucket của bạn đang dùng BucketOwnerEnforced, ACL public-read sẽ không có tác dụng dù Block Public Access đã tắt.
Kiểm tra Object Ownership setting:
aws s3api get-bucket-ownership-controls \
--bucket ten-bucket-cua-ban
Nếu output là BucketOwnerEnforced, bạn cần dùng bucket policy để public:
🔽 Bucket Policy — Cho phép public read toàn bộ bucket
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::ten-bucket-cua-ban/*"
}
]
}
Apply policy này:
aws s3api put-bucket-policy \
--bucket ten-bucket-cua-ban \
--policy file://public-read-policy.json
IAM Policy Để Kiểm Tra Cấu Hình (Cho DevOps/Admin)
Nếu bạn cần cấp quyền cho một IAM user hoặc role để chạy các lệnh chẩn đoán trên, đây là policy tối thiểu cần thiết. Lưu ý rằng s3control:GetPublicAccessBlock (kiểm tra account-level) và s3:GetPublicAccessBlock (kiểm tra bucket-level) là hai action khác nhau thuộc hai service namespace khác nhau:
🔽 IAM Policy — Quyền chẩn đoán S3 Block Public Access
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BucketLevelDiagnostics",
"Effect": "Allow",
"Action": [
"s3:GetPublicAccessBlock",
"s3:GetBucketPolicy",
"s3:GetBucketAcl",
"s3:GetObjectAcl",
"s3:GetBucketOwnershipControls"
],
"Resource": [
"arn:aws:s3:::ten-bucket-cua-ban",
"arn:aws:s3:::ten-bucket-cua-ban/*"
]
},
{
"Sid": "AccountLevelDiagnostics",
"Effect": "Allow",
"Action": [
"s3control:GetPublicAccessBlock"
],
"Resource": "arn:aws:s3control::123456789012:account/123456789012"
}
]
}
Lưu Ý Bảo Mật Trước Khi Tắt Block Public Access
Block Public Access được bật mặc định có lý do chính đáng — nó ngăn data breach do cấu hình sai. Trước khi tắt, hãy xác nhận:
- Bucket này thực sự cần public access (ví dụ: static website, public CDN origin).
- Không có dữ liệu nhạy cảm nào trong bucket hoặc các prefix con.
- Nếu chỉ cần public một số object, cân nhắc dùng CloudFront với Origin Access Control (OAC) thay vì public bucket trực tiếp — bucket vẫn private, chỉ CloudFront mới có quyền đọc.
- Tắt ở cấp account ảnh hưởng toàn bộ tài khoản — chỉ làm nếu bạn kiểm soát được tất cả bucket trong account.
Wrap-Up: Checklist Xử Lý S3 Access Denied
Khi gặp lỗi S3 Access Denied trên URL public, chạy theo thứ tự này:
- Kiểm tra account-level Block Public Access (
aws s3control get-public-access-block). - Kiểm tra bucket-level Block Public Access (
aws s3api get-public-access-block). - Kiểm tra Object Ownership — nếu
BucketOwnerEnforced, ACL vô hiệu, dùng bucket policy. - Xác nhận object ACL hoặc bucket policy đã được set đúng.
- Kiểm tra bucket policy có Deny statement nào không.
Tài liệu tham khảo chính thức: AWS S3 Block Public Access và S3 Object Ownership.
Glossary — Thuật Ngữ Chính
| Thuật ngữ | Giải thích |
|---|---|
| Block Public Access | Cơ chế của S3 ngăn chặn truy cập công khai, hoạt động độc lập ở cấp account và bucket. |
| IgnorePublicAcls | Cờ khiến S3 bỏ qua mọi ACL public khi đánh giá quyền truy cập, dù ACL đã được set. |
| Object ACL | Danh sách kiểm soát truy cập gắn trực tiếp vào một S3 object cụ thể. |
| BucketOwnerEnforced | Chế độ Object Ownership vô hiệu hóa hoàn toàn ACL, buộc dùng bucket policy để kiểm soát quyền. |
| Explicit Deny | Quy tắc Deny trong IAM/bucket policy luôn ghi đè mọi Allow, bất kể nguồn gốc của Allow đó. |
Nhận xét
Đăng nhận xét