ConfigMap vs Secret #

Pertanyaan yang sering muncul saat mulai bekerja dengan Kubernetes: “Data ini masuk ConfigMap atau Secret?” Jawabannya tidak selalu hitam-putih. Artikel ini memberikan framework keputusan yang jelas, lengkap dengan contoh konkret dan anti-pattern yang perlu dihindari.

Framework Keputusan #

Pertanyaan pertama: Apakah nilai ini sensitif?

Sensitif berarti: jika orang yang tidak seharusnya membacanya,
bisa terjadi kerugian (data breach, akses tidak sah, kerugian finansial)

  Ya → Gunakan SECRET
  Tidak → Pertanyaan kedua

Pertanyaan kedua: Apakah nilai ini berbeda per environment?

  Ya → Gunakan CONFIGMAP
  Tidak → Bisa hardcode di manifest atau image
Klasifikasi cepat:

CONFIGMAP:
  ✓ URL database (bukan credentials-nya)
  ✓ Hostname dan port service lain
  ✓ Feature flags (dark_mode=true, new_ui=false)
  ✓ App settings (max_connections=100, timeout=30s)
  ✓ Log level (debug, info, warn, error)
  ✓ File konfigurasi (nginx.conf, app.yaml)
  ✓ Nama environment (production, staging)
  ✓ Resource limits aplikasi (thread pool size, queue size)

SECRET:
  ✓ Password database
  ✓ API key (Stripe, SendGrid, Twilio, dll)
  ✓ OAuth client secret
  ✓ JWT signing key
  ✓ TLS certificate dan private key
  ✓ SSH private key
  ✓ Token autentikasi (bearer token, service account token)
  ✓ Encryption key
  ✓ Webhook secret

Kasus Abu-abu #

Beberapa nilai tidak jelas masuk mana. Berikut panduan untuk kasus yang sering menimbulkan kebingungan:

Connection string lengkap:
  "postgresql://user:password@host:5432/db"
  → SECRET, karena mengandung password

Connection string tanpa credentials:
  "postgresql://host:5432/db"
  → CONFIGMAP, karena tidak ada informasi sensitif

Database name:
  "production_db"
  → CONFIGMAP — nama database saja tidak sensitif

Encryption key (AES key, HMAC secret):
  → SECRET, meskipun "hanya" kunci enkripsi, nilai ini harus dilindungi

Internal service URL:
  "http://payment-service.production:8080"
  → CONFIGMAP — URL internal tidak sensitif
  → Tapi jika URL mengandung API key dalam query string: SECRET

Debug flag:
  DEBUG=true
  → CONFIGMAP — tidak ada risiko keamanan

Admin username (tapi bukan password):
  ADMIN_USER=admin
  → Bisa CONFIGMAP, tapi pertimbangkan bahwa mengetahui username
    bisa membantu brute force. Untuk high-security: Secret.

Perbandingan Teknis #

                  ConfigMap              Secret
────────────────────────────────────────────────────────
Penyimpanan       Plaintext di Etcd      Base64 di Etcd*
Enkripsi          Tidak                  Opsional (at-rest)**
kubectl describe  Tampil nilai           Hanya tampil ukuran
Ukuran maks       1 MB                   1 MB
Auto-update       Ya (volume)            Ya (volume)
RBAC terpisah     Tidak                  Ya (lebih granular)
Tipe khusus       Tidak                  Ya (tls, docker, dll)

* Base64 bukan enkripsi — bisa di-decode oleh siapapun
** Aktifkan via EncryptionConfiguration atau cloud KMS

Anti-Pattern yang Sering Ditemui #

Anti-Pattern 1: Password di ConfigMap #

# ANTI-PATTERN: password masuk ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: database-config
data:
  DB_HOST: "postgres-service"
  DB_PORT: "5432"
  DB_NAME: "appdb"
  DB_PASSWORD: "SuperSecret123"    # ← INI SALAH

Konsekuensinya: siapapun yang bisa kubectl get configmap bisa baca password. ConfigMap tidak punya proteksi RBAC yang sama dengan Secret.

# BENAR: pisahkan sensitif ke Secret
apiVersion: v1
kind: ConfigMap
data:
  DB_HOST: "postgres-service"
  DB_PORT: "5432"
  DB_NAME: "appdb"
  # DB_PASSWORD tidak ada di sini

---
apiVersion: v1
kind: Secret
metadata:
  name: database-secret
type: Opaque
stringData:
  DB_PASSWORD: "SuperSecret123"    # ← di Secret

Anti-Pattern 2: Seluruh .env File di ConfigMap #

# ANTI-PATTERN: file .env berisi semua config termasuk yang sensitif
data:
  .env: |
    APP_ENV=production
    DB_HOST=postgres-service
    DB_PASSWORD=secret123        # ← sensitif masuk ConfigMap
    API_KEY=sk-abc123            # ← sensitif masuk ConfigMap
    LOG_LEVEL=info    

Seharusnya dipecah: nilai non-sensitif ke ConfigMap, nilai sensitif ke Secret. Inject keduanya ke dalam Pod secara terpisah.

Anti-Pattern 3: Hardcode Secret di Image #

# ANTI-PATTERN: build time secret masuk image layer
FROM python:3.11
ENV DATABASE_PASSWORD=SuperSecret123   # ← tersimpan permanen di image layer
COPY . /app

Secret dalam image bisa di-extract dari image history dan akan bocor jika image dipush ke registry publik atau registry yang kurang terlindungi.


Contoh Konfigurasi Lengkap yang Benar #

# ConfigMap untuk konfigurasi non-sensitif
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
  namespace: production
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"
  DB_HOST: "postgres-service.production.svc.cluster.local"
  DB_PORT: "5432"
  DB_NAME: "appdb"
  REDIS_HOST: "redis-service.production.svc.cluster.local"
  REDIS_PORT: "6379"
  MAX_CONNECTIONS: "50"
  REQUEST_TIMEOUT: "30"

---
# Secret untuk kredensial dan kunci sensitif
apiVersion: v1
kind: Secret
metadata:
  name: api-secrets
  namespace: production
type: Opaque
stringData:
  DB_PASSWORD: "..."
  REDIS_PASSWORD: "..."
  JWT_SECRET_KEY: "..."
  STRIPE_API_KEY: "..."

---
# Pod menggunakan keduanya
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: api
        envFrom:
        - configMapRef:
            name: api-config        # inject semua dari ConfigMap
        - secretRef:
            name: api-secrets       # inject semua dari Secret

Ringkasan #

  • Pertanyaan kunci: apakah exposure menyebabkan kerugian? — jika ya, gunakan Secret; jika tidak, ConfigMap sudah cukup.
  • URL terpisah dari credentials — hostname dan port masuk ConfigMap; password dan API key masuk Secret; jangan gabungkan dalam satu connection string di ConfigMap.
  • Base64 bukan alasan untuk taruh password di ConfigMap — encode base64 dan taruh di ConfigMap tidak lebih aman dari plaintext; gunakan Secret yang punya perlindungan RBAC berbeda.
  • Jangan taruh secret di image layerENV SECRET=value di Dockerfile tersimpan permanen di image history; gunakan ConfigMap/Secret saat runtime, bukan saat build.
  • Pisahkan file .env menjadi dua — nilai non-sensitif ke ConfigMap, nilai sensitif ke Secret; inject keduanya bersama ke Pod via envFrom.
  • Ukuran batas sama (1MB) — keduanya punya batas ukuran yang sama; untuk konfigurasi sangat besar, pertimbangkan split atau external config store.

← Sebelumnya: External Secret Manager   Berikutnya: Configuration Hot Reload →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact