Environment Variables & Secrets — DevOps

Config Berbeda per Environment, Tapi Kode Sama Aplikasi perlu tahu: URL database production, API key Stripe, secret JWT. Nilai-nilai ini berbeda per environment

Config Berbeda per Environment, Tapi Kode Sama

Aplikasi perlu tahu: URL database production, API key Stripe, secret JWT. Nilai-nilai ini berbeda per environment (dev, staging, prod) tapi kode harus tetap sama. Jawabannya: environment variables.

Env Var Dasar

# Set sementara (hanya untuk satu command)
DATABASE_URL=postgres://localhost/mydb node server.js

# Set untuk session shell
export DATABASE_URL=postgres://localhost/mydb
echo $DATABASE_URL

# Akses di aplikasi
# Node.js
process.env.DATABASE_URL

# PHP
getenv('DATABASE_URL');
$_ENV['DATABASE_URL'];

# Python
os.environ.get('DATABASE_URL')

.env Files untuk Development

# .env (di root project)
DATABASE_URL=postgres://localhost/mydb
STRIPE_SECRET_KEY=sk_test_abc123
JWT_SECRET=dev-secret-do-not-use-in-prod
LOG_LEVEL=debug

# Library loader (dotenv di Node, phpdotenv di PHP)
# otomatis baca .env saat aplikasi start

⚠️ WAJIB: tambahkan .env ke .gitignore. Commit .env.example (tanpa nilai sensitif) sebagai template bagi tim.

12-Factor App: Config

Prinsip III dari 12-factor app: store config in the environment. Artinya:

Config vs Secrets: Berbeda!

# CONFIG — aman di commit, tidak rahasia
LOG_LEVEL=info
DEFAULT_PAGE_SIZE=20
FEATURE_DARK_MODE=true

# SECRETS — WAJIB dirahasiakan
DATABASE_PASSWORD=prod-secret-xyz
STRIPE_SECRET_KEY=sk_live_abc
JWT_SIGNING_KEY=very-long-random-string
AWS_SECRET_ACCESS_KEY=...

Kedua jenis sama-sama lewat env var, tapi penanganannya berbeda. Secrets butuh rotasi, access control ketat, dan audit log.

Secret Managers

Menyimpan secret di env var plain text di server production berisiko. Gunakan secret manager:

# Flow umum di production:
# 1. App start
# 2. Auth ke secret manager pakai IAM role (bukan credential)
# 3. Fetch secrets ke memory
# 4. Tidak pernah menulis ke disk

// Contoh AWS SDK (Node)
const client = new SecretsManagerClient({ region: "ap-southeast-1" });
const data = await client.send(
  new GetSecretValueCommand({ SecretId: "prod/db" })
);
const { username, password } = JSON.parse(data.SecretString);

KMS & Encryption-at-Rest

KMS (Key Management Service) mengelola master encryption key. Secret manager menyimpan secret dalam bentuk terenkripsi di disk, KMS yang memegang key-nya. Akses secret → app butuh permission baca secret dan permission kms:Decrypt.

Secret Rotation

Secret yang sama selama 2 tahun = risiko besar jika bocor. Best practice: rotate secara berkala.

Secrets di CI/CD

# GitHub Actions — encrypted di repository settings
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy
        env:
          API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
        run: ./deploy.sh

OIDC: Pengganti Long-Lived Credentials

Daripada menyimpan AWS_ACCESS_KEY_ID tetap di secrets (berisiko bocor via log), gunakan OpenID Connect. GitHub bertindak sebagai identity provider, cloud provider meng-issue credential sementara per workflow run.

permissions:
  id-token: write

jobs:
  deploy:
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123:role/gha-deploy
          aws-region: ap-southeast-1
      # Credential temporary — tidak ada yang disimpan long-term

Build-Time vs Runtime Secrets

# BURUK: ENV di Dockerfile — secret ada di image layer selamanya
ENV DATABASE_PASSWORD=supersecret

# BAIK: inject saat run
docker run -e DATABASE_PASSWORD=$DB_PASS myapp
# atau pakai --env-file .env.production

Common Leaks: Apa yang Harus Dihindari

Tools seperti git-secrets, gitleaks, atau GitHub secret scanning bisa mendeteksi leak sebelum push.

Yang akan kamu pelajari