Belajar Microservices - Keamanan Microservices (Zero Trust)
Episode 19 of 28

Belajar Microservices - Keamanan Microservices (Zero Trust)

Menerapkan zero trust di tokokita: validasi JWT dan OAuth2 di gateway, rate limiting token bucket untuk login, secrets management dengan Vault dan External Secrets Operator, NetworkPolicy, supply chain security dengan Trivy dan cosign, serta perlindungan PII

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Di episode 4-18 kita membangun banyak layanan dan menghubungkannya. Episode ini mempertanyakan semua yang sudah dibuat: "apakah kalian mempercayai jaringan ini?" Jawaban zero trust adalah tidak — percayai identitas, otentikasi setiap akses, enkripsi setiap komunikasi, dan anggap setiap titik rawan sebagai permukaan serangan.

Mengapa keamanan microservices beda dengan monolith? Karena memperbesar permukaan serangan: lebih banyak API, lebih banyak secrets yang dipakai antar service, lebih banyak komponen pada rantai suplai. Satu secret bocor di satu service bisa jadi jalan masuk ke semuanya tanpa segmentasi yang benar.

API Security: JWT di Gateway & OAuth2

Validasi Token Sekali di Gateway

Prinsip yang sudah kita jatuhkan di episode 10 kini menjadi kebijakan resmi: gateway adalah satu-satunya tempat yang menerima token user. Layanan internal memverifikasi machine identity sendiri (internal token/mTLS — episode 11/18), dan tidak menerima ataupun mewarisi token user.

Pembagian tanggung jawab
api-gateway  → validasi access token user (JWT/JWKS)
layanan internal → verifikasi identitas machine (mTLS / x-service-token)

OAuth2 / OIDC

Untuk integrasi "login dengan Google" atau otorisasi delegatif, standar de-facto adalah OAuth2 + OpenID Connect. flow Authorization Code + PKCE dipakai untuk web/mobile; token dinilai sesaat lewat validator OIDC, bukan di-re-implementasi manual.

OAuth2 Authorization Code + PKCE
web-app → /authorize?code_challenge=... → provider login
       ← authorization code
web-app → /token (code + code_verifier) → access/info token
api-gateway → /userinfo (introspection/JWKS) untuk klaim identitas

Belajar mendalam stack OAuth2 bisa disambung ke series otentikasi tersendiri; intinya di tokokita: jangan menulis token service sendiri — pakai provider (Auth.js di web, atau layanan OIDC) dan validasi di gateway.

Rate Limiting: Token Bucket dan Throttling Login

Rate limiting melindungi API dari brute-force dan banjir. Algoritma yang paling masif digunakan: token bucket — bucket berisi token, tiap request memakai satu, terisi kembali dengan laju tetap. Di Redis per IP/user:

Rate limiter token bucket di Redis
const BUCKET = 100        // kapasitas token
const REFILL_RATE = 20    // token per menit
 
export async function allow(key: string): Promise<boolean> {
  // Lua script atomic: hitung token tersisa
  const remaining = await redis.eval(`
    local t = redis.call('GET', KEYS[1])
    local last = redis.call('GET', KEYS[2])
    if not t then return ARGV[1] end
    local tokens = math.min(ARGV[1], t + (ARGV[2] - last) * ARGV[3])
    if tokens >= 1 then
      redis.call('SET', KEYS[1], tokens - 1, 'XX')
      return 1
    else
      return 0
    end
  `, [key, `${key}:ts`], [BUCKET, Date.now(), REFILL_RATE / 60000])
  return remaining === 1
}

Kebijakan minimum di tokokita:

  • Login endpoint: 5-10 percobaan per menit per IP + per email — kombinasi mencegah brute-force terbagi.
  • Public API (katalog): 100 req/menit per IP.
  • Payment/order: ketat + wajib idempotency.

Secrets: Vault / External Secrets Operator

Jangan pernah memasukkan secrets ke git, env container, atau image. Di Kubernetes, Secret native disimpan base64 (bukan enkripsi) — rahasia nyata harus ada di luar cluster:

  • Vault (HashiCorp) — store rahasia pusat dengan rotation + audit.
  • External Secrets Operator (ESO) — sinkronkan secret dari AWS Secrets Manager/GCP/Vault ke Secret K8s secara deklaratif.
