Policy đó cấp toàn quyền S3 trên mọi bucket của account, vi phạm nguyên tắc least privilege. Rủi ro cụ thể: một service chỉ cần đọc một bucket nhưng lại có thể DeleteBucket, đọc bucket chứa log/backup của hệ thống khác, hoặc ghi đè dữ liệu — nếu service bị chiếm quyền thì bán kính thiệt hại là cả account.
Siết theo ba trục:
1. Action: liệt kê đúng action cần, không dùng wildcard rộng.
2. Resource: chỉ định ARN cụ thể. Nhớ hai ARN khác nhau — bucket (cho ListBucket) và object (cho GetObject).
3. Condition: thêm ràng buộc theo prefix, tag, source VPC endpoint, aws:SecureTransport.
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::app-uploads-prod/users/*"
}Cách làm thực tế thay vì ngồi đoán quyền: chạy với policy hẹp trên môi trường staging, xem service nào bị AccessDenied trong CloudTrail rồi bổ sung dần; hoặc dùng IAM Access Analyzer sinh policy từ log CloudTrail của role đó. Với account có nhiều team, thêm permissions boundary để giới hạn trần quyền mà developer tự cấp cho role họ tạo.
Một lưu ý hay bị bỏ qua: "Resource": "*" là bắt buộc với vài action cấp account (vd s3:ListAllMyBuckets) — chỗ đó không phải lỗi, nhưng nên tách riêng statement thay vì gộp chung với action ghi/xoá.