Membuat S3 Presigned URL: Akses Sementara ke File Private dengan AWS SDK
Ketika kamu perlu memberikan akses sementara ke file private di S3 tanpa mengekspos kredensial AWS atau mengubah bucket policy, presigned URL adalah solusi yang tepat. Skenario ini muncul terus-menerus di production — misalnya user ingin mengunduh invoice PDF mereka, atau aplikasi mobile perlu streaming video dari bucket private selama sesi aktif.
TL;DR: Membuat S3 Presigned URL
| Aspek | Detail |
|---|---|
| Tujuan | Berikan akses unduh sementara ke objek S3 private |
| Expiration | Dapat dikonfigurasi — contoh ini menggunakan 1 jam (3600 detik) |
| SDK yang Digunakan | AWS SDK for Python (Boto3) dan JavaScript (v3) |
| IAM yang Diperlukan | s3:GetObject pada objek target |
| Batasan Penting | URL ditandatangani dengan kredensial pemanggil — jika kredensial kedaluwarsa sebelum URL, URL ikut tidak valid |
Bagaimana S3 Presigned URL Bekerja
Presigned URL bukan mekanisme autentikasi terpisah — ini adalah URL biasa yang menyertakan signature kriptografis dari kredensial AWS kamu sebagai bagian dari query string. Ketika S3 menerima request ke URL tersebut, S3 memvalidasi signature menggunakan Signature Version 4 (SigV4), memeriksa apakah URL belum kedaluwarsa, lalu melayani objek seolah-olah request datang langsung dari identity yang menandatanganinya.
Implikasinya: jika IAM role yang digunakan untuk membuat presigned URL di-revoke atau session token-nya kedaluwarsa sebelum presigned URL digunakan, URL tersebut akan langsung gagal meskipun expiration time belum tercapai. Ini sering menjadi sumber kebingungan di production ketika menggunakan temporary credentials dari IAM role (misalnya EC2 instance profile atau Lambda execution role).
- Aplikasi server memanggil SDK untuk menghasilkan presigned URL menggunakan kredensial IAM yang aktif.
- SDK menghitung SigV4 signature berdasarkan bucket, key, expiration, dan kredensial — tidak ada request ke S3 pada tahap ini.
- Server mengembalikan URL ke client (browser/mobile app).
- Client melakukan HTTP GET langsung ke S3 menggunakan URL tersebut — tanpa melewati server kamu.
- S3 memvalidasi signature dan expiration, lalu mengembalikan objek jika valid.
Prasyarat IAM untuk Membuat S3 Presigned URL
Identity yang memanggil operasi presigned URL generation harus memiliki izin s3:GetObject pada objek target. Tanpa izin ini, URL yang dihasilkan akan tetap menghasilkan 403 Access Denied saat digunakan — SDK tidak memvalidasi izin saat URL dibuat, hanya saat URL digunakan oleh S3.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGetObjectForPresignedURL",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::nama-bucket-kamu/*"
}
]
}
Analogi: Presigned URL seperti tiket konser yang sudah dicetak — tiket itu valid selama konser belum mulai (belum expired), tapi jika penerbit tiket (kredensial IAM) dicabut izinnya sebelum kamu masuk, tiket itu tidak akan diterima di pintu masuk (S3).
Membuat S3 Presigned URL dengan Boto3 (Python)
Boto3 menyediakan method generate_presigned_url langsung dari S3 client. Expiration diatur dalam satuan detik — untuk 1 jam, gunakan nilai 3600.
import boto3
from botocore.exceptions import ClientError
def generate_presigned_url(bucket_name, object_key, expiration=3600):
"""
Menghasilkan presigned URL untuk mengunduh objek S3 private.
:param bucket_name: Nama S3 bucket
:param object_key: Key objek di dalam bucket
:param expiration: Durasi validitas URL dalam detik (default: 3600 = 1 jam)
:return: Presigned URL sebagai string, atau None jika gagal
"""
s3_client = boto3.client('s3', region_name='us-east-1')
try:
url = s3_client.generate_presigned_url(
ClientMethod='get_object',
Params={
'Bucket': bucket_name,
'Key': object_key
},
ExpiresIn=expiration
)
return url
except ClientError as e:
print(f'Error generating presigned URL: {e}')
return None
# Contoh penggunaan
if __name__ == '__main__':
url = generate_presigned_url(
bucket_name='nama-bucket-kamu',
object_key='dokumen/invoice-2024-001.pdf'
)
if url:
print(f'Presigned URL (valid 1 jam):\n{url}')
Perhatikan bahwa region_name harus sesuai dengan region bucket. Jika client dibuat tanpa region yang tepat, URL yang dihasilkan bisa menghasilkan redirect atau error pada bucket di region tertentu.
Membuat S3 Presigned URL dengan AWS SDK JavaScript v3
Di SDK v3, presigned URL dibuat menggunakan package terpisah @aws-sdk/s3-request-presigner bersama dengan GetObjectCommand dari @aws-sdk/client-s3.
🔽 Klik untuk melihat kode JavaScript (Node.js)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3Client = new S3Client({ region: 'us-east-1' });
async function generatePresignedUrl(bucketName, objectKey, expiresInSeconds = 3600) {
const command = new GetObjectCommand({
Bucket: bucketName,
Key: objectKey,
});
try {
const url = await getSignedUrl(s3Client, command, {
expiresIn: expiresInSeconds,
});
return url;
} catch (error) {
console.error('Error generating presigned URL:', error);
throw error;
}
}
// Contoh penggunaan
generatePresignedUrl('nama-bucket-kamu', 'dokumen/invoice-2024-001.pdf')
.then(url => console.log('Presigned URL:', url))
.catch(err => console.error(err));
Membuat S3 Presigned URL via AWS CLI
Untuk kebutuhan testing atau scripting cepat, AWS CLI juga mendukung pembuatan presigned URL. Perintah berikut menghasilkan URL dengan expiration 3600 detik (1 jam):
aws s3 presign s3://nama-bucket-kamu/dokumen/invoice-2024-001.pdf \
--expires-in 3600 \
--region us-east-1
Output-nya adalah URL lengkap yang bisa langsung digunakan di browser atau di-curl. Berguna untuk memverifikasi bahwa konfigurasi IAM dan bucket sudah benar sebelum mengintegrasikan ke aplikasi.
Diagnosis: URL Menghasilkan 403 Meski Baru Dibuat
Ini adalah pola kegagalan yang paling sering ditemui di production, dan hampir selalu salah didiagnosis.
Gejala: Presigned URL berhasil dibuat oleh SDK tanpa error, tapi ketika client mencoba menggunakannya, S3 mengembalikan 403 Access Denied.
Diagnosis awal yang salah: Kebanyakan engineer langsung memeriksa bucket policy atau Block Public Access settings — padahal itu bukan masalahnya. SDK tidak memvalidasi izin saat URL dibuat.
Penyebab sebenarnya yang paling umum:
- Kredensial temporary sudah expired: Jika server kamu menggunakan IAM role (Lambda, EC2, ECS), session token bisa kedaluwarsa sebelum presigned URL digunakan. Verifikasi dengan memeriksa expiration dari credentials yang aktif.
aws sts get-caller-identity # Untuk melihat expiration session token pada temporary credentials: aws sts get-session-token --query 'Credentials.Expiration' - Identity pembuat URL tidak punya izin s3:GetObject: Cek izin efektif identity yang membuat URL.
aws iam simulate-principal-policy \ --policy-source-arn arn:aws:iam::123456789012:role/NamaRoleKamu \ --action-names s3:GetObject \ --resource-arns arn:aws:s3:::nama-bucket-kamu/dokumen/invoice-2024-001.pdf - S3 Block Public Access tidak relevan di sini — Block Public Access hanya memblokir akses berbasis ACL publik dan bucket policy publik, bukan presigned URL yang menggunakan autentikasi SigV4.
Satu hal yang tidak intuitif: presigned URL yang dibuat oleh Lambda function bisa valid selama maksimal durasi session role Lambda tersebut, bukan hanya nilai ExpiresIn yang kamu set. Jika kamu set ExpiresIn=86400 (24 jam) tapi session role Lambda hanya berlaku 1 jam, URL akan gagal setelah 1 jam — bukan 24 jam.
dengan Presigned URL] --> B{URL sudah
melewati ExpiresIn?} B -- Ya --> C[403 Access Denied
Request Expired] B -- Tidak --> D{SigV4 Signature
valid?} D -- Tidak --> E[403 Access Denied
Invalid Signature] D -- Ya --> F{Session credentials
masih aktif?} F -- Tidak --> G[403 Access Denied
Credentials Expired] F -- Ya --> H[200 OK
Objek dikembalikan]
- S3 menerima request dengan presigned URL.
- S3 pertama-tama memeriksa apakah URL sudah melewati
ExpiresIn— jika ya, langsung403. - Jika belum expired, S3 memvalidasi SigV4 signature menggunakan kredensial yang tertanam di URL.
- Jika signature valid tapi kredensial underlying sudah di-revoke atau session expired, hasilnya tetap
403. - Jika semua valid, S3 mengembalikan objek.
Praktik Terbaik Operasional untuk S3 Presigned URL
- Gunakan expiration sesingkat mungkin yang masih fungsional untuk use case kamu. URL dengan expiration panjang yang bocor ke log atau third-party service bisa dieksploitasi.
- Jangan log presigned URL secara lengkap di application log — perlakukan seperti secret. Log hanya metadata seperti bucket, key, dan waktu pembuatan.
- Untuk file besar atau unduhan yang sering diulang, pertimbangkan CloudFront dengan signed URL atau signed cookies sebagai alternatif yang lebih scalable.
- Jika menggunakan IAM role dengan temporary credentials, pastikan
ExpiresInpresigned URL tidak melebihi sisa durasi session credentials yang digunakan untuk menandatanganinya.
Wrap-Up: S3 Presigned URL di Production
Membuat S3 presigned URL itu sederhana secara mekanis, tapi memahami model kepercayaannya — bahwa URL mewarisi validitas dari kredensial pembuatnya — adalah yang membedakan implementasi yang robust dari yang rapuh. Untuk langkah selanjutnya, pelajari dokumentasi resmi AWS tentang Sharing objects with presigned URLs dan pertimbangkan apakah use case kamu lebih cocok menggunakan CloudFront signed URL untuk distribusi konten skala besar.
Glosarium
| Istilah | Penjelasan |
|---|---|
| Presigned URL | URL S3 yang menyertakan signature kriptografis sehingga siapa pun yang memilikinya bisa mengakses objek tanpa kredensial AWS sendiri |
| SigV4 (Signature Version 4) | Protokol penandatanganan request AWS yang digunakan untuk mengautentikasi request ke layanan AWS termasuk S3 |
| Temporary Credentials | Kredensial AWS (access key + secret + session token) yang dikeluarkan oleh STS dengan durasi terbatas, biasanya digunakan oleh IAM role |
| s3:GetObject | Izin IAM yang diperlukan untuk membaca/mengunduh objek dari S3 bucket |
| ExpiresIn | Parameter SDK yang menentukan berapa lama (dalam detik) presigned URL valid sejak dibuat |
Komentar
Posting Komentar