Menguasai fondasi keamanan cloud: users, roles, dan policies, prinsip least privilege, service accounts, permission boundary, serta SCP, lengkap dengan praktik setup IAM role dan policy yang benar lewat CLI dan Terraform beserta kesalahan umum seperti wildcard action dan access key berumur panjang

Setelah di episode 2 kita memetakan shared responsibility dan lapisan-lapisan security cloud, sekarang kita turun ke lapisan pertama dan paling menentukan: identity. Di cloud modern, identitas adalah perimeter baru. Firewall yang sempurna tidak berarti apa-apa jika sebuah IAM policy memberi izin *:* kepada service account yang tokennya bisa dicuri.
Mengapa episode ini sangat penting? Karena mayoritas privilege escalation dan exfiltrasi data di cloud dimulai dari konfigurasi IAM yang terlalu longgar — bukan dari eksploitasi kernel yang eksotis. Menguasai IAM berarti kalian bisa menutup kelas serangan terbesar di cloud dengan kode beberapa baris policy.
Tiga objek dasar yang wajib kalian bedakan dengan tajam:
| Objek | Definisi | Kapan Dipakai |
|---|---|---|
| User | Identitas permanen untuk manusia atau system | Seminimal mungkin — prefer federasi |
| Role | Identitas yang diasumsikan sementara, tanpa password/key permanen | Default untuk service dan lintas-akun |
| Policy | Dokumen JSON yang mendefinisikan izin | Menempel pada user, role, atau resource |
Aturan emas: role over user. Role menghasilkan kredensial sementara (STS token) yang otomatis kedaluwarsa, sedangkan user dengan access key statis adalah bom waktu — key yang bocor tetap valid sampai dirotasi manual.
Policy JSON punya struktur Effect, Action, Resource, dan opsional Condition. Contoh policy read-only untuk satu bucket tertentu:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::app-assets-prod",
"arn:aws:s3:::app-assets-prod/*"
]
}
]
}Perhatikan Resource yang spesifik hingga ARN bucket — inilah lawan dari arn:aws:s3:::* yang memberi akses ke seluruh storage organisasi.
Least privilege mudah dikatakan, sulit dieksekusi karena izin nyata baru terlihat setelah beban kerja berjalan. Alur kerja yang pragmatis:
AccessDenied muncul.Contoh men-generate policy dari aktivitas nyata:
aws iam generate-organizations-access-report --entity-path o-xxxxx/account/123456789012-role/app-runtime
aws accessanalyzer start-policy-generation \
--policy-generation-details principalArn=arn:aws:iam::123456789012:role/app-runtime,cloudTrailDetails='{}'Tip
Metrik yang layak dilaporkan tiap bulan: jumlah identitas dengan akses administratif dan persentase policy yang memakai wildcard. Jika angka itu naik, least privilege kalian sedang tergerus — bahkan tanpa insiden apa pun.
Aplikasi juga butuh identitas — dan di sinilah kesalahan paling mahal sering terjadi. Prinsipnya: satu workload, satu role, nol kredensial statis.
Perbandingan pola yang benar vs salah:
Resources:
AppRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: {Statement: [{Effect: Allow, Principal: {Service: ec2.amazonaws.com}, Action: sts:AssumeRole}]}
ManagedPolicyArns: [arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess]Versi "benar" memberi kredensial yang dirotasi otomatis oleh platform dan bisa dicabut dengan menghapus role.
Dua mekanisme yang membuat least privilege bertahan skala besar:
AdministratorAccess, boundary tetap memotong.Contoh SCP yang mencegah region liar:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyNonApprovedRegions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {"aws:RequestedRegion": ["ap-southeast-1", "us-east-1"]}
}
}]
}Guardrail semacam ini bekerja sebelum resource lahir — jauh lebih murah daripada remediation sesudahnya. Episode 11 dan 25 akan memperluas pola ini ke policy-as-code dan architecture review.
Mari bangun role untuk aplikasi yang hanya boleh membaca objek dari satu bucket. Pertama lewat Terraform — cara yang direkomendasikan karena tereview dan ter-versi:
resource "aws_iam_role" "app_runtime" {
name = "app-runtime"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "app_s3_read" {
name = "s3-read-app-assets"
role = aws_iam_role.app_runtime.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject"]
Resource = "arn:aws:s3:::app-assets-prod/*"
}]
})
}Terapkan dan verifikasi:
terraform init && terraform apply -auto-approve
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/app-runtime \
--action-names s3:GetObject s3:DeleteObject \
--resource-arns arn:aws:s3:::app-assets-prod/file.pngsimulate-principal-policy adalah alat verifikasi favorit: ia menjawab "boleh atau tidak" tanpa harus mencoba aksi aslinya. Hasil yang diharapkan: s3:GetObject bernilai allowed, s3:DeleteObject bernilai explicitDeny atau implicitDeny.
Action: "*", Resource: "*" — izin dewa; hampir selalu hasil copy-paste tutorial.Principal: "*" pada assume role mempersilakan akun lain mengambil role kalian.Warning
Aktifkan MFA enforcement sekarang, bukan nanti: policy Deny dengan kondisi aws:MultiFactorAuthPresent = false untuk semua aksi sensitif. Akun konsol tanpa MFA adalah vektor takeover termudah di cloud.
Inti yang harus dibawa pulang:
simulate-principal-policy, bukan trial-and-error di production.Di episode 4 selanjutnya kita naik ke lapisan kedua: cloud network security — desain VPC, security groups vs NACL, segmentasi, dan egress control yang membuat lateral movement jadi sulit. Sampai jumpa!