Struktur Dasar IAM Policy JSON: Memahami Effect, Action, Resource, dan Condition
Pertama kali membuka IAM policy di konsol AWS, sebagian besar engineer langsung fokus ke bagian Action dan Resource — lalu bertanya-tanya kenapa akses masih ditolak meski policy sudah terpasang. Memahami struktur dasar IAM policy JSON, khususnya interaksi antara elemen Effect, Action, Resource, dan Condition, adalah fondasi yang menentukan apakah sistem authorization kamu bekerja seperti yang diharapkan atau gagal secara diam-diam.
TL;DR: Struktur Dasar IAM Policy
| Elemen | Fungsi | Nilai Umum |
|---|---|---|
Effect | Menentukan izin atau penolakan | Allow / Deny |
Action | Operasi API yang diizinkan atau ditolak | s3:GetObject, ec2:DescribeInstances |
Resource | ARN target yang berlaku untuk statement ini | ARN spesifik atau * |
Condition | Syarat tambahan yang harus terpenuhi | IP range, MFA status, tag |
Bagaimana IAM Policy Bekerja: Mekanisme Evaluasi
IAM policy bukan sekadar daftar izin. AWS mengevaluasi setiap API call melalui serangkaian lapisan keputusan — dari SCP di level Organization, permission boundary, resource-based policy, hingga identity-based policy yang kamu tulis. Memahami urutan evaluasi ini penting karena explicit Deny selalu menang, bahkan jika ada Allow di policy lain.
- Default Deny — Semua request ditolak secara default. Tidak ada akses tanpa Allow yang eksplisit.
- SCP Check — Jika akun berada dalam AWS Organization, SCP dievaluasi pertama. SCP yang tidak mengizinkan action akan memblokir meski ada Allow di IAM policy.
- Explicit Deny Check — Jika ada statement dengan
Effect: Denyyang cocok, evaluasi berhenti dan akses ditolak. - Allow Check — Jika ada statement dengan
Effect: Allowyang cocok dan tidak ada Deny yang menghalangi, akses diberikan. - Implicit Deny — Jika tidak ada Allow yang cocok, akses ditolak secara implisit.
Anatomi IAM Policy JSON: Struktur Dasar IAM Policy
Setiap IAM policy terdiri dari satu atau lebih statement. Setiap statement adalah unit keputusan independen yang menggabungkan keempat elemen utama.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
],
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
}
]
}
Elemen Version bukan versi policy kamu — ini adalah versi bahasa policy IAM. Selalu gunakan 2012-10-17. Versi lama 2008-10-17 tidak mendukung policy variable seperti ${aws:username}.
Elemen Effect: Allow vs Deny
Hanya ada dua nilai valid: Allow dan Deny. Perbedaan kritis yang sering diabaikan adalah bahwa Deny eksplisit tidak bisa di-override oleh Allow manapun — termasuk policy yang di-attach ke role lain, inline policy, atau bahkan AdministratorAccess.
Bayangkan
Denyseperti gembok fisik di pintu — tidak peduli berapa banyak kunci Allow yang kamu punya, gembok itu tetap mengunci.Allowhanya bekerja di ruang kosong yang tidak dikunci oleh Deny.
Gunakan Deny secara strategis — misalnya untuk memblokir region tertentu atau mencegah penghapusan resource kritis, bukan sebagai mekanisme primary access control.
Verifikasi effective permissions pada identity menggunakan IAM Policy Simulator atau CLI:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/ExampleRole \
--action-names s3:DeleteBucket \
--resource-arns arn:aws:s3:::example-bucket
Elemen Action: Menentukan Operasi API
Nilai Action adalah mapping langsung ke operasi API AWS, dengan format service:OperationName. Satu karakter salah di sini — misalnya s3:Getobject alih-alih s3:GetObject — dan policy tidak akan pernah match, tanpa error apapun.
Wildcard * bisa digunakan di level service (s3:*) atau di level operasi (s3:Get*). Gunakan wildcard dengan hati-hati karena cakupannya bisa lebih luas dari yang kamu perkirakan — s3:Get* mencakup s3:GetBucketPolicy, s3:GetEncryptionConfiguration, dan banyak operasi lainnya.
Daftar lengkap action untuk setiap service harus selalu diperiksa di AWS Service Authorization Reference. Tidak ada perintah CLI tunggal yang dapat mendaftar semua action yang tersedia untuk sebuah service — referensi dokumentasi resmi adalah satu-satunya sumber yang akurat dan lengkap.
Untuk memeriksa policy yang sudah ada pada sebuah managed policy:
aws iam get-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/ExamplePolicy \
--version-id v1
Elemen Resource: Target ARN yang Tepat
Ini adalah elemen yang paling sering menjadi sumber bug tersembunyi. Resource menentukan AWS resource mana yang berlaku untuk statement ini, menggunakan format ARN.
Kesalahan klasik dengan S3: policy yang hanya mencantumkan arn:aws:s3:::example-bucket akan mengizinkan operasi bucket-level seperti s3:ListBucket, tapi tidak mengizinkan operasi object-level seperti s3:GetObject. Untuk object, kamu butuh arn:aws:s3:::example-bucket/* sebagai resource terpisah.
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::example-bucket"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::example-bucket/*"
}
Beberapa action IAM tidak mendukung resource-level permission dan harus menggunakan "Resource": "*". Contohnya banyak operasi Describe* dan List* di EC2 dan IAM. Selalu verifikasi di Service Authorization Reference sebelum mencoba membatasi resource pada action tersebut — membatasi resource pada action yang tidak mendukungnya akan menyebabkan policy tidak pernah match.
Verifikasi ARN resource yang benar untuk Lambda function:
aws lambda get-function \
--function-name ExampleFunction \
--query 'Configuration.FunctionArn'
Elemen Condition: Kontrol Akses Kontekstual
Elemen Condition adalah lapisan kontrol yang paling powerful sekaligus paling mudah salah dikonfigurasi. Condition menambahkan syarat yang harus terpenuhi agar statement berlaku — jika condition tidak terpenuhi, statement di-skip sepenuhnya (bukan ditolak).
- Condition Operator — Menentukan jenis perbandingan:
StringEquals,IpAddress,Bool,ArnLike, dan lainnya. - Condition Key — Konteks request yang dievaluasi:
aws:SourceIp,aws:MultiFactorAuthPresent,s3:prefix, dll. - Condition Value — Nilai yang dibandingkan dengan condition key.
- Multiple Conditions — Jika ada beberapa condition key dalam satu operator, semua harus terpenuhi (AND logic). Jika ada beberapa operator, semua harus terpenuhi (AND logic antar operator).
Contoh penggunaan condition untuk membatasi akses hanya dari VPC endpoint tertentu:
{
"Effect": "Deny",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-0123456789abcdef0"
}
}
}
Pola di atas menggunakan Deny dengan StringNotEquals — artinya akses ditolak jika request tidak berasal dari VPC endpoint yang ditentukan. Ini lebih robust daripada Allow dengan StringEquals karena Deny tidak bisa di-override.
Pengalaman Lapangan: Misdiagnosis yang Umum Terjadi
Skenario ini terjadi cukup sering: engineer menambahkan policy dengan s3:GetObject Allow ke sebuah role, tapi aplikasi masih mendapat AccessDenied. Pemeriksaan pertama biasanya ke IAM policy — policy terlihat benar. Pemeriksaan kedua ke bucket policy — tidak ada Deny eksplisit. Lalu menyerah dan menambahkan s3:* pada Resource: *, yang 'berhasil' tapi membuka akses jauh lebih luas dari yang dibutuhkan.
Penyebab sebenarnya: bucket memiliki S3 Block Public Access aktif di level akun, dan bucket policy menggunakan condition aws:SecureTransport yang menolak request non-HTTPS. SDK yang digunakan aplikasi dikonfigurasi tanpa SSL endpoint yang benar. Dua lapisan kondisi yang berbeda, keduanya harus dipenuhi.
Cara mendiagnosis dengan benar — periksa effective policy evaluation:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/AppRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::example-bucket/path/to/object \
--context-entries '[{"ContextKeyName":"aws:SecureTransport","ContextKeyValues":["false"],"ContextKeyType":"boolean"}]'
Output simulator akan menunjukkan implicitDeny atau explicitDeny beserta policy mana yang menjadi penyebabnya — jauh lebih informatif daripada menebak-nebak.
Insight yang sering terlewat: condition yang tidak terpenuhi tidak menghasilkan Deny — statement tersebut hanya tidak berlaku. Ini berarti jika kamu mengandalkan Deny dengan condition untuk keamanan, pastikan tidak ada Allow lain yang bisa bypass kondisi tersebut.
IAM Policy Minimal dengan Least Privilege
Berikut contoh policy lengkap yang mengikuti prinsip least privilege — memberikan akses baca ke S3 bucket spesifik, hanya dari region tertentu, dan hanya jika MFA aktif:
🔽 Klik untuk melihat contoh policy lengkap
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBucketWithMFA",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
},
"StringEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
},
{
"Sid": "GetObjectWithMFA",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
},
"StringEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
}
]
}
Attach policy ke role menggunakan CLI:
aws iam put-role-policy \
--role-name ExampleRole \
--policy-name S3ReadWithMFA \
--policy-document file://policy.json
Wrap-Up: Struktur Dasar IAM Policy dan Langkah Selanjutnya
Keempat elemen — Effect, Action, Resource, dan Condition — bekerja bersama sebagai unit keputusan dalam setiap statement. Kesalahan di satu elemen tidak menghasilkan error yang jelas, hanya akses yang tidak bekerja seperti yang diharapkan. Gunakan IAM Policy Simulator sebagai alat diagnostik utama sebelum menyimpulkan bahwa policy sudah benar.
Untuk memperdalam pemahaman, baca juga artikel tentang IAM Role vs IAM User dan Resource-Based Policy vs Identity-Based Policy di blog ini.
Referensi resmi yang wajib di-bookmark:
Glosarium
| Istilah | Definisi |
|---|---|
| Statement | Unit keputusan tunggal dalam IAM policy yang menggabungkan Effect, Action, Resource, dan Condition. |
| ARN (Amazon Resource Name) | Identifier unik untuk setiap AWS resource, dengan format arn:aws:service:region:account-id:resource. |
| Explicit Deny | Statement dengan Effect: Deny yang secara aktif menolak akses dan tidak bisa di-override oleh Allow manapun. |
| Condition Key | Atribut konteks request (seperti IP address, MFA status, atau tag) yang dievaluasi dalam elemen Condition. |
| Least Privilege | Prinsip keamanan yang memberikan hanya izin minimum yang dibutuhkan untuk menjalankan fungsi yang diperlukan. |
Komentar
Posting Komentar