Sự khác biệt giữa IAM User và IAM Role: Khi nào dùng cái nào?

Một trong những lỗi phổ biến nhất khi mới làm việc với AWS là nhúng Access Key của IAM User trực tiếp vào code chạy trên EC2 — rồi sau đó phát hiện ra key đó bị lộ lên GitHub. IAM User và IAM Role đều cấp quyền truy cập AWS, nhưng cơ chế hoạt động và ngữ cảnh sử dụng khác nhau hoàn toàn, và việc chọn sai có thể tạo ra lỗ hổng bảo mật nghiêm trọng trong môi trường production.

TL;DR — IAM User vs IAM Role

Tiêu chí IAM User IAM Role
Danh tính Người dùng cụ thể (người hoặc service account) Tập hợp quyền có thể được assume bởi entity khác
Xác thực Username/password hoặc Access Key tĩnh Temporary credentials (STS) — tự động rotate
Dùng cho EC2 truy cập S3 Không khuyến nghị — key tĩnh, rủi ro cao Khuyến nghị — Instance Profile, không cần quản lý key
Phạm vi sử dụng Con người dùng AWS Console/CLI EC2, Lambda, ECS, cross-account, federated identity
Credential lifecycle Tồn tại vĩnh viễn cho đến khi xóa/disable Tự động hết hạn (mặc định 1 giờ, tối đa 12 giờ)

Cơ chế hoạt động của IAM User và IAM Role

IAM User là một identity tồn tại lâu dài trong AWS account. Khi tạo IAM User, AWS cấp cho nó một bộ credentials cố định: password để đăng nhập Console, và/hoặc Access Key ID + Secret Access Key để gọi API. Những credentials này không tự hết hạn — chúng tồn tại cho đến khi bạn chủ động xóa hoặc vô hiệu hóa.

IAM Role hoạt động theo cơ chế khác. Role không có credentials cố định. Thay vào đó, khi một entity (EC2 instance, Lambda function, hay một IAM User khác) assume một Role, AWS Security Token Service (STS) phát hành một bộ temporary credentials gồm Access Key ID, Secret Access Key, và Session Token. Những credentials này tự động hết hạn và được rotate.

sequenceDiagram participant App as Ứng dụng trên EC2 participant IMDS as Instance Metadata Service participant STS as AWS STS participant S3 as Amazon S3 App->>IMDS: GET /iam/security-credentials/EC2S3AccessRole IMDS->>STS: AssumeRole (EC2S3AccessRole) STS-->>IMDS: Temporary Credentials
(AccessKey + SecretKey + Token) IMDS-->>App: Trả về Temporary Credentials App->>S3: GetObject (dùng Temp Credentials) S3-->>App: Object data Note over IMDS,STS: Credentials tự động rotate
trước khi hết hạn
  1. EC2 Instance được gắn Instance Profile chứa IAM Role.
  2. Khi ứng dụng cần credentials, AWS SDK tự động gọi Instance Metadata Service (IMDS) tại endpoint http://169.254.169.254/latest/meta-data/iam/security-credentials/.
  3. STS phát hành temporary credentials và trả về cho EC2.
  4. SDK dùng credentials đó để gọi S3 API.
  5. Credentials tự động được rotate trước khi hết hạn — ứng dụng không cần làm gì thêm.

Tại sao không dùng IAM User cho EC2 truy cập S3?

Lý do không phải là 'không thể làm được' — mà là rủi ro vận hành thực tế. Khi bạn đặt Access Key của IAM User vào EC2 (qua environment variable, file ~/.aws/credentials, hoặc hardcode trong code), key đó trở thành một điểm thất bại duy nhất:

  • Key không tự hết hạn — nếu bị lộ, attacker có thể dùng vô thời hạn cho đến khi bạn phát hiện và revoke.
  • Khi scale out nhiều EC2 instances, bạn phải phân phối và quản lý key trên tất cả instances.
  • Rotation key thủ công tốn công và dễ gây downtime nếu làm sai thứ tự.
  • Key thường bị vô tình commit lên version control — đây là nguồn gốc của hàng trăm security incident thực tế.
Nghĩ về IAM User credentials như chìa khóa nhà — một bản sao duy nhất, tồn tại mãi. IAM Role credentials giống như mã OTP — ngắn hạn, tự hết hạn, và được tạo mới mỗi lần cần.

Hướng dẫn: Gắn IAM Role cho EC2 Instance truy cập S3

Bước 1: Tạo IAM Role với Trust Policy cho EC2

Trust Policy xác định ai được phép assume Role này. Với EC2, principal là ec2.amazonaws.com. Đây là bước hay bị bỏ qua khi tạo Role thủ công — nếu Trust Policy sai, EC2 sẽ không thể assume Role dù Permission Policy đúng hoàn toàn.

# Tạo file trust policy
cat > ec2-trust-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

# Tạo IAM Role
aws iam create-role \
  --role-name EC2S3AccessRole \
  --assume-role-policy-document file://ec2-trust-policy.json \
  --region us-east-1

Bước 2: Tạo và gắn Permission Policy theo nguyên tắc least privilege

Chỉ cấp quyền cụ thể mà ứng dụng thực sự cần. Nếu ứng dụng chỉ đọc từ một bucket cụ thể, đừng cấp s3:* trên tất cả resources.

🔽 Click để xem Permission Policy và lệnh gắn policy
# Tạo permission policy — chỉ cho phép đọc từ bucket cụ thể
cat > s3-read-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-app-bucket",
        "arn:aws:s3:::my-app-bucket/*"
      ]
    }
  ]
}
EOF

# Tạo policy
aws iam create-policy \
  --policy-name EC2S3ReadPolicy \
  --policy-document file://s3-read-policy.json

# Gắn policy vào role (thay 123456789012 bằng Account ID thực)
aws iam attach-role-policy \
  --role-name EC2S3AccessRole \
  --policy-arn arn:aws:iam::123456789012:policy/EC2S3ReadPolicy

Bước 3: Tạo Instance Profile và gắn vào EC2

Instance Profile là container bọc IAM Role để EC2 có thể sử dụng. Đây là điểm nhiều người nhầm lẫn — Role và Instance Profile là hai resource riêng biệt trong IAM, dù AWS Console thường tạo cả hai cùng lúc khi bạn dùng giao diện đồ họa.

# Tạo instance profile
aws iam create-instance-profile \
  --instance-profile-name EC2S3AccessProfile

# Gắn role vào instance profile
aws iam add-role-to-instance-profile \
  --instance-profile-name EC2S3AccessProfile \
  --role-name EC2S3AccessRole

# Gắn instance profile vào EC2 instance đang chạy
# Thay i-0abcdef1234567890 bằng Instance ID thực
aws ec2 associate-iam-instance-profile \
  --instance-id i-0abcdef1234567890 \
  --iam-instance-profile Name=EC2S3AccessProfile \
  --region us-east-1

Bước 4: Xác minh credentials trên EC2 instance

Sau khi gắn Instance Profile, kiểm tra rằng EC2 thực sự nhận được temporary credentials qua IMDS. Nếu lệnh này trả về lỗi hoặc không có output, kiểm tra lại Instance Profile đã được gắn đúng chưa.

# Chạy trực tiếp trên EC2 instance
# Kiểm tra role đã được gắn
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Xem temporary credentials (thay EC2S3AccessRole bằng tên role thực)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2S3AccessRole

# Hoặc dùng AWS CLI để xác minh identity
aws sts get-caller-identity

Kinh nghiệm thực tế: Lỗi hay gặp khi migrate từ IAM User sang IAM Role

Một pattern hay gặp trong thực tế: team migrate ứng dụng từ dùng Access Key sang Instance Profile, nhưng ứng dụng vẫn tiếp tục dùng key cũ. Lý do? File ~/.aws/credentials vẫn còn trên instance và AWS SDK ưu tiên credentials theo thứ tự cố định.

AWS SDK tìm credentials theo thứ tự sau: environment variables → ~/.aws/credentials file → Instance Metadata Service. Nếu file credentials cũ vẫn tồn tại, SDK sẽ dùng key cũ thay vì Role — và bạn sẽ không thấy lỗi nào, chỉ thấy ứng dụng vẫn chạy bình thường cho đến khi key cũ bị revoke.

Triệu chứng: aws sts get-caller-identity trả về ARN của IAM User thay vì assumed-role ARN. Chẩn đoán nhầm: nghĩ Instance Profile chưa được gắn đúng. Nguyên nhân thực: credentials file cũ vẫn còn. Fix: xóa file ~/.aws/credentials~/.aws/config trên instance, sau đó kiểm tra lại.

# Kiểm tra credentials provider nào đang được dùng
aws sts get-caller-identity

# Nếu output chứa 'assumed-role' thì Instance Profile đang hoạt động đúng
# Ví dụ output đúng:
# {
#   'UserId': 'AROAXXXXXXXXXXXXXXXXX:i-0abcdef1234567890',
#   'Account': '123456789012',
#   'Arn': 'arn:aws:sts::123456789012:assumed-role/EC2S3AccessRole/i-0abcdef1234567890'
# }

# Nếu output chứa ARN của IAM User, kiểm tra credentials file
ls -la ~/.aws/
cat ~/.aws/credentials

Khi nào vẫn nên dùng IAM User?