ExternalSecret sederhana
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: auth-secrets
  namespace: tokokita
spec:
  secretStoreRef:
    name: vault
    kind: SecretStore
  target:
    name: tokokita-secrets
  data:
    - secretKey: JWT_SECRET
      remoteRef:
        key: tokokita/auth/jwt-secret

Pola lahirnya: manifest di git hanya berisi referensi (ExternalSecret), nilainya diambil saat runtime — kata kunci "referensikan, jangan salin".

NetworkPolicy: Batasi Siapa Bicara dengan Siapa

Di Kubernetes, semua pod bisa bicara semua pod secara default. Zero trust memperlihatkan aturan yang lebih ketat — siapa layak memanggil siapa:

NetworkPolicy: hanya gateway boleh ke order-service
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-ingress-gateway-only
  namespace: tokokita
spec:
  podSelector:
    matchLabels:
      app: order-service
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api-gateway
      ports:
        - port: 3004

Menuliskannya butuh disiplin: setiap layanan mendaftar "siapa yang sah memanggil saya" — daftar ini juga jadi dokumentasi arsitektur yang hidup. (Catatan: enforcement-nya butuh CNI yang mendukung NetworkPolicy, misal Calico; pada cluster cloud, ini level komponen.)

Supply Chain Security

Image yang kita bangun di episode 16 masih bisa disusupi di rantai suplai. Tiga lapis pertahanan:

  • Scan: pindai image terhadap CVE base image dan dependency. Trivy cepat & populer:
Scan image dengan Trivy
trivy image ghcr.io/tokokita/order-service:v1.4.2
trivy fs services/order-service   # scan repo saat CI
  • Sign: tandatangani image agar hanya image yang sah bisa deploy. cosign dari Sigstore:
Sign dan verify image
cosign sign ghcr.io/tokokita/order-service:v1.4.2
cosign verify ghcr.io/tokokita/order-service:v1.4.2
  • Audit dependency: bun audit/npm audit di pipeline; naikkan package yang punya CVE; lockb/lockfile wajib di-commit.

Sensitive Data: PII di Database

Zero trust untuk data — PII (email, nama) di database (auth-service) wajib dilindungi:

  • Enkripsi at rest — aktifkan enkripsi disk volume (K8s/cloud native) dan kolom sensitif bila perlu (mis. nomor kartu tidak pernah disimpan; hash password sudah).
  • Masquerade/masking di log — jangan pernah log email & token utuh. Gunakan request_id (episode 10) sebagai referensi, bukan PII.
Masking di log
function maskEmail(email: string) {
  const [local, domain] = email.split('@')
  return `${local[0]}***@${domain}`
}
logger.info({ user: maskEmail(email), requestId })

Warning

"Enkripsi at rest" mencegah pencurian disk, bukan kebodohan aplikasi. Dua tempat PII paling sering bocor di microservices justru: log yang mencetak body request penuh, dan debug tool yang menampilkan token/password. Mulai dari prinsip jangan log apa pun yang tidak wajib, baru pikirkan enkripsi. Masking harus menjadi kebijakan tim, bukan insiden.

Penutup

Episode 19 menerapkan zero trust di tokokita:

  • JWT/OAuth2 divalidasi di gateway; layanan internal memakai machine identity — tidak mewarisi token user.
  • Rate limiting token bucket di Redis + throttling agresif di login.
  • Secrets: Vault / External Secrets Operator; manifest hanya menyimpan referensi.
  • NetworkPolicy: batasi who-can-call-whom; dokumentasi arsitektur yang hidup.
  • Supply chain: scan Trivy, sign cosign, audit dependency.
  • PII: enkripsi at rest + masking di log (jangan log dulu, baru enkripsi).

Di episode 20 selanjutnya, kita masuk observability: OpenTelemetry untuk tracing, metrics, dan log — span per HTTP/event, propagasi traceparent melintasi auth → order → payment → Kafka → notif, metrik RED, log JSON terstruktur, dan backend Prometheus/Grafana/Tempo/Loki. Sampai jumpa di episode 20!

Belajar Microservices - Keamanan Microservices (Zero Trust) | Belajar Microservices