S3 Access Denied Meski Objek Sudah Publik: Cara Kerja Block Public Access dan Cara Memperbaikinya

Kamu upload gambar ke S3, set ACL-nya ke public-read, lalu buka URL-nya di browser — dan yang muncul malah Access Denied. Ini salah satu sumber frustrasi paling umum di S3, dan hampir selalu disebabkan oleh satu hal: Block Public Access di level bucket atau akun sedang aktif, dan itu menimpa semua izin yang kamu set di level objek.

TL;DR: Kenapa S3 Access Denied Terjadi Meski Objek Sudah Publik

KondisiHasil Akses Publik
Block Public Access aktif di akun atau bucketAccess Denied — semua ACL/policy publik diabaikan
Block Public Access nonaktif, tapi tidak ada ACL atau bucket policyAccess Denied — default S3 private
Block Public Access nonaktif, objek punya ACL public-readAkses publik berhasil
Block Public Access nonaktif, bucket policy mengizinkan s3:GetObject untuk *Akses publik berhasil
Object Ownership = BucketOwnerEnforcedACL dinonaktifkan — public-read tidak berlaku

Bagaimana S3 Public Access Benar-Benar Bekerja

Banyak yang mengira izin S3 itu satu lapis: set objek ke publik, selesai. Kenyataannya ada tiga lapis kontrol yang harus semuanya 'mengizinkan' sebelum request anonim bisa berhasil. Block Public Access adalah lapisan paling atas, dan ia bersifat override — bukan additive.

graph TD A["Request Publik Anonim"] --> B{"Account-Level Block Public Access?"} B -- "Aktif" --> Z1["Access Denied"] B -- "Nonaktif" --> C{"Bucket-Level Block Public Access?"} C -- "Aktif" --> Z2["Access Denied"] C -- "Nonaktif" --> D{"Ada Explicit Deny di Bucket Policy?"} D -- "Ya" --> Z3["Access Denied"] D -- "Tidak" --> E{"Object Ownership = BucketOwnerEnforced?"} E -- "Ya" --> F{"Bucket Policy Allow s3:GetObject *?"} E -- "Tidak" --> G{"ACL Objek = public-read?"} F -- "Ya" --> OK1["Akses Berhasil"] F -- "Tidak" --> Z4["Access Denied"] G -- "Ya" --> H{"IgnorePublicAcls Aktif?"} G -- "Tidak" --> Z5["Access Denied"] H -- "Ya" --> Z6["Access Denied"] H -- "Tidak" --> OK2["Akses Berhasil"]
  1. Block Public Access (BPA) — dievaluasi pertama. Jika aktif, request publik langsung ditolak tanpa melihat ACL atau bucket policy sama sekali.
  2. Bucket Policy — dievaluasi setelah BPA. Jika ada Deny eksplisit, request ditolak. Jika ada Allow untuk principal *, akses publik diizinkan (asalkan BPA tidak menghalangi).
  3. Object ACL — dievaluasi terakhir. public-read hanya berlaku jika BPA tidak aktif dan Object Ownership tidak disetel ke BucketOwnerEnforced.
Analoginya seperti gedung dengan tiga pintu berurutan. Block Public Access adalah pintu pertama yang dikunci dari luar. Tidak peduli kunci pintu kedua dan ketiga ada di tanganmu — kalau pintu pertama terkunci, kamu tidak akan pernah sampai ke sana.

Satu hal yang sering terlewat: Block Public Access bisa aktif di dua level berbeda — level akun (S3 Account Settings) dan level bucket. Keduanya independen, dan keduanya bisa memblokir akses. Kamu bisa sudah menonaktifkan BPA di bucket, tapi kalau di level akun masih aktif, hasilnya tetap Access Denied.

Empat Setting Block Public Access yang Perlu Kamu Pahami

BPA bukan satu toggle — ada empat pengaturan terpisah, dan masing-masing punya efek berbeda.

SettingApa yang Diblokir
BlockPublicAclsMencegah penambahan ACL publik baru pada bucket atau objek
IgnorePublicAclsMengabaikan semua ACL publik yang sudah ada — ini yang paling sering jadi penyebab masalah
BlockPublicPolicyMencegah penambahan bucket policy yang mengizinkan akses publik
RestrictPublicBucketsMembatasi akses ke bucket yang punya policy publik — hanya AWS service dan akun yang diotorisasi yang bisa akses

Dalam kasus upload gambar yang tiba-tiba Access Denied, IgnorePublicAcls adalah tersangka utama. Kamu sudah set public-read di objek, tapi S3 secara diam-diam mengabaikannya.

Diagnosis S3 Access Denied: Langkah per Langkah

Langkah 1: Cek Block Public Access di Level Akun

Mulai dari sini karena ini yang paling sering terlewat. Banyak tim mengira mereka sudah 'fix' masalah di bucket, padahal blokade sebenarnya ada di level akun. Kalau level akun masih memblokir, perubahan apapun di bucket tidak akan berpengaruh.

aws s3control get-public-access-block \
  --account-id 123456789012

Output yang perlu diperhatikan:

{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": true,
        "RestrictPublicBuckets": true
    }
}

Jika salah satu atau semua bernilai true dan kamu memang butuh akses publik, kamu perlu menonaktifkannya di level akun terlebih dahulu.

Langkah 2: Cek Block Public Access di Level Bucket

Setelah level akun bersih, cek level bucket. Keduanya independen — menonaktifkan di akun tidak otomatis menonaktifkan di bucket.

aws s3api get-public-access-block \
  --bucket nama-bucket-kamu

Struktur output-nya sama dengan level akun. Perhatikan nilai IgnorePublicAcls dan RestrictPublicBuckets — keduanya yang paling sering memblokir akses publik via ACL.

Langkah 3: Cek Object Ownership Setting

Ini sering jadi 'hidden gotcha'. Sejak AWS memperkenalkan Object Ownership, bucket baru secara default menggunakan BucketOwnerEnforced — yang berarti ACL sepenuhnya dinonaktifkan. Kamu bisa set public-read seribu kali, tidak akan ada efeknya.

aws s3api get-bucket-ownership-controls \
  --bucket nama-bucket-kamu

Jika output menunjukkan BucketOwnerEnforced, ACL tidak berlaku. Kamu harus menggunakan bucket policy sebagai gantinya untuk mengizinkan akses publik.

Langkah 4: Verifikasi ACL Objek

Setelah memastikan BPA tidak aktif dan Object Ownership mengizinkan ACL, baru cek apakah ACL objek benar-benar sudah ter-set dengan benar. Langkah ini tidak berguna sebelum tiga langkah di atas bersih — itulah kenapa urutannya penting.

aws s3api get-object-acl \
  --bucket nama-bucket-kamu \
  --key path/ke/gambar.jpg

Cari grant dengan URI: http://acs.amazonaws.com/groups/global/AllUsers dan permission READ. Jika tidak ada, ACL belum ter-set dengan benar.

Langkah 5: Cek Bucket Policy

Jika kamu memilih menggunakan bucket policy daripada ACL (yang direkomendasikan untuk bucket baru), pastikan policy-nya benar dan tidak ada Deny eksplisit yang menimpa Allow.

aws s3api get-bucket-policy \
  --bucket nama-bucket-kamu

Jika tidak ada policy sama sekali, command ini akan mengembalikan error NoSuchBucketPolicy — bukan output kosong.

graph LR A["Mulai Diagnosis"] --> B["1. Cek Account-Level BPA s3control get-public-access-block"] B --> C{"BPA Aktif di Akun?"} C -- "Ya" --> D["Nonaktifkan BPA di Level Akun"] C -- "Tidak" --> E["2. Cek Bucket-Level BPA s3api get-public-access-block"] D --> E E --> F{"BPA Aktif di Bucket?"} F -- "Ya" --> G["Nonaktifkan BPA di Level Bucket"] F -- "Tidak" --> H["3. Cek Object Ownership get-bucket-ownership-controls"] G --> H H --> I{"BucketOwnerEnforced?"} I -- "Ya" --> J["Gunakan Bucket Policy bukan ACL"] I -- "Tidak" --> K["4. Cek ACL Objek get-object-acl"] J --> OK["Akses Publik Berhasil"] K --> L{"ACL public-read Sudah Ada?"} L -- "Tidak" --> M["Set ACL: put-object-acl --acl public-read"] L -- "Ya" --> N["5. Cek Bucket Policy get-bucket-policy"] M --> OK N --> OK

Solusi: Dua Pendekatan untuk Mengizinkan Akses Publik S3

Pendekatan A: Menggunakan Bucket Policy (Direkomendasikan)

Ini pendekatan yang lebih modern dan tidak bergantung pada ACL. Cocok untuk bucket baru dengan BucketOwnerEnforced.

Langkah 1: Nonaktifkan Block Public Access yang relevan di bucket

aws s3api put-public-access-block \
  --bucket nama-bucket-kamu \
  --public-access-block-configuration \
    'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'

Jika level akun juga memblokir, nonaktifkan di sana dulu:

aws s3control put-public-access-block \
  --account-id 123456789012 \
  --public-access-block-configuration \
    'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'

Langkah 2: Buat bucket policy yang mengizinkan s3:GetObject untuk semua principal