IAM Role không phải lúc nào cũng là lựa chọn phù hợp. IAM User vẫn có ngữ cảnh sử dụng hợp lý:

  • Con người truy cập AWS Console: Developer, admin cần đăng nhập Console — đây là use case chính của IAM User.
  • CI/CD pipeline không chạy trên AWS: Nếu pipeline chạy trên GitHub Actions, GitLab CI, hay Jenkins on-premise, bạn cần credentials để xác thực. Tuy nhiên, nhiều CI/CD platform hiện đã hỗ trợ OIDC federation với AWS — cho phép dùng Role thay vì long-lived key.
  • Third-party tool không hỗ trợ IAM Role: Một số legacy tool chỉ hỗ trợ Access Key authentication.
graph TD Start(["Cần cấp quyền AWS cho ai?"]) Start --> Q1{"Con người cần
truy cập Console/CLI?"} Q1 -->|Có| IAMUser["Dùng IAM User
+ Bật MFA"] Q1 -->|Không| Q2{"Workload chạy
trên AWS?"} Q2 -->|Có| IAMRole["Dùng IAM Role
+ Instance Profile"] Q2 -->|Không| Q3{"CI/CD hoặc
External System?"} Q3 -->|Hỗ trợ OIDC| OIDCFed["OIDC Federation
với IAM Role"] Q3 -->|Không hỗ trợ OIDC| IAMUserKey["IAM User với
Access Key + Rotation Policy"] Q2 -->|Cross-account| CrossRole["IAM Role với
Cross-account Trust Policy"] style IAMRole fill:#2d8a4e,color:#fff style OIDCFed fill:#2d8a4e,color:#fff style IAMUser fill:#d4860a,color:#fff style IAMUserKey fill:#c0392b,color:#fff
  1. Nếu identity là con người cần truy cập Console hoặc CLI — dùng IAM User, cân nhắc thêm MFA.
  2. Nếu là ứng dụng chạy trên AWS (EC2, Lambda, ECS, v.v.) — luôn dùng IAM Role.
  3. Nếu là CI/CD hoặc external system — ưu tiên OIDC federation nếu platform hỗ trợ, fallback về IAM User với key rotation policy nếu không.
  4. Nếu cần cross-account access — IAM Role với cross-account trust policy là cách duy nhất được khuyến nghị.

Sự khác biệt IAM User và IAM Role trong bối cảnh bảo mật production

Một điểm ít được nhắc đến: khi EC2 instance bị compromise, attacker có thể gọi IMDS để lấy temporary credentials của Instance Profile. Đây là lý do tại sao AWS khuyến nghị dùng IMDSv2 (Instance Metadata Service version 2) thay vì IMDSv1 — IMDSv2 yêu cầu session-oriented request với PUT method trước, ngăn chặn một số vector tấn công SSRF.

# Kiểm tra phiên bản IMDS đang dùng trên instance
aws ec2 describe-instances \
  --instance-ids i-0abcdef1234567890 \
  --query 'Reservations[0].Instances[0].MetadataOptions' \
  --region us-east-1

# Bật IMDSv2 bắt buộc (require) thay vì optional
aws ec2 modify-instance-metadata-options \
  --instance-id i-0abcdef1234567890 \
  --http-tokens required \
  --http-endpoint enabled \
  --region us-east-1

Dù dùng IAM Role, phạm vi thiệt hại vẫn bị giới hạn bởi hai yếu tố: temporary credentials tự hết hạn, và Permission Policy chỉ cấp quyền tối thiểu. So với Access Key tĩnh của IAM User, đây là sự khác biệt đáng kể trong thực tế ứng phó sự cố.

Wrap-up: Sử dụng IAM User và IAM Role đúng ngữ cảnh

Nguyên tắc đơn giản: nếu đó là workload chạy trên AWS — EC2, Lambda, ECS, hay bất kỳ compute service nào — luôn dùng IAM Role. Không có lý do chính đáng nào để nhúng long-lived Access Key vào compute resource khi Instance Profile hoạt động tốt hơn ở mọi khía cạnh bảo mật và vận hành.

Tham khảo thêm tài liệu chính thức: Using IAM Roles — AWS DocumentationUsing an IAM Role to Grant Permissions to Applications on EC2.

Glossary — Thuật ngữ chính

Thuật ngữ Giải thích
IAM User Identity tồn tại lâu dài trong AWS account, có credentials cố định (password, Access Key)
IAM Role Tập hợp quyền không gắn với identity cố định, được assume để lấy temporary credentials
Instance Profile Container chứa IAM Role, cho phép EC2 instance assume Role đó
STS (Security Token Service) AWS service phát hành temporary credentials khi một entity assume IAM Role
IMDS (Instance Metadata Service) Endpoint nội bộ trên EC2 (169.254.169.254) cung cấp metadata và temporary credentials cho instance
Trust Policy Phần của IAM Role định nghĩa entity nào được phép assume Role đó

Nhận xét

Bài đăng phổ biến từ blog này

EC2 Không Có Internet Trong Custom VPC: Cách Gắn Internet Gateway và Cập Nhật Route Table

Route 53 Alias vs CNAME: Khi Nào Dùng Alias Record Cho Zone Apex?