Trong bài hướng dẫn AWS IAM này, chúng ta sẽ thực hành cách sử dụng IAM User, IAM Group và IAM Policy để giới hạn quyền truy cập S3 theo nguyên tắc Least Privilege. Qua lab thực tế, bạn sẽ hiểu cách kiểm soát quyền truy cập S3 Bucket và xây dựng mô hình AWS Security an toàn hơn cho công ty của bạn.
Least Privilege trong AWS là gì?
Least Privilege là nguyên tắc chỉ cấp cho một người dùng hay một nhóm người dùng identity đúng những quyền cần thiết để hoàn thành công việc, trên đúng tài nguyên và trong đúng điều kiện cần thiết. Thay vì cấp AdministratorAccess toàn quyền truy cập tài nguyên, bạn có thể xác định cụ thể Action (hành động), Resource (tài nguyên) và khi cần cả Condition (điều kiện) trong IAM Policy. Đây là một best practice chính thức của AWS Well-Architected Framework. [1]
Contents
- 1 Sai lầm nguy hiểm: “Cứ cấp AdministratorAccess cho nhanh”
- 2 Hiểu IAM trước khi viết policy
- 3 Xây dựng Least Privilege Policy cho S3
- 4 Tạo Group, User và kiểm chứng quyền truy cập
- 5 Những lỗi thực tế khiến policy “đúng mà vẫn AccessDenied”
- 5.1 Do chúng ta có thể nhầm bucket ARN với object ARN như sau.
- 5.2 Hay có thể là trường hợp bạn cho cấp quyền GetObject nhưng quên quyền ListBucket cho S3 Bucket của bạn.
- 5.3 Cấp quyền ListBucket trên object ARN.
- 5.4 Dùng wildcard vì “đỡ phải debug”
- 5.5 Upload được file nhỏ nhưng gặp vấn đề với multipart upload
- 5.6 Bucket dùng SSE-KMS nhưng chỉ cấp S3 permissions
- 6 Từ bài lab nhỏ đến thiết kế IAM thực sự trong doanh nghiệp
- 7 Câu hỏi thường gặp về AWS IAM Least Privilege
- 7.1 AWS Least Privilege là gì?
- 7.2 Có nên cấp AdministratorAccess cho developer hoặc contractor không?
- 7.3 IAM User có còn nên dùng không?
- 7.4 IAM Group có tác dụng gì?
- 7.5 Inline Policy khác Managed Policy như thế nào?
- 7.6 Tại sao S3 Policy phải có cả bucket ARN và object ARN?
- 7.7 s3:ListAllMyBuckets có cho phép đọc tất cả bucket không?
- 7.8 Vì sao đã có s3:GetObject mà vẫn AccessDenied?
- 7.9 Làm sao kiểm tra policy có quá rộng không?
- 7.10 Policy hoàn chỉnh nào phù hợp cho lab này?
Sai lầm nguy hiểm: “Cứ cấp AdministratorAccess cho nhanh”
Hãy tưởng tượng một tình huống rất bình thường. Công ty của bạn thuê một contractor (nhà thầu) để xử lý tài liệu cho một dự án.
Công việc của nhà thầu này cực kỳ đơn giản, vì vậy người dùng chỉ cần làm các việc như: Đăng nhập AWS → mở một S3 bucket → xem file → upload file mới.
Vậy họ cần bao nhiêu quyền để truy cập vào tài nguyên của công ty bạn? câu trả lời là họ không cần phải có nhiều quyền, và đây là nguyên tắc bảo mật cấp đặc quyền tối thiểu cho người dùng.
Nhưng vì đội kỹ thuật của công ty bạn đang bận và muốn “làm nhanh cho xong”, và ai đó đã gán luôn cho tài khoản khách hàng quyền:
AdministratorAccess
Như vậy vấn đề truy cập cho người dùng được giải quyết trong vài phút.
Nhưng một vấn đề lớn hơn vừa được tạo ra.
Nếu identity hay người dùng/user đó thực sự có quyền quản trị rộng và không bị giới hạn bởi những lớp kiểm soát khác, phạm vi thao tác của user có thể vượt rất xa nhu cầu upload các files vào S3. AWS xem việc mặc định cấp quyền administrator và tạo policy quá rộng là các anti-pattern của kiến trúc bảo mật; Well-Architected Framework xếp rủi ro của việc không triển khai least privilege ở mức cao. [3]
Đây là lúc chúng ta cần hiểu một trong những nguyên tắc quan trọng nhất của AWS Security:
Một người có thể làm được việc không đồng nghĩa với việc họ nên được quyền làm mọi thứ.
AWS định nghĩa hướng tiếp cận least privilege (cấp đặc quyền tối thiểu) là cấp đúng những action cần thiết, trên đúng resource cần thiết và, khi thích hợp, trong đúng các condition cần thiết. IAM identities mặc định không tự động có quyền truy cập tài nguyên; quyền phải được cấp thông qua các cơ chế authorization phù hợp. [1]
Vì vậy, với contractor của chúng ta, mục tiêu không phải là:
Contractor → AWS, mà phải gần hơn với:
Contractor
│
▼
IAM permissions
│
├── List đúng bucket cần dùng
├── GetObject
└── PutObject
│
▼
phuong-demo-bucket01
Không cấp quyền dùng EC2, RDS, IAM administration, và không được có quyền xóa dữ liệu nếu công việc không yêu cầu. Không được quyền truy cập ngẫu nhiên sang các S3 bucket khác. Như vậy đó mới là tư duy Least Privilege.
Và đó cũng là điểm khác nhau giữa việc bạn “biết cách sử dụng AWS Console” với “biết cách thiết kế quyền truy cập AWS”.
Một cập nhật rất quan trọng cho môi trường AWS hiện đại
Có một chi tiết cần làm rõ trước khi bắt đầu thực hiện bài lab.
Trong bài thực hành này, chúng ta sẽ sử dụng:
IAM User→ IAM Group→IAM Policy→S3 Bucket
Đây là mô hình rất tốt để học cách IAM Policy hoạt động.
Tuy nhiên, đối với human workforce trong môi trường production hiện đại, AWS hiện khuyến nghị sử dụng federation và temporary credentials, thường thông qua AWS IAM Identity Center, thay vì tạo IAM User với long-term credentials cho từng nhân viên hoặc contractor. AWS chỉ khuyến nghị IAM User trong những use case cụ thể chưa phù hợp với federation. [4]
Vì vậy chúng ta hãy phân biệt:
Trong lab: IAM User + IAM Group + Policy
Trong nhiều kiến trúc production hiện đại:
Identity Provider→IAM Identity Center→Group / Permission Set→Temporary AWS credentials
Nguyên tắc bảo mật phía sau vẫn giống nhau:
Identity chỉ nên nhận những permissions thực sự cần thiết.
AWS Well-Architected cũng khuyến nghị sử dụng group hoặc identity attributes để quản lý permission ở quy mô lớn thay vì tạo quyền thủ công cho từng cá nhân. [5]
Hiểu IAM trước khi viết policy
Đừng vội copy một đoạn JSON từ Internet.
Nếu hiểu ba thành phần sau, IAM Policy sẽ bớt làm “đáng sợ” đi rất nhiều cho bạn:
WHO →Identity
CAN DO WHAT→ Action
ON WHAT→Resource
Trong bài lab này:
WHO là: contractor
CAN DO WHAT gồm:
ListBucket
GetObject
PutObject
ON WHAT:
phuong-demo-bucket01
Đó chính là câu chuyện mà IAM Policy phải diễn đạt.
IAM Group giúp quản lý quyền dễ hơn như thế nào?
Giả sử ngày hôm nay công ty có một contractor, ngày mai sẽ có năm người, tháng sau có hai mươi người.
Vậy bạn có thể attach policy trực tiếp vào từng user:
contractor01 → policy
contractor02 → policy
contractor03 → policy
contractor04 → policy
…
Nhưng cách đó nhanh chóng trở nên khó quản lý.
Với IAM Group:
┌── contractor01
│
Contractors ───┼── contractor02
│
├── contractor03
│
└── contractor04
│
▼
Policy
AWS IAM cho phép attach identity-based policy vào user group; tất cả IAM users thuộc group sẽ nhận các permissions của group đó. Đây chính là lý do group có thể giúp quản trị permission dễ hơn khi bạn đang sử dụng IAM users. [6]
Một tổ chức có thể phân quyền theo các chức năng kiểu: DevOps, Contractors, Finance, Security
Tất nhiên, tên và thiết kế group thực tế phải phản ánh job function và access model của từng doanh nghiệp.
Một điều dễ nhầm về Inline Policy
Trong bài lab này chúng ta sẽ sử dụng Inline Policy. Inline Policy được nhúng trực tiếp vào một IAM user, group hoặc role và duy trì quan hệ chặt chẽ với identity đó. Nếu identity bị xóa thì inline policy gắn với nó cũng bị xóa. [7]
Tuy nhiên chúng ta cần lưu ý: AWS không khuyến nghị Inline Policy cho phần lớn trường hợp thông thường.
Nếu cùng một policy có khả năng được tái sử dụng cho nhiều identity, customer managed policy thường là lựa chọn tốt hơn. AWS documentation nói rõ rằng trong hầu hết trường hợp họ không khuyến nghị inline policies, và nếu policy có thể áp dụng cho nhiều entity thì managed policy phù hợp hơn. [8]
Vì vậy: Lab nhỏ / policy chỉ thuộc về một identity → Inline Policy có thể phù hợp. Với Production / cần reuse / quản trị tập trung → Customer Managed Policy thường tốt hơn. Đây là một trong những khác biệt quan trọng giữa lab để học IAM và IAM design trong production.
Xây dựng Least Privilege Policy cho S3
Bây giờ chúng ta đi vào phần thực hành.
Giả sử chúng có một bucket có tên là:
phuong-demo-bucket01
Và Contractor cần có các quyền như:
✓ Xem danh sách object
✓ Download/read object
✓ Upload object
✗ Không cần xóa object
✗ Không cần tạo bucket
✗ Không cần thay đổi bucket policy
✗ Không cần quản lý ACL
✗ Không cần EC2
✗ Không cần IAM
Đây là lúc chúng ta biến business requirement thành technical permissions.
Lấy ARN của S3 bucket
Giả sử trong AWS Console có một Bucket: S3→ Buckets → phuong-demo-bucket01 → Properties
Bucket ARN sẽ có dạng: arn:aws:s3:::phuong-demo-bucket01
ARN rất quan trọng vì IAM Policy có thể sử dụng Resource để xác định tài nguyên cụ thể mà action được phép tác động tới. Với Amazon S3, bucket-level resource có dạng arn:aws:s3:::bucket-name, còn tất cả objects bên trong bucket thường được biểu diễn bằng arn:aws:s3:::bucket-name/*. [9]
Đây là chỗ nhiều người mới học IAM thường bỏ sót, bạn có thể có các thông tin với bucket của bạn như sau:
Bucket: arn:aws:s3:::phuong-demo-bucket01
Objects: arn:aws:s3:::phuong-demo-bucket01/*
Hai ARN này không có cùng ý nghĩa.
Hãy hình dung:
phuong-demo-bucket01 ← là Bucket
│
├── image.jpg ← là Object
├── invoice.pdf ← là Object
├── report.xlsx ← là Object
└── backup/
└── db.sql ← là Object
Các action ở bucket level như s3:ListBucket cần bucket resource, trong khi các action như s3:GetObject và s3:PutObject tác động tới object resource. AWS documentation phân biệt rõ hai resource type này. [10]
Policy nên chính xác hơn Get*, Put*
Script ban đầu sử dụng:
“Action”: [
“s3:Get*”,
“s3:List*”,
“s3:Describe*”,
“s3:Put*”
]
Đoạn json cho việc cấp quyền truy cập vào S3 Bucket này có vẻ tiện, tuy nhiên hãy quay lại câu hỏi ban đầu: Contractor thực sự cần làm gì? Vậy nếu họ chỉ cần các quyền trong S3 Bucket như:List, Read, Upload. Vậy thì tại sao bạn lại cấp toàn bộ: Get*, List*, Describe*, Put* ?
Một trong những nguyên tắc của least privilege là thu hẹp permission (phân quyền) đến đúng API actions thực sự cần thiết; AWS cũng khuyến nghị scope broad actions xuống resource cụ thể khi service hỗ trợ và liên tục loại bỏ các quyền dư thừa. [11]
Với requirement hiện tại, tôi sẽ viết policy rõ ràng hơn như sau:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “AllowS3ConsoleBucketList”,
“Effect”: “Allow”,
“Action”: “s3:ListAllMyBuckets”,
“Resource”: “*”
},
{
“Sid”: “AllowAccessToTargetBucket”,
“Effect”: “Allow”,
“Action”: [
“s3:ListBucket”,
“s3:GetBucketLocation”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
},
{
“Sid”: “AllowReadAndUploadObjects”,
“Effect”: “Allow”,
“Action”: [
“s3:GetObject”,
“s3:PutObject”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
]
}
Policy này dễ đọc hơn. Và bạn hãy thay đổi tên backet trong policy trên thành tên S3 bucket của bạn: arn:aws:s3:::phuong-demo-bucket01
Và quan trọng hơn: mỗi permission đều có lý do tồn tại.
s3:ListAllMyBuckets dùng để làm gì?
Statement đầu tiên:
{
“Effect”: “Allow”,
“Action”: “s3:ListAllMyBuckets”,
“Resource”: “*”
}
có vẻ mâu thuẫn với câu chuyện least privilege.
Tại sao lại có:
Resource: “*”
?
Bởi vì s3:ListAllMyBuckets là một trong những permissions mà AWS nêu trong policy mẫu dành cho truy cập S3 qua console. Permission này cho phép console lấy danh sách các buckets mà authenticated sender có thể thấy ở bước liệt kê; nó không tự động cấp quyền đọc objects trong tất cả các bucket đó. [12]
Nhưng có một trade-off cần hiểu: User có thể nhìn thấy tên các bucket trong account.
Điều đó khác với việc: User có quyền mở và đọc dữ liệu trong tất cả các bucket.
Nếu việc lộ tên bucket cũng không được chấp nhận, bạn cần thiết kế trải nghiệm khác thay vì mặc định cho phép console bucket listing; chẳng hạn có thể dựa vào API/CLI hoặc workflow được kiểm soát chặt hơn tùy use case.
Đây là ví dụ rất hay cho một bài học lớn hơn:
Least Privilege không phải copy một policy mẫu. Least Privilege là hiểu mỗi permission giải quyết vấn đề gì và chấp nhận trade-off nào.
Bucket-level permissions
Tiếp theo:
{
“Effect”: “Allow”,
“Action”: [
“s3:ListBucket”,
“s3:GetBucketLocation”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
}
s3:ListBucket cho phép list objects trong bucket; AWS ánh xạ ListObjects và ListObjectsV2 tới permission này. s3:GetBucketLocation cho phép lấy Region của bucket. [13]
Hãy chú ý Resource:
arn:aws:s3:::phuong-demo-bucket01
Nó không có:
/*
bởi đây là các thao tác liên quan tới bucket.
Object-level permissions
Tiếp theo chúng ta có đoạn json:
{
“Effect”: “Allow”,
“Action”: [
“s3:GetObject”,
“s3:PutObject”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
Đây mới là phần cho phép contractor làm việc với files.
s3:GetObject dùng cho việc đọc object; s3:PutObject là permission bắt buộc để thực hiện PutObject. AWS documentation cũng chỉ rõ các object actions phải sử dụng object resource phù hợp. [14]
Chú ý:
/*
ở cuối, vậy nếu bạn chỉ viết: arn:aws:s3:::phuong-demo-bucket01; Thì bạn đang tham chiếu bucket, chứ không phải toàn bộ objects bên trong nó. AWS sử dụng dạng: arn:aws:s3:::bucket-name/* để đại diện cho các object resources trong bucket. [9] Đây là một trong những chi tiết nhỏ nhưng cực kỳ quan trọng khi debug S3 permissions.
Tại sao không có DeleteObject?
Bởi contractor không được yêu cầu xóa file, vì vậy chúng ta không cấp quyền : s3:DeleteObject
AWS xác định s3:DeleteObject là permission tương ứng cần thiết cho thao tác xóa object không chỉ định version. [15]
Đơn giản vậy thôi, đừng bắt đầu bằng câu hỏi: “AWS có những permissions nào?” mà hãy bắt đầu bằng: “Người này cần hoàn thành công việc nào?”
Sau đó map từng công việc sang API permissions, đó là cách tư duy IAM hiệu quả hơn.
Tạo Group, User và kiểm chứng quyền truy cập
Bây giờ hãy đưa policy vào một mô hình có thể kiểm thử.
Luồng lab của chúng ta như sau:
Create IAM Group –> Attach Least Privilege Policy –> Create IAM User–>Add User to Group–>Login as User–>Test Allowed Actions–>Test Denied Actions
Đầu tiên cần tạo IAM Group
Trong IAM console:
Vào IAM→ click User groups → click Create group

Đặt tên cho group là: contractors và bạn nhớ Group name chỉ cần là: contractors
Không phải là: arn:aws:s3:::phuong-demo-bucket01, đây là ARN của bucket thuộc về phần Resource trong IAM Policy, không phải tên IAM Group.
AWS IAM user groups được thiết kế để gom các IAM users có cùng nhu cầu permission (phân quyền) và cho phép attach identity-based policies để các thành viên kế thừa permissions từ group. [16]

Tạo Inline Policy cho lab
Tiếp theo chúng ta mở Click vào: contractors

Click Permissions :

Click Add permissions → Create inline policy

Click JSON

Và paste policy sau:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “AllowS3ConsoleBucketList”,
“Effect”: “Allow”,
“Action”: “s3:ListAllMyBuckets”,
“Resource”: “*”
},
{
“Sid”: “AllowAccessToTargetBucket”,
“Effect”: “Allow”,
“Action”: [
“s3:ListBucket”,
“s3:GetBucketLocation”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
},
{
“Sid”: “AllowReadAndUploadObjects”,
“Effect”: “Allow”,
“Action”: [
“s3:GetObject”,
“s3:PutObject”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
]
}
Đặt tên ví dụ: S3ContractorLeastPrivilege, và click Create

AWS IAM Console kiểm tra syntax/grammar khi bạn tạo hoặc chỉnh sửa JSON policy; nếu có quyền sử dụng IAM Access Analyzer validation, console cũng có thể trả về findings và recommendations nhằm giúp policy an toàn và đúng chức năng hơn. [17]
Đây là thói quen mà chúng ta nên có: Write → Validate → Test → Observe → Reduce → permissions → Repeat
Least privilege không phải một việc “làm một lần rồi quên”. AWS Prescriptive Guidance mô tả đây là quá trình lặp lại, trong đó permissions cần được xem xét và giảm dần theo dữ liệu sử dụng thực tế. [18]
Tạo IAM User cho bài lab
Tiếp theo quay lại: IAM → Click Users→ Click Create user → và đặt Tên cho user là: contractor
Và check vào chọn: Provide user access to the AWS Management Console – optional để user này có quyền login vào aws console > Click Next để tiếp tục
AWS khuyến nghị chỉ tạo loại credential mà user thực sự cần. Ví dụ, nếu user chỉ cần Management Console thì không cần tạo thêm access keys một cách không cần thiết. [19]

Sau đó trong màn hình Set permissions chúng ta cấp quyền cho user này có thể truy cập vào S3 bucket của chúng ta bằng cách check chọn group
contractors đã được tạo ở bước trên, như vậy User sẽ nhận được permissions thông qua policies đã được gắn vào group. [6]: Click Next

và Click Create để tạo user này.

Bây giờ bạn có thể thấy user contractor đã được tạo ra như hình dưới, chúng ta có thể thấy các thông tin của user này gồm:
Console sign-in URL: Hãy copy URL này sau đó dán vào 1 tab trong trình duyệt để login vào AWS console dành riêng cho user này.
User name: Hãy copy user để sau khi màn hình đăng nhập của user này hiển thị trong trình duyệt, bạn hãy dán user name này vào Username
Console Password: Hãy copy mật khẩu của user này để sau khi màn hình đăng nhập của user này hiển thị trong trình duyệt, bạn hãy dán mật khẩu này vào Password.
Tốt nhất bạn hãy click vào nút Download .csv file để download file csv chứa các thông tin về Console sign-in URL, User name,Console Password của user này về PC của bạn, sau đó mở ra để xem thông tin.

Lưu ý: Nếu sử dụng tùy chọn yêu cầu đổi password ở lần đăng nhập đầu tiên, AWS Console có thể cấu hình user phải thay password khi sign-in lần đầu; AWS documentation cũng khuyến nghị MFA cho IAM users. [20]
Tuy nhiền trong môi trường production, với contractor là một nhà thầu, hãy cân nhắc IAM Identity Center/federation và temporary credentials thay vì mặc định tạo IAM User lâu dài. [4]
Kiểm thử những gì được phép
Đăng nhập bằng identity contractor bằng cách nhập Username và Password của user này.

Sau đó vào dich vụ Aws S3, và click mở S3 bucket của bạn, như trong ví dụ này có tên là phuong-demo-bucket01:

Sau đó thử các bước làm sau:
✓ Mở phuong-demo-bucket01
✓ List objects
✓ Upload một file nhỏ
✓ Mở/download file

Thấy Upload succeded tức là user có quyền upload file.

Như vậy nếu policy đúng và không có lớp kiểm soát khác từ chối request, ListBucket, GetObject và PutObject cung cấp các quyền nền tảng cho những thao tác tương ứng của user. [21]
Tuy nhiên bạn không nên dừng lại ở việc test kiểm thử các hành động được phép.
Least privilege chỉ thực sự được kiểm chứng khi bạn test cả các hành động phải bị từ chối.
Hãy thử vào bucket và thực hiện các việc như sau:
✗ Delete object
✗ Truy cập bucket khác
✗ Launch EC2 instance
✗ Thay đổi IAM users
✗ Tạo S3 bucket mới
Trong lab nơi identity hay user không nhận thêm permissions từ policy khác, các action không được cho phép sẽ bị implicit deny. AWS IAM bắt đầu quá trình authorization với trạng thái mặc định deny; explicit allow cần tồn tại để cho phép action, và một explicit deny áp dụng từ policy thích hợp sẽ thắng allow. [22]
Đây là một hiểu biết rất quan trọng về các khái niệm với AWS IAM. Vì vậy chúng ta không nên nói là:
“Policy này cấm EC2.” Mà chính xác hơn chúng ta nói là: “Policy này không cấp EC2 permission.”
Chúng ta nhớ hai câu trên là khác nhau.
Như vậy IAM policy trên chỉ có: Allow S3… Và Nó không chứa: Deny EC2…
Nếu giả sử nếu sau này user nhận thêm một policy khác: AmazonEC2FullAccess thì effective permissions có thể thay đổi bởi AWS đánh giá tổng hợp các policies áp dụng cho request. [23]
Đây chính là lý do security review phải nhìn vào effective permissions, không chỉ một file JSON đơn lẻ.
Những lỗi thực tế khiến policy “đúng mà vẫn AccessDenied”
Đây là phần tôi đặc biệt khuyên người học AWS nên đọc kỹ. Bởi trong thực tế, khi chúng ta viết policy thường không khó bằng việc trả lời câu hỏi:
Tại sao mình cấu hình policy như vậy mà nó vẫn không chạy?
Do chúng ta có thể nhầm bucket ARN với object ARN như sau.
Viết sai:
{
“Action”: “s3:GetObject”,
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
}
Viết đúng:
{
“Action”: “s3:GetObject”,
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
Bucket và object là resource types (loại tài nguyên) khác nhau trong S3 policy model. [9]
Hay có thể là trường hợp bạn cho cấp quyền GetObject nhưng quên quyền ListBucket cho S3 Bucket của bạn.
Trường hợp này bạn có thể nghĩ: Tôi đã cấp quyền GetObject. Và tại sao console không browse được file trong S3 bucket?
Lý do là : Bởi vì việc list objects sử dụng s3:ListBucket, trong khi đọc nội dung object sử dụng object-level permission như s3:GetObject. [13]
Đây là hai việc khác nhau.
Cấp quyền ListBucket trên object ARN.
Sai:
{
“Action”: “s3:ListBucket”,
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
Đúng phải là:
{
“Action”: “s3:ListBucket”,
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
}
Như vậy AWS xác định ListObjects/ListObjectsV2 cần s3:ListBucket trên bucket resource. [10]
Dùng wildcard vì “đỡ phải debug”
Bạn gặp lỗi AccessDenied. Và bạn thêm: “s3:Get*” như truy cập S3 bucket Vẫn lỗi. Sau đó bạn thêm: “s3:Put*”, Cuối cùng: “Action”: “s3:*”. Và bạn thêm : “Resource”: “*”, lúc này bạn thấy nó chạy! Tuy nhiên trường hợp chạy này không phải là lúc bạn sửa xong lỗi, và đó có thể là lúc bạn vừa xóa bỏ ranh giới bảo mật.
AWS khuyến nghị tiến dần tới fine-grained, use-case-specific permissions và có thể sử dụng Access Analyzer để giúp tinh chỉnh quyền dựa trên access activity. [24]
Một quy trình debug tốt hơn nên là: AccessDenied → Action nào bị deny?→ Resource ARN nào?→ Identity-based policy?→ Bucket policy?→ Permissions boundary?→ SCP/RCP?→ KMS policy?→ Condition nào không match (khớp)?
AWS authorization có thể liên quan đồng thời đến identity-based policies, resource-based policies, permissions boundaries, AWS Organizations SCPs/RCPs và các loại policy khác; explicit deny phù hợp có thể override allow. [22]
Upload được file nhỏ nhưng gặp vấn đề với multipart upload
Một policy rất nhỏ chỉ có: s3:PutObject, vì vậy có thể đủ cho các thao tác upload cơ bản.
Nhưng trong môi trường production use case có thể cần xử lý multipart upload. AWS xác định s3:PutObject là permission cần thiết để initiate, upload parts và complete multipart upload, trong khi các thao tác như abort và list parts sử dụng các permissions riêng như s3:AbortMultipartUpload và s3:ListMultipartUploadParts. [25]
Nếu requirement thực sự cần các tính năng đó, policy có thể được mở rộng có chủ đích:
{
“Sid”: “AllowMultipartOperations”,
“Effect”: “Allow”,
“Action”: [
“s3:AbortMultipartUpload”,
“s3:ListMultipartUploadParts”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
và nếu cần list các multipart uploads đang diễn ra ở bucket level:
{
“Sid”: “AllowListMultipartUploads”,
“Effect”: “Allow”,
“Action”: “s3:ListBucketMultipartUploads”,
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
}
AWS liệt kê riêng các permissions này trong tài liệu multipart upload. [26]
Điểm quan trọng không phải là thêm chúng vào mọi policy. Điểm quan trọng là: Chỉ thêm khi use case cần.
Bucket dùng SSE-KMS nhưng chỉ cấp S3 permissions
Đây là một lỗi cực kỳ thực tế. Ví dụ bạn có:
s3:GetObject
s3:PutObject
Chúng ta có thể thấy Policy này nhìn hoàn toàn đúng. Tuy nhiên khi user truy cập vào S3 bucket nhưng vẫn gặp lỗi: AccessDenied, nguyên nhân khả năng là objects đang sử dụng SSE-KMS.
AWS quy định rằng để upload object sử dụng KMS key, caller cần kms:GenerateDataKey trên key; để download object được mã hóa bằng KMS key, caller cần kms:Decrypt. Multipart upload sử dụng SSE-KMS có thể cần cả hai. [27]
Tức là authorization path đã trở thành:
Contractor
│
├── S3 permission
│
└── KMS permission
│
▼
KMS Key
Và bạn phải xem xét cả IAM policy lẫn quyền liên quan đến KMS key phù hợp. Đó là lý do tại sao câu: “Tôi đã cấp S3 Full Access rồi, tại sao vẫn AccessDenied?” không phải lúc nào cũng được giải quyết bằng cách cấp thêm S3 permissions.
Từ bài lab nhỏ đến thiết kế IAM thực sự trong doanh nghiệp
Đến đây chúng ta đã có một lab chạy được. Nhưng nếu tôi review kiến trúc production, tôi sẽ không dừng ở:
IAM User
+
IAM Group
+
Inline Policy
Tôi sẽ hỏi thêm vài câu.
Đây có thực sự nên là IAM User không?
Nếu contractor là một con người, AWS hiện khuyến nghị human users sử dụng federation với identity provider và temporary credentials; IAM Identity Center là giải pháp AWS khuyến nghị cho centralized workforce access management. [4]
Một kiến trúc hiện đại hơn có thể là:
Contractor → Corporate / External IdP→ IAM Identity Center→ Restricted Permission Set→ AWS Account→ Specific S3 Resource
Temporary credentials làm giảm sự phụ thuộc vào long-lived user credentials và phù hợp với best practice AWS dành cho human identities. [28]
Policy có nên là Inline Policy không?
Nếu chỉ có đúng một identity và policy cần lifecycle gắn chặt với identity đó, inline policy có thể có ý nghĩa.
Nhưng nếu permission sẽ được tái sử dụng:
Contractors-A
Contractors-B
Contractors-C
customer managed policy giúp quản trị tập trung tốt hơn. AWS nói rằng policy dùng được cho nhiều entity phù hợp hơn với managed policy. [7]
Ví dụ:
S3ContractorReadWritePolicy
│
├── Group A
├── Group B
└── Role C
thường dễ maintain hơn việc duplicate ba inline policies.
Có thể thu hẹp xuống một prefix không?
Giả sử contractor chỉ cần folder:
uploads/contractors/
Thay vì là : arn:aws:s3:::phuong-demo-bucket01/*
object access có thể được thu hẹp thành: arn:aws:s3:::phuong-demo-bucket01/uploads/contractors/*
Amazon S3 hỗ trợ object resource ARN theo prefix theo dạng bucket-name/prefix/*. [29]
Như vậy:
phuong-demo-bucket01
│
├── finance/ ✗
├── database-backup/ ✗
├── security-logs/ ✗
└── uploads/
└── contractors/ ✓
Đây mới là lúc least privilege trở nên thú vị, chúng ta Không chỉ hỏi: S3 hay không S3? Mà chúng ta hỏi:
Bucket nào?
Folder/prefix nào?
Action nào?
Trong điều kiện nào?
Trong bao lâu?
AWS Well-Architected mô tả least privilege chính xác theo hướng cấp các action cụ thể trên resource cụ thể và có thể bổ sung conditions để giới hạn thêm quyền. [30]
Có thực sự cần quyền xóa không?
Hầu hết contractor upload tài liệu không nhất thiết cần: DeleteObject, vì vậy nếu không có business requirement thì chúng ta không cấp quyền này.
Một permission không tồn tại thường dễ bảo vệ hơn một permission rộng rồi cố kiểm soát bằng quy trình con người.
Làm thế nào biết policy vẫn còn quá rộng?
Bạn không nhất thiết phải đoán mãi. IAM Access Analyzer có thể phân tích access activity từ AWS CloudTrail trong một khoảng thời gian được hỗ trợ và tạo policy template dựa trên những service/actions thực sự đã được sử dụng; sau đó bạn review, bổ sung resource và condition rồi triển khai policy tinh chỉnh hơn. [31]
Đây là một vòng lặp rất đáng học: Grant → Use→ Observe→ Analyze→ Reduce→ Validate→ Grant again
AWS cũng khuyến nghị review permissions thường xuyên để tránh hiện tượng permissions creep (sự gia tăng dần các quyền truy cập) khi user thay đổi vai trò hoặc quyền cũ không còn cần thiết. [32]
Và đây có lẽ là bài học lớn nhất của toàn bộ bài viết: Least Privilege không phải một file JSON. Nó là một quá trình.
Bạn không đạt được least privilege chỉ bằng việc tạo policy một lần. Mà bạn đạt gần nó hơn bằng cách liên tục hỏi:
Quyền này còn cần không?
Resource này có thể thu hẹp không?
Wildcard này có thể bỏ không?
Credential này có cần tồn tại không?
User này có nên chuyển sang role/federation không?
Đó là tư duy AWS Security thực sự.
Câu hỏi thường gặp về AWS IAM Least Privilege
AWS Least Privilege là gì?
AWS Least Privilege là nguyên tắc chỉ cho phép identity thực hiện những action cần thiết trên những resource cần thiết, dưới các condition thích hợp để hoàn thành nhiệm vụ. AWS Well-Architected coi việc mặc định cấp quyền administrator hoặc tạo policy quá rộng là các anti-pattern bảo mật. [3]
Có nên cấp AdministratorAccess cho developer hoặc contractor không?
Không nên sử dụng AdministratorAccess như quyền mặc định chỉ vì cấu hình nó dễ dàng và thuận tiện. AWS khuyến nghị giới hạn administrator privileges cho một nhóm nhỏ đáng tin cậy và cấp cho các identity khác quyền tối thiểu phù hợp với nhiệm vụ của họ. [3]
IAM User có còn nên dùng không?
IAM User vẫn tồn tại và có những use case cụ thể, nhưng với human users AWS hiện khuyến nghị federation và temporary credentials; IAM Identity Center được AWS khuyến nghị cho centralized workforce access. [4]
IAM Group có tác dụng gì?
IAM Group là tập hợp IAM users. Bạn có thể attach identity-based policies vào group để các users trong group nhận những permissions đó, giúp quản lý IAM users có cùng nhiệm vụ dễ dàng hơn. Group không phải authenticated principal và không thể được dùng như Principal trong resource-based policy. [33]
Inline Policy khác Managed Policy như thế nào?
Inline Policy được nhúng trực tiếp vào một user, group hoặc role và có quan hệ một-một với identity đó. Managed Policy là policy độc lập có thể attach (gắn) tới nhiều identity. AWS cho biết nếu policy có thể áp dụng cho nhiều entity thì managed policy thường phù hợp hơn, và trong hầu hết trường hợp AWS không khuyến nghị dùng inline policies. [8]
Tại sao S3 Policy phải có cả bucket ARN và object ARN?
Bởi vì Amazon S3 phân biệt bucket-level resources và object-level resources. Ví dụ s3:ListBucket áp dụng cho bucket ARN, còn s3:GetObject và s3:PutObject áp dụng cho object ARN dạng arn:aws:s3:::bucket-name/*. [10]
s3:ListAllMyBuckets có cho phép đọc tất cả bucket không?
Không. Action này hỗ trợ việc lấy danh sách buckets và thường được AWS đưa vào policy mẫu cần cho S3 Console; quyền truy cập nội dung của từng bucket vẫn phụ thuộc vào những permissions khác như s3:ListBucket, s3:GetObject và các applicable policies khác. Tuy nhiên, việc cấp ListAllMyBuckets có thể làm user nhìn thấy tên bucket, nên đây vẫn là yếu tố cần cân nhắc trong threat model. [12]
Vì sao đã có s3:GetObject mà vẫn AccessDenied?
Có nhiều nguyên nhân. Có thể object ARN sai, bucket/resource policy có explicit deny, permissions boundary hoặc SCP giới hạn quyền, hay object dùng SSE-KMS nhưng identity thiếu KMS permissions. AWS IAM đánh giá nhiều lớp policy khác nhau; explicit deny áp dụng cho request sẽ override allow. [34]
Làm sao kiểm tra policy có quá rộng không?
AWS cung cấp IAM Access Analyzer để validate policies và có thể tạo policy template dựa trên access activity được ghi nhận trong CloudTrail. AWS khuyến nghị review và giảm permissions liên tục thay vì coi least privilege là thao tác một lần. [35]
Policy hoàn chỉnh nào phù hợp cho lab này?
Với yêu cầu dùng S3 Console, xem danh sách object, đọc file và upload file vào phuong-demo-bucket01, nhưng không xóa file, policy cơ bản có thể là:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “AllowS3ConsoleBucketList”,
“Effect”: “Allow”,
“Action”: “s3:ListAllMyBuckets”,
“Resource”: “*”
},
{
“Sid”: “AllowAccessToTargetBucket”,
“Effect”: “Allow”,
“Action”: [
“s3:ListBucket”,
“s3:GetBucketLocation”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01”
},
{
“Sid”: “AllowReadAndUploadObjects”,
“Effect”: “Allow”,
“Action”: [
“s3:GetObject”,
“s3:PutObject”
],
“Resource”: “arn:aws:s3:::phuong-demo-bucket01/*”
}
]
}
Policy này bám sát các action/resource mappings và console permissions được AWS document cho Amazon S3. Production policy vẫn cần được điều chỉnh theo encryption, multipart upload, bucket policy, AWS Organizations guardrails, prefix restrictions và các yêu cầu thực tế khác. [36]
Điều quan trọng nhất cần nhớ sau bài lab này không phải tên của ba API actions.
Mà là cách suy nghĩ, chúng ta Đừng hỏi: “Làm thế nào để user này truy cập được?”
Mà hãy hỏi: “Quyền tối thiểu nào đủ để user này hoàn thành đúng công việc?”
Đó chính là ranh giới giữa một AWS account “chạy được” và một AWS environment được thiết kế có chủ đích.
AWS IAM không chỉ là nơi chúng ta tạo user và attach policy, mà IAM nằm ở trung tâm của câu hỏi quan trọng nhất trong Cloud Security:
Ai được phép làm gì, với tài nguyên nào, và trong điều kiện nào?
Khi hiểu thật sâu câu hỏi đó, bạn không chỉ học IAM, mà ở đâybạn đang bắt đầu suy nghĩ như một Cloud Engineer, DevOps Engineer và Cloud Security Engineer. Và nếu chỉ có một nguyên tắc mà bạn cần nhớ sau bài viết này, hãy nhớ:
Đừng cấp quyền để “phòng khi cần”. Hãy cấp quyền vì có một nhu cầu sử dụng cụ thể — và chỉ đúng mức cần thiết. [1]
[1] [4] [11] [24] [28] Security best practices in IAM – AWS Identity and Access Management
https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html?utm_source=chatgpt.com
[2] Creating Helpful, Reliable, People-First Content | Google Search Central | Documentation | Google for Developers
[3] [5] [30] [32] SEC03-BP02 Grant least privilege access – AWS Well-Architected Framework
[6] [16] [33] IAM user groups – AWS Identity and Access Management
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html?utm_source=chatgpt.com
[7] [8] Managed policies and inline policies – AWS Identity and Access Management
[9] [29] Policies and permissions in Amazon S3 – Amazon Simple Storage Service
[10] [13] [14] [15] [21] [36] Required permissions for Amazon S3 API operations – Amazon Simple Storage Service
[12] Identity-based policy examples for Amazon S3 – Amazon Simple Storage Service
[17] [35] Validate policies with IAM Access Analyzer – AWS Identity and Access Management
[18] IAM resources – AWS Prescriptive Guidance
[19] [20] Create an IAM user in your AWS account – AWS Identity and Access Management
https://docs.aws.amazon.com/us_en/IAM/latest/UserGuide/id_users_create.html?utm_source=chatgpt.com
[22] [23] [34] Policy evaluation logic – AWS Identity and Access Management
[25] [26] Uploading and copying objects using multipart upload in Amazon S3 – Amazon Simple Storage Service
https://docs.aws.amazon.com/us_en/AmazonS3/latest/userguide/mpuoverview.html?utm_source=chatgpt.com
[27] Using server-side encryption with AWS KMS keys (SSE-KMS) – Amazon Simple Storage Service
https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html?utm_source=chatgpt.com
[31] IAM Access Analyzer policy generation – AWS Identity and Access Management
#AWSIAM #IAMPolicy #S3BucketPolicy #IAMUser #IAMGroup #AWSSecurity #S3Security #LeastPrivilege #AWSTutorial