🔽 Klik untuk melihat bucket policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::nama-bucket-kamu/*"
    }
  ]
}
aws s3api put-bucket-policy \
  --bucket nama-bucket-kamu \
  --policy file://bucket-policy.json

Pendekatan B: Menggunakan Object ACL (Untuk Bucket dengan ACL Aktif)

Gunakan pendekatan ini hanya jika Object Ownership bucket kamu disetel ke BucketOwnerPreferred atau ObjectWriter — bukan BucketOwnerEnforced.

Langkah 1: Pastikan IgnorePublicAcls dan BlockPublicAcls dinonaktifkan (sama seperti Pendekatan A, Langkah 1).

Langkah 2: Set ACL objek ke public-read

aws s3api put-object-acl \
  --bucket nama-bucket-kamu \
  --key path/ke/gambar.jpg \
  --acl public-read

Atau saat upload:

aws s3 cp gambar.jpg s3://nama-bucket-kamu/path/ke/gambar.jpg \
  --acl public-read

Pola Kegagalan Nyata: Misdiagnosis yang Sering Terjadi

Skenario yang paling sering terjadi: developer baru bergabung ke tim, membuat bucket S3 baru, upload gambar, set public-read, dan bingung kenapa URL-nya tetap Access Denied. Mereka cek bucket-level BPA — sudah dinonaktifkan. Mereka cek ACL objek — sudah public-read. Semua terlihat benar.

Yang terlewat: account-level Block Public Access masih aktif. Tim security mengaktifkannya sebagai baseline di seluruh akun, tapi tidak ada yang mendokumentasikannya. Bucket-level BPA yang sudah dinonaktifkan tidak ada artinya karena account-level BPA menimpa segalanya.

Fix-nya satu command:

aws s3control get-public-access-block --account-id 123456789012

Dan terlihat semua empat setting bernilai true. Inilah kenapa diagnosis selalu harus dimulai dari level akun, bukan level bucket.

Ada satu lagi yang lebih subtle: bucket dibuat setelah April 2023, ketika AWS mengubah default Object Ownership menjadi BucketOwnerEnforced. Developer yang terbiasa dengan bucket lama mengasumsikan ACL masih bekerja. Mereka set public-read, BPA sudah nonaktif, tapi akses tetap gagal — karena ACL sudah sepenuhnya dinonaktifkan di level bucket. Tidak ada error message yang menjelaskan ini secara eksplisit. S3 hanya mengembalikan Access Denied.

Pertimbangan Keamanan Sebelum Membuat Bucket Publik

Block Public Access ada karena alasan yang bagus. Sebelum menonaktifkannya, pastikan kamu memang butuh akses publik anonim — bukan sekadar akses dari aplikasi atau user tertentu.

  • Jika konten hanya perlu diakses oleh user yang sudah login, gunakan pre-signed URL daripada membuat bucket publik.
  • Jika konten perlu diakses secara publik tapi dengan kontrol lebih, pertimbangkan CloudFront dengan Origin Access Control (OAC) — bucket tetap private, CloudFront yang mengakses S3.
  • Jangan pernah menonaktifkan BPA di level akun hanya untuk satu bucket. Nonaktifkan di level bucket saja.
  • Audit bucket publik secara berkala menggunakan S3 Storage Lens atau AWS Config rule s3-bucket-public-read-prohibited.

Wrap-Up: Checklist S3 Access Denied dan Langkah Selanjutnya

Ketika menghadapi S3 Access Denied pada objek yang seharusnya publik, urutan diagnosis yang benar adalah: account-level BPA → bucket-level BPA → Object Ownership → ACL atau bucket policy. Melewati urutan ini adalah alasan utama kenapa masalah ini butuh waktu lama untuk di-debug.

Untuk setup baru, gunakan bucket policy daripada ACL — lebih eksplisit, lebih mudah di-audit, dan tidak terpengaruh oleh perubahan default Object Ownership di masa depan.

Referensi resmi yang relevan:

Glosarium

IstilahPenjelasan
Block Public Access (BPA)Fitur S3 yang memblokir akses publik di level akun atau bucket, menimpa ACL dan bucket policy
Object ACLAccess Control List pada level objek individual, mengontrol siapa yang bisa membaca atau menulis objek tersebut
Bucket PolicyDokumen JSON yang mendefinisikan izin akses ke bucket dan objek di dalamnya menggunakan IAM policy language
Object OwnershipSetting bucket yang mengontrol apakah ACL diaktifkan dan siapa yang memiliki objek yang diupload ke bucket
Pre-signed URLURL sementara yang memberikan akses ke objek S3 private tanpa membuat bucket publik

Komentar

Postingan populer dari blog ini

EC2 Tidak Bisa Akses Internet di Custom VPC: Cara Pasang Internet Gateway dan Update Route Table