Emulator untuk develop, bukan penyimpanan: hindari data produksi, sanitasi secret, isolasi workspace antar developer, dan aturan PERSISTENCE agar state tetap aman dan reproducible.

Di episode 14 kita membuka kotak hitam autentikasi LocalStack: kredensial palsu, evaluasi policy IAM, dan batasan emulasinya. Kini kita bicara hal yang lebih praktis tapi sering terlupakan: keamanan dan kebersihan environment. LocalStack terasa persis seperti AWS sungguhan, sehingga naluri "ini cuma emulator" membuat kita lengah. Akibatnya, data produksi masuk ke emulator, secret bocor ke log, dan state antar developer saling menimpa. Episode ini menyusun aturan main agar LocalStack nyaman dipakai tanpa menciptakan risiko produksi.
Aturan pertama dan paling penting: jangan pernah mengimpor data produksi ke LocalStack. Analoginya seperti membawa dompet asli ke toko mainan — tanpa sadar kita membawa aset berharga ke tempat yang bukan seharusnya. Data produksi biasanya berisi PII, token, atau data finansial. Begitu masuk ke mesin lokal, data itu keluar dari perimeter akun AWS: laptop hilang, volume ikut terbawa, dan snapshot repository bisa ter-upload ke lokasi yang salah.
Gantikan data asli dengan data sintetis. Untuk realisme bentuk tanpa makna, bangkitkan data sendiri:
import boto3
from faker import Faker
fake = Faker()
dynamodb = boto3.client("dynamodb", endpoint_url="http://localhost:4566")
for _ in range(100):
dynamodb.put_item(
TableName="users",
Item={"id": {"S": fake.uuid4()}, "email": {"S": fake.email()}},
)Jika skenario memang butuh sampel struktur data produksi, ambil skema dan contoh kecil yang sudah dianonimisasi — bukan dump mentahnya.
Sekalipun data sudah dianonimisasi, secret bisa saja terselip di dalamnya. Sebelum mengimpor, scrub nilai yang menyerupai kredensial atau token. Pola umum adalah access key AWS (AKIA...) atau token panjang seperti ghp_...:
sed -i 's/AKIA[0-9A-Z]\{16\}/AKIAFAKEFAKEFAKEFAKE/g' users.json
sed -i 's/ghp_[a-zA-Z0-9]\{36\}/ghp_FAKE_TOKEN_PLACEHOLDER/g' users.json
sed -i 's/Bearer [a-zA-Z0-9._-]\{20,\}/Bearer TOKEN_PLACEHOLDER/g' users.jsonAturan praktisnya: nilai apa pun yang jika bocor akan berbahaya wajib diganti sebelum menyentuh emulator. Kredensial produksi juga tidak boleh mengalir ke log atau environment LocalStack yang dibagikan antar developer.
LocalStack pada dasarnya satu state di satu mesin. Jika satu tim memakai instance bersama, developer A yang menghapus tabel akan merusak kerja developer B. Solusinya: satu instance per developer dengan port berbeda. Contoh pemetaan:
| Developer | Port | Endpoint |
|---|---|---|
| A | 4566 | http://localhost:4566 |
| B | 4567 | http://localhost:4567 |
| C | 4568 | http://localhost:4568 |
Developer B menjalankan instance sendiri di port 4567:
docker run -d --name localstack-dev-b \
-p 4567:4566 -p 4510-4559:4510-4559 \
-e SERVICES=s3,dynamodb,sqs \
localstack/localstack:stableLalu arahkan client ke port tersebut:
export AWS_ENDPOINT_URL=http://localhost:4567
awslocal s3 mb s3://isolated-bucketSatu catatan penting: meski port berbeda, volume data default bisa sama bila tidak diatur. Pastikan setiap instance memakai volume atau VOLUME_DIR sendiri agar benar-benar terisolasi.
Test membutuhkan determinisme: mulai kosong, seed yang sama, lalu teardown. Kalau state dev ikut tercampur, test menjadi flaky — kadang lulus, kadang gagal tergantung data tersisa. Cara paling sederhana: dua profil Compose, dev memakai PERSISTENCE, test tidak:
services:
localstack:
image: localstack/localstack:stable
ports:
- "4566:4566"
environment:
PERSISTENCE: 0
DEBUG: 1Jalankan hanya untuk sesi test dengan docker compose -f docker-compose.test.yml up -d. Setelah selesai, instance dibuang dan state kembali kosong untuk run berikutnya.
PERSISTENCE=1 membuat state bertahan antar restart — sangat nyaman untuk dev, sangat berbahaya untuk test. Masalah umumnya: data basi tersimpan sehingga konfigurasi tidak reproducible, atau state sensitif ikut tertinggal di volume. Pedoman ringkasnya:
| Environment | PERSISTENCE | Alasan |
|---|---|---|
| Dev lokal | 1 | Kerja lanjut tanpa reset |
| Test suite | 0 | State bersih per run |
| CI | 0 | Reproducible dari nol |
| Demo/workshop | 1 + volume bernama | Bisa di-rollback |
Untuk dev, pisahkan volume per project supaya tidak saling menimpa:
docker run -d --name localstack-dev \
-v localstack_dev_data:/var/lib/localstack \
-e PERSISTENCE=1 \
-p 4566:4566 localstack/localstack:stableJangan menyalin pasangan default test/test begitu saja ke CI — ganti dengan nilai unik agar mudah dilacak jika muncul di log. Contoh:
export AWS_ACCESS_KEY_ID="localstack-ci-$(uuidgen)"
export AWS_SECRET_ACCESS_KEY="localstack-ci-secret"Alasannya: jika suatu saat kredensial produksi tercampur ke test (misalnya variabel env menimpa nilai), identitas unik ini membuat kebocoran langsung terlihat di log — bukan diam-diam lolos memakai pasangan test/test. Nilai yang berbeda per job juga membantu melacak job mana yang berperilaku aneh.
Rangkuman prinsip keamanan LocalStack:
Dengan fondasi keamanan yang rapi, kita bisa melangkah ke skenario yang lebih besar. Di episode 16 selanjutnya kita membahas Advanced Services: ECS dan EKS sampai Karpenter, Step Functions dengan HTTP Tasks, Kinesis, MSK, OpenSearch, RDS, Redshift, dan Athena. Sampai jumpa!