Rahasia, variabel lingkungan & astro:env
Satu impor yang salah bisa membawa server key ke bundel JavaScript. astro:env mengubah kesalahan itu dari bencana senyap jadi error saat build.
Intisari
PUBLIC_ikut ke browser. Apa pun tanpa awalan itu tidak boleh.astro:envmendeklarasikan tiap variabel beserta konteks dan tipenya โ dan menegakkannya.- Rahasia produksi tinggal di AWS Secrets Manager, bukan di
.envyang di-commit. .envharus ada di.gitignore;.env.exampleyang di-commit.- Verifikasi di CI: cari pola rahasia di
dist/client/dan gagalkan build kalau ada.
Cara lama, dan bahayanya
// Bekerja, tapi tidak ada yang menjagamu
const kunci = import.meta.env.MIDTRANS_SERVER_KEY;
Aturan Vite: variabel berawalan PUBLIC_ disisipkan ke kode klien; sisanya hanya di server.
Perlindungannya nyata tapi tidak sempurna โ kalau kamu mengimpor modul yang membaca variabel server ke
dalam komponen .vue, seluruh modul itu ikut ke bundel klien, dan peringatannya mudah
terlewat di antara keluaran build.
astro:env: batasnya jadi bagian dari tipe
// astro.config.mjs
import { defineConfig, envField } from "astro/config";
export default defineConfig({
env: {
schema: {
// Boleh ke browser
PUBLIC_SITE_URL: envField.string({ context: "client", access: "public" }),
PUBLIC_MIDTRANS_CLIENT_KEY: envField.string({ context: "client", access: "public" }),
// Server saja, rahasia
MIDTRANS_SERVER_KEY: envField.string({ context: "server", access: "secret" }),
DB_PASSWORD: envField.string({ context: "server", access: "secret" }),
ASTRO_KEY: envField.string({ context: "server", access: "secret" }),
// Server saja, bukan rahasia
DB_HOST_RW: envField.string({ context: "server", access: "public" }),
DB_HOST_RO: envField.string({ context: "server", access: "public" }),
MIDTRANS_PRODUKSI: envField.boolean({ context: "server", access: "public", default: false }),
},
},
});
// Di kode server
import { MIDTRANS_SERVER_KEY, DB_HOST_RW } from "astro:env/server";
// Di komponen Vue atau skrip klien
import { PUBLIC_MIDTRANS_CLIENT_KEY } from "astro:env/client";
// Ini GAGAL SAAT BUILD, bukan diam-diam bocor:
import { MIDTRANS_SERVER_KEY } from "astro:env/client";
// ^ Error: MIDTRANS_SERVER_KEY is a server-only variable
Inilah nilainya. Kesalahan yang sebelumnya berarti "server key ada di JavaScript publikmu dan tidak ada yang tahu selama berbulan-bulan" sekarang berarti "build gagal dengan pesan yang jelas". Untuk proyek yang menyentuh pembayaran, ini termasuk perubahan paling menguntungkan yang bisa kamu lakukan dalam sepuluh menit.
Tiga tingkat
| Kombinasi | Contoh | Perilaku |
|---|---|---|
client + public | Client key Midtrans, URL situs | Disisipkan ke bundel klien |
server + public | Host database, mode produksi | Hanya di server; boleh tampil di log |
server + secret | Server key, sandi DB, ASTRO_KEY | Hanya server; jangan pernah di-log |
client + secret | โ | Tidak ada. Rahasia di klien bukan rahasia |
Dari mana nilainya datang
| Lingkungan | Sumber |
|---|---|
| Laptop | .env โ di .gitignore |
| CI | GitHub Actions secrets |
| Produksi | AWS Secrets Manager, disuntikkan ECS ke task (Fase 10) |
{
"containerDefinitions": [{
"secrets": [
{ "name": "DB_PASSWORD", "valueFrom": "arn:aws:secretsmanager:โฆ:portal/db:sandi::" },
{ "name": "MIDTRANS_SERVER_KEY", "valueFrom": "arn:aws:secretsmanager:โฆ:portal/midtrans:server_key::" },
{ "name": "ASTRO_KEY", "valueFrom": "arn:aws:secretsmanager:โฆ:portal/astro:key::" }
],
"environment": [
{ "name": "DB_HOST_RW", "value": "portal.abc.rds.amazonaws.com" },
{ "name": "MIDTRANS_PRODUKSI", "value": "true" }
]
}]
}
Perbedaan secrets dan environment di ECS bukan kosmetik: nilai di
environment terlihat di konsol AWS, di describe-task-definition, dan di banyak
tempat lain. Nilai di secrets hanya ada di dalam container.
.env.example
# .env.example โ DI-COMMIT. Isi contoh, bukan nilai asli.
PUBLIC_SITE_URL=http://localhost:4321
PUBLIC_MIDTRANS_CLIENT_KEY=SB-Mid-client-xxxxxxxx
DB_HOST_RW=127.0.0.1
DB_HOST_RO=127.0.0.1
DB_USER=portal
DB_PASSWORD=ganti-saya
DB_NAME=portal_dev
MIDTRANS_PRODUKSI=false
MIDTRANS_SERVER_KEY=SB-Mid-server-xxxxxxxx
# pnpm astro create-key
ASTRO_KEY=
Kalau rahasia terlanjur ter-commit
| Langkah | Catatan |
|---|---|
| 1. Rotasi kuncinya sekarang juga | Ini yang paling penting dan paling sering ditunda |
| 2. Perbarui Secrets Manager | โ |
| 3. Deploy ulang | โ |
| 4. Baru bersihkan riwayat git | Menghapus dari riwayat tidak membatalkan kuncinya |
Urutannya penting dan sering terbalik. Orang menghabiskan sore membersihkan riwayat git dengan
filter-repo lalu merasa selesai โ sementara kuncinya masih sah dan sudah terlanjur ada di
fork, di cache, atau di layar seseorang. Rotasi dulu; membersihkan riwayat adalah kerapian,
bukan perbaikan.
Pagar di CI
#!/usr/bin/env bash
set -euo pipefail
pnpm build
POLA='Mid-server-|SB-Mid-server-|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}'
if grep -rlE "$POLA" dist/client/ 2>/dev/null | grep -q .; then
echo "FATAL: pola rahasia ditemukan di bundel klien"
grep -rlE "$POLA" dist/client/
exit 1
fi
echo "OK: tidak ada rahasia di bundel klien"
Latihan: pindahkan seluruh variabel proyekmu ke skema astro:env. Lalu buktikan
pagarnya bekerja: impor MIDTRANS_SERVER_KEY dari astro:env/client di sebuah
komponen .vue dan jalankan pnpm build โ ia harus gagal dengan pesan yang
menyebut nama variabelnya. Tambahkan juga skrip pemindai di atas ke pipeline-mu.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.