Multi-Tenancy #

Ketika sebuah organisasi berkembang dan mulai mengadopsi Kubernetes secara luas, mereka akan dihadapkan pada satu keputusan arsitektural yang krusial: apakah kita harus menyediakan satu kluster fisik kecil terpisah untuk setiap tim pengembang (single-tenant clusters), atau menggabungkan seluruh tim ke dalam satu kluster fisik besar yang digunakan bersama (multi-tenant clusters)? Pendekatan kluster tunggal per tim sangatlah mahal karena memicu pemborosan kapasitas node yang tidak terpakai dan melipatgandakan beban pemeliharaan infrastruktur tim platform. Sebaliknya, menyatukan banyak tim ke dalam satu kluster besar (disebut dengan Multi-Tenancy) menawarkan efisiensi biaya yang sangat tinggi dan menyederhanakan tata kelola kebijakan. Namun, tantangannya adalah keamanan: bagaimana kita memastikan tim A tidak dapat mengintip data sensitif milik tim B, bug pada aplikasi tim C tidak melumpuhkan kinerja tim D, dan administrator satu tim tidak dapat memodifikasi konfigurasi kluster global? Artikel ini membahas konsep isolasi logis vs fisik, arsitektur pembatasan akses, isolasi jaringan nol-kepercayaan (zero-trust networking), serta implementasi kluster virtual menggunakan vCluster.


Soft Multi-Tenancy vs Hard Multi-Tenancy #

Pendekatan multi-tenancy di Kubernetes dibagi menjadi dua kategori utama berdasarkan tingkat isolasi dan batasan kepercayaan (trust boundaries):

+-------------------------------------------------------------------------+
|                      SOFT MULTI-TENANCY (LOGICAL)                       |
|   - Menggunakan Namespace, RBAC, NetworkPolicy, dan ResourceQuota       |
|   - Seluruh Tenant berbagi API Server dan Host Kernel yang sama         |
|   - Kerentanan: Celah keamanan eksploitasi kernel host                 |
|   - Cocok untuk: Tim internal di bawah satu organisasi tepercaya        |
+-------------------------------------------------------------------------+
|                      HARD MULTI-TENANCY (PHYSICAL/VIRTUAL)              |
|   - Menggunakan Kluster Fisik Terpisah atau Kluster Virtual (vCluster)  |
|   - Isolasi Control Plane & etcd database secara fisik/logis terpisah   |
|   - Keuntungan: Keamanan tinggi, minim risiko eskalasi hak akses        |
|   - Cocok untuk: Perusahaan SaaS yang melayani pelanggan eksternal      |
+-------------------------------------------------------------------------+

Dalam skenario Soft Multi-Tenancy, jika seorang peretas berhasil mendapatkan hak akses root di dalam sebuah kontainer pada salah satu namespace, peretas tersebut berpotensi mengeksploitasi celah keamanan kernel Linux host (seperti container escape) untuk menguasai seluruh Node dan membaca rahasia (Secrets) milik tenant lain yang berjalan di Node yang sama.

Untuk skenario Hard Multi-Tenancy, isolasi fisik atau enkapsulasi virtual tingkat tinggi wajib diterapkan untuk menutup rapat seluruh celah eksploitasi lintas tenant.


Namespace sebagai Unit Isolasi Dasar #

Di Kubernetes, Namespace adalah unit isolasi logis fundamental. Namespace membagi kluster tunggal menjadi beberapa wilayah logis. Namun, membuat namespace saja tidak serta-merta mengamankan kluster. Kita harus melengkapi Namespace dengan kebijakan Pod Security Standards (PSS), ResourceQuota, dan LimitRange.

Berkas Manifest Namespace Terproteksi #

Berikut adalah contoh manifest konfigurasi Namespace yang dikeraskan (hardened namespace) untuk membatasi hak istimewa kontainer tenant:

# File: k8s/namespaces/team-backend-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: team-backend
  labels:
    team: backend-engineers
    environment: production
    # Mengaktifkan aturan PSS 'restricted' secara ketat (enforce)
    # Kebijakan ini otomatis menolak pembuatan Pod yang berjalan sebagai root, 
    # menggunakan host namespace, atau meminta kapabilitas privileged
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest

---
# Membatasi kuota sumber daya akumulatif untuk mencegah monopoli kapasitas Node
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-backend-quota
  namespace: team-backend
spec:
  hard:
    requests.cpu: "12"
    requests.memory: "24Gi"
    limits.cpu: "24"
    limits.memory: "48Gi"
    pods: "40"
    services: "15"
    persistentvolumeclaims: "10"

---
# Menjamin default spec resources untuk mencegah pod masuk ke QoS BestEffort
apiVersion: v1
kind: LimitRange
metadata:
  name: team-backend-limitrange
  namespace: team-backend
spec:
  limits:
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "200m"
      memory: "256Mi"

Otorisasi Akses via RBAC Tingkat Tenant #

Sistem autentikasi Kubernetes tidak boleh mengizinkan pengembang dari satu tim untuk memodifikasi atau bahkan melihat (read) sumber daya milik tim lain. Kita harus membatasi hak akses pengembang menggunakan aturan Role-Based Access Control (RBAC) yang diarahkan secara eksplisit pada tingkat Namespace (Namespace-scoped RBAC).

Secara bawaan, jika kita tidak membuat RoleBinding di suatu namespace untuk pengguna tertentu, Kubernetes akan menerapkan prinsip keamanan Default-Deny (akses ditolak total).

# File: k8s/rbac/team-backend-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-backend-developers-binding
  namespace: team-backend # Batasi pengikatan peran HANYA di namespace ini!
subjects:
- kind: Group
  name: "backend-developers-group" # Nama group OIDC dari integrasi Google / Azure AD
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  # Menggunakan ClusterRole default bawaan 'admin' 
  # Namun karena diikat menggunakan RoleBinding (bukan ClusterRoleBinding), 
  # pengguna KSA hanya bertindak sebagai admin di dalam namespace 'team-backend' saja.
  name: admin 
  apiGroup: rbac.authorization.k8s.io

Dengan konfigurasi di atas, jika seorang pengembang yang tergabung dalam backend-developers-group mencoba menjalankan perintah berikut:

# Sukses: Pengembang memiliki hak admin di namespace sendiri
kubectl get pods -n team-backend

# Ditolak: API Server menolak akses karena ketiadaan binding di namespace lain
kubectl get pods -n team-frontend
# Error from server (Forbidden): User "dev-user" cannot list resource "pods" in API group "" in the namespace "team-frontend"

NetworkPolicy: Isolasi Jaringan Nol-Kepercayaan (Zero-Trust) #

Secara bawaan, Kubernetes menganut prinsip jaringan datar (flat network model). Artinya, setiap Pod di dalam kluster dapat saling mengirimkan paket data secara bebas lintas namespace tanpa ada batasan apa pun. Ini adalah celah keamanan yang sangat fatal di lingkungan produksi. Pod microservice pengujian yang kurang aman di namespace dev dapat dengan mudah memanggil pod database produksi sensitif di namespace prod-apps secara langsung.

Kita harus menerapkan kebijakan NetworkPolicy bertipe Default-Deny All Ingress & Egress di setiap namespace tenant, lalu membuka jalur koneksi secara eksplisit hanya untuk layanan yang sah.

# File: k8s/networks/team-backend-netpol.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: team-backend-secure-policy
  namespace: team-backend
spec:
  podSelector: {} # Karakter kosong {} berarti aturan ini berlaku untuk SEMUA Pod di namespace ini
  policyTypes:
  - Ingress
  - Egress
  
  ingress:
  # Aturan 1: Izinkan lalu lintas dari Pod di dalam Namespace yang sama
  - from:
    - podSelector: {}
  
  # Aturan 2: Izinkan lalu lintas HTTP/gRPC hanya dari Ingress Controller Namespace
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx # Hanya dari namespace Ingress Nginx
    ports:
    - port: 8080
      protocol: TCP
      
  # Aturan 3: Izinkan scraping metrik dari sistem Monitoring kluster
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: monitoring-system
          
  egress:
  # Aturan 1: Izinkan akses resolusi nama domain (DNS) ke CoreDNS kluster
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
      
  # Aturan 2: Izinkan koneksi keluar ke internet publik (outbound)
  # Namun BLOKIR akses ke rentang IP CIDR kluster internal lainnya
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.0.0.0/8       # Blokir akses ke IP internal VPC / Kluster A
        - 172.16.0.0/12    # Blokir akses ke IP internal VPC / Kluster B
        - 192.168.0.0/16

vCluster: Solusi Kluster Virtual untuk Hard Multi-Tenancy #

Meskipun Namespace dan RBAC sangat andal untuk isolasi standar, mereka memiliki keterbatasan kritis: seluruh tenant berbagi satu database etcd dan satu API Server global yang sama.

Keterbatasan ini memicu beberapa masalah di organisasi besar:

  • Ketiadaan Akses CRD: Tenant tidak dapat mendaftarkan Custom Resource Definition (CRD) mereka sendiri karena CRD adalah objek tingkat kluster global (cluster-wide). Jika Tim A mendaftarkan CRD database versi v1, Tim B tidak dapat mendaftarkan versi v2.
  • Risiko API Server Overload: Satu tenant yang melakukan kueri API yang salah secara terus-menerus dapat membebani API Server utama, menyebabkan kelambatan operasional bagi seluruh tenant lain di kluster.

vCluster (Virtual Cluster) menyelesaikan masalah ini secara revolusioner. vCluster menjalankan kontrol plane Kubernetes virtual yang terisolasi di dalam satu namespace kluster host. vCluster memiliki API Server, etcd, dan controller-manager sendiri yang berjalan sebagai Pod biasa.

flowchart TD
    subgraph HostCluster["Kluster Fisik Utama (Host Cluster)"]
        direction TB
        HostAPI["Host API Server"]
        HostNodes["Physical Nodes (Node 1, Node 2)"]
        
        subgraph NamespaceTenant["Namespace: vcluster-team-frontend"]
            direction LR
            vAPI["Virtual API Server (vCluster)"]
            vetcd["Virtual etcd (sqlite / etcd Pod)"]
            vSyncer["vCluster Syncer Controller"]
        end
    end
    
    TenantDev["Developer Frontend (kubectl)"] -->|"Kirim manifest ke Port 8443"| vAPI
    vAPI <-->|"Simpan State"| vetcd
    
    vSyncer -->|"Membaca Pod Virtual & Hubungkan"| HostAPI
    HostAPI -->|"Jadwalkan Pod Fisik Nyata di"| HostNodes

Mekanisme Sinkronisasi vCluster (Syncer) #

vCluster tidak memiliki Node fisik sendiri. Ketika pengguna vCluster mengirimkan manifest Pod ke Virtual API Server:

  1. Virtual API Server menyimpan definisi Pod tersebut di dalam database virtual etcd-nya sendiri.
  2. Komponen vCluster Syncer memantau Virtual API Server, mendeteksi adanya pembuatan Pod baru, lalu menulis ulang nama Pod tersebut dengan menambahkan prefix unik (misalnya pod-frontend-vcluster-xyz), dan mengirimkannya ke API Server kluster host fisik.
  3. API Server kluster host menjadwalkan Pod fisik tersebut pada Node fisik utama. Dari sudut pandang kluster host, vCluster hanyalah kumpulan pod biasa yang berjalan di dalam satu namespace terisolasi.

Tabel Perbandingan Solusi Multi-Tenancy #

Berikut adalah matriks komparasi untuk membantu Anda memilih metode isolasi yang tepat:

Karakteristik Aspek Namespace biasa vCluster (Virtual Cluster) Kluster Fisik Terpisah
Isolasi API Server Berbagi bersama (Shared) Terisolasi Virtual Terisolasi Fisik Total
Isolasi Database etcd Berbagi bersama Terisolasi Virtual (SQLite/etcd Pod) Terisolasi Fisik Total
Kustomisasi CRDs Tidak Bisa (Cluster-wide restriction) Bisa (Bebas pasang CRD sendiri) Bisa
Overhead Sumber Daya Nol (Tidak ada control plane tambahan) Sangat Ringan (~200MB RAM per vCluster) Sangat Tinggi (Minimal 3 Master VM VMs)
Keamanan Kernel Host Berbagi bersama (Risiko escaping kernel) Berbagi bersama Terisolasi Total secara fisik
Kemudahan Pemeliharaan Sangat Mudah Mudah (Dikelola sebagai Pod biasa) Sulit (Mengelola banyak kluster)

Panduan Keputusan: Kapan Harus Memisahkan Kluster Fisik? #

Meskipun multi-tenancy sangat efisien, ada kondisi tertentu di mana kita wajib memisahkan kluster secara fisik:

  1. Kepatuhan Regulasi Hukum (Regulatory Compliance): Kerangka hukum seperti PCI-DSS (untuk pemrosesan transaksi kartu kredit) atau HIPAA (untuk rekam medis kesehatan) sering kali mewajibkan isolasi fisik yang ketat di tingkat jaringan dan komputasi. Workload transaksi kartu kredit tidak boleh dicampur dengan aplikasi blog promosi pemasaran di kluster yang sama.
  2. Batas Kepercayaan Nol (Zero Trust Boundaries): Jika kita menyediakan platform kontainer untuk organisasi luar/pelanggan eksternal yang bermusuhan atau tidak dipercaya (seperti layanan SaaS publik), isolasi namespace saja tidak cukup aman. Eksploitasi celah keamanan kernel host dapat membocorkan data antar pelanggan.
  3. Skala dan Kapasitas Kluster (Cluster Scale Limits): Kubernetes API Server dan etcd memiliki batas kapasitas pemrosesan optimal (biasanya optimal hingga maksimal 5.000 Node atau 150.000 Pod). Jika total beban kerja gabungan seluruh tim di perusahaan melampaui batas skala ini, kita harus membagi beban ke dalam beberapa kluster fisik terpisah.

Anti-Pattern dalam Penerapan Multi-Tenancy #

Hindari dua kesalahan arsitektur berikut saat mengonfigurasi multi-tenancy di tingkat produksi:

1. Mengizinkan Tenant Berjalan dengan Izin Cluster-Wide RBAC #

Memberikan hak akses administratif atau peran yang terlalu longgar di luar namespace tenant.

# ANTI-PATTERN: Mengikat RoleBinding tenant ke ClusterRoleBinding global
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding # JANGAN: Ini akan memberikan akses ke seluruh kluster!
metadata:
  name: team-frontend-cluster-admin
subjects:
- kind: Group
  name: "frontend-developers"
roleRef:
  kind: ClusterRole
  name: admin # Akses admin untuk seluruh namespace kluster!
Risiko Operasional:
- Developer tim frontend dapat secara tidak sengaja membaca Secret sensitif di namespace backend atau menghapus pod database produksi milik tim lain.
✓ SOLUSI: Selalu gunakan 'RoleBinding' (bukan 'ClusterRoleBinding') saat mengaitkan ClusterRole bawaan (seperti admin atau edit) ke subjek tenant agar ruang lingkup aksesnya terbatasi di satu namespace saja.

2. Mengabaikan Isolasi Jaringan Lintas Tenant (Flat Namespace Isolation) #

Membagi tim ke dalam beberapa namespace terpisah dan memasang RBAC yang ketat, namun tidak memasang satu pun aturan NetworkPolicy di kluster.

Risiko Operasional:
- Meskipun pengembang frontend tidak memiliki akses 'kubectl' ke namespace backend.
- Aplikasi web frontend mereka yang berjalan di kluster tetap dapat mengirimkan kueri jaringan HTTP/TCP langsung ke port database backend secara internal (misal memanggil 'http://postgres-service.backend-namespace.svc.cluster.local:5432').
- Jika kontainer aplikasi web frontend terkompromi oleh peretas, peretas dapat memindai dan mencuri seluruh data database internal kluster tanpa hambatan firewall.
✓ SOLUSI: Terapkan kebijakan default-deny NetworkPolicy di setiap namespace tenant dan buka rute koneksi secara eksplisit hanya untuk IP pod terdaftar.

Checklist Audit Multi-Tenancy #

Gunakan checklist ini untuk mengaudit tingkat isolasi multi-tenancy di kluster produksi Anda:

ISOLASI LOGIS & KEBIJAKAN NAMESPACE:
  □ Setiap tim atau aplikasi diisolasi di dalam Namespace yang terdedikasi.
  □ Pod Security Standards (PSS) terkonfigurasi pada tingkat 'restricted' di setiap namespace tenant.
  □ Objek ResourceQuota terpasang untuk membatasi konsumsi akumulatif CPU/RAM per namespace.
  □ LimitRange terkonfigurasi untuk menjamin alokasi requests/limits default kontainer.

OTORISASI AKSES (RBAC):
  □ Tidak ada tenant biasa yang memiliki izin akses 'ClusterRoleBinding' ke tingkat kluster global.
  □ Izin akses tenant diikat menggunakan 'RoleBinding' untuk membatasi ruang lingkup di satu namespace.
  □ Penggunaan hak istimewa (seperti membuat CRD, ClusterRole, atau ServiceAccount) dibatasi hanya untuk tim platform.
  □ Akses masuk engineer terintegrasi dengan OIDC Group resmi perusahaan (bukan menggunakan token statis serviceaccount).

ISOLASI JARINGAN (NETWORKPOLICY):
  □ Kebijakan NetworkPolicy default-deny ingress & egress aktif di setiap namespace tenant.
  □ Komunikasi lintas namespace ditolak secara total kecuali dibuka secara eksplisit.
  □ Akses keluar ke internet dari pod dibatasi hanya untuk port dan domain tujuan yang sah.
  □ Lalu lintas scraping metrik Prometheus dibatasi hanya dari namespace sistem monitoring yang valid.

Ringkasan #

  • Terapkan Isolasi Berlapis — Jamin keamanan multi-tenancy dengan menggabungkan isolasi logis (Namespace), akses (RBAC), jaringan (NetworkPolicy), dan kuota (ResourceQuota).
  • NetworkPolicy Adalah Wajib — Jangan biarkan kluster Anda berjalan dengan jaringan datar; wajib aktifkan default-deny NetworkPolicy antar namespace sejak awal kluster dibangun.
  • Batasi Ruang RBAC via RoleBinding — Selalu gunakan RoleBinding alih-alih ClusterRoleBinding untuk membatasi izin akses pengembang agar terisolasi di satu namespace saja.
  • vCluster untuk CRD Mandiri — Manfaatkan vCluster jika tenant Anda membutuhkan control plane virtual sendiri untuk memasang CRD kustom tanpa membeli kluster fisik tambahan.
  • Pisahkan Cluster untuk Kepatuhan — Segera buat kluster fisik terpisah jika aplikasi Anda terikat aturan kepatuhan hukum ketat (seperti PCI-DSS) atau melayani pelanggan eksternal yang tidak dipercaya.
  • Aktifkan Pod Security Standards Labeli namespace dengan pod-security.kubernetes.io/enforce: restricted untuk mencegah tenant menjalankan kontainer jahat berhak akses privileged host.

← Sebelumnya: Disaster Recovery   Berikutnya: Anti-Pattern Production →

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