โ† Semua pembelajaran / Astro Nol โ†’ Portal Berita
Fase 7 ยท Keamanan

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.

Sumber asli docs.astro.build Resmi Rangkuman ~8 menit baca

Intisari

  • PUBLIC_ ikut ke browser. Apa pun tanpa awalan itu tidak boleh.
  • astro:env mendeklarasikan tiap variabel beserta konteks dan tipenya โ€” dan menegakkannya.
  • Rahasia produksi tinggal di AWS Secrets Manager, bukan di .env yang di-commit.
  • .env harus ada di .gitignore; .env.example yang 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

KombinasiContohPerilaku
client + publicClient key Midtrans, URL situsDisisipkan ke bundel klien
server + publicHost database, mode produksiHanya di server; boleh tampil di log
server + secretServer key, sandi DB, ASTRO_KEYHanya server; jangan pernah di-log
client + secretโ€”Tidak ada. Rahasia di klien bukan rahasia

Dari mana nilainya datang

LingkunganSumber
Laptop.env โ€” di .gitignore
CIGitHub Actions secrets
ProduksiAWS 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

LangkahCatatan
1. Rotasi kuncinya sekarang jugaIni yang paling penting dan paling sering ditunda
2. Perbarui Secrets Managerโ€”
3. Deploy ulangโ€”
4. Baru bersihkan riwayat gitMenghapus 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.