Tim data TokoKita tumbuh dari tiga orang menjadi dua puluh, dan daftar izin per orang ikut membengkak. Memberi atau mencabut izin satu per satu di warehouse, database, dan object storage tidak hanya melelahkan — pola pemberiannya juga cepat berantakan karena tidak ada satu pun orang yang mengingat siapa diberi apa dan mengapa. Role-Based Access Control (RBAC) merapikan kekacauan tersebut dengan satu ide sederhana: izin melekat pada role, pengguna tinggal diberi role. Chapter ini membangun matriks role-permission TokoKita, menguji pemeriksaan akses deny by default, lalu menjalankan audit kecil yang menemukan izin sisa proyek lama yang melanggar principle of least privilege.
Role sebagai Kumpulan Izin #
RBAC memutuskan tiga hal terpisah: izin apa saja yang ada (permission), izin mana yang membentuk sebuah role, dan role mana yang dipegang tiap pengguna. Pemisahan tersebut membuat pertanyaan audit menjadi mudah dijawab: bukan “apa saja izin Siti”, melainkan “apa saja izin role analyst, dan siapa saja pemegangnya”. Berikut pembagian role awal untuk warehouse TokoKita:
| Role | Izin khas | Pemegang awal |
|---|---|---|
| analyst | baca tabel analitik | Siti |
| engineer | baca dan tulis tabel, kelola pipeline | Budi |
| support | baca data pelanggan untuk tiket | Dewi |
| dba | seluruh izin termasuk hapus dan DDL | Andi |
Matriks ini bukan sekadar dokumentasi; matriks tersebut menjadi sumber kebenaran yang sama untuk penerapan di PostgreSQL (GRANT), di IAM object storage, dan di policy orchestrator. Satu perubahan role langsung berlaku untuk semua pemegangnya — itulah keunggulan RBAC dibanding mengelola izin per orang seperti pada skema scope di Chapter Authentication dan Authorization.
Simulasi Pemeriksaan Akses #
Mari kita terjemahkan matriks di atas menjadi kode pemeriksaan akses yang menolak secara bawaan, termasuk skenario nyata yang selalu muncul di tim yang sudah berjalan lama: izin ekstra di luar role yang tertinggal dari proyek sebelumnya:
"""Demo ch3: matriks RBAC, akses deny-by-default, audit izin berlebih."""
# Matriks role -> izin pada tabel warehouse TokoKita
IZIN_PER_ROLE = {
"analyst": {"pelanggan:read", "pesanan:read", "produk:read"},
"engineer": {"pelanggan:read", "pesanan:read", "pesanan:write",
"produk:read", "produk:write", "tabel:write"},
"support": {"pelanggan:read", "pesanan:read"},
"dba": {"pelanggan:read", "pelanggan:write", "pelanggan:delete",
"pesanan:read", "pesanan:write", "pesanan:delete",
"produk:read", "produk:write", "produk:delete", "tabel:write"},
}
# Pemetaan pengguna -> role (satu role per pengguna untuk contoh ini)
ROLE_PENGGUNA = {
"budi": "engineer",
"siti": "analyst",
"dewi": "support",
"andi": "dba",
}
# Izin ekstra per pengguna di luar role: sumber pelanggaran least privilege
IZIN_EKSTRA = {
"siti": {"pesanan:delete"}, # sisa proyek migrasi tahun lalu
"dewi": {"produk:write"}, # sementara menggantikan engineer
}
def izin_pengguna(pengguna: str) -> set:
role = ROLE_PENGGUNA.get(pengguna)
if role is None:
return set() # pengguna tanpa role: tidak punya izin apa pun
return IZIN_PER_ROLE[role] | IZIN_EKSTRA.get(pengguna, set())
def cek_akses(pengguna: str, aksi: str) -> str:
status = "DIIZINKAN" if aksi in izin_pengguna(pengguna) else "DITOLAK"
return f"{pengguna:14}{aksi:18}-> {status}"
print("== Uji akses: deny by default ==")
for aksi in ("pesanan:read", "pesanan:delete", "produk:delete", "tabel:write"):
print(cek_akses("siti", aksi))
print(cek_akses("pengguna-baru", "pesanan:read"))
print()
print("== Audit izin melebihi kebutuhan role ==")
print(f"{'pengguna':14}{'role':9}{'jumlah':7}{'catatan'}")
for pengguna, role in sorted(ROLE_PENGGUNA.items()):
ekstra = IZIN_EKSTRA.get(pengguna, set())
jumlah = len(IZIN_PER_ROLE[role] | ekstra)
catatan = f"EKSTRA: {', '.join(sorted(ekstra))}" if ekstra else "bersih"
print(f"{pengguna:14}{role:9}{jumlah:<7}{catatan}")
print()
print("== Setelah pruning: izin ekstra Siti dan Dewi dihapus ==")
IZIN_EKSTRA.clear()
for aksi in ("pesanan:delete", "produk:write"):
print(cek_akses("siti", aksi))
print(cek_akses("dewi", aksi))Output yang Dihasilkan:
== Uji akses: deny by default ==
siti pesanan:read -> DIIZINKAN
siti pesanan:delete -> DIIZINKAN
siti produk:delete -> DITOLAK
siti tabel:write -> DITOLAK
pengguna-baru pesanan:read -> DITOLAK
== Audit izin melebihi kebutuhan role ==
pengguna role jumlah catatan
andi dba 10 bersih
budi engineer 6 bersih
dewi support 3 EKSTRA: produk:write
siti analyst 4 EKSTRA: pesanan:delete
== Setelah pruning: izin ekstra Siti dan Dewi dihapus ==
siti pesanan:delete -> DITOLAK
dewi pesanan:delete -> DITOLAK
siti produk:write -> DITOLAK
dewi produk:write -> DITOLAKMari kita telaah baris-baris kode di atas:
- Baris 5-13 (
IZIN_PER_ROLE): matriks role-permission menjadi satu-satunya tempat izin didefinisikan; menambah izin baru bagi analyst cukup mengubah satu baris pada role, bukan dua puluh akun. - Baris 24-27 (
IZIN_EKSTRA): izin di luar role tetap dimungkinkan untuk pengecualian mendesak, tetapi struktur terpisah tersebut membuat pengecualian langsung terlihat saat audit. - Baris 30-34 (
izin_pengguna): pengguna tanpa role mendapat himpunan kosong — penerapan deny by default, karena tidak ada izin yang diberikan tanpa keputusan eksplisit. - Baris 37-39 (
cek_akses): pemeriksaan aksi cukup menguji keanggotaan pada himpunan izin gabungan role dan ekstra; hasil selalu berupa keputusan tunggal. - Baris 58 (
IZIN_EKSTRA.clear()): pruning hanya menghapus pengecualian tanpa menyentuh matriks role, sehingga pemegang role lain tidak terdampak.
Audit dan Pruning sebagai Rutinitas #
Baris kedua keluaran memperlihatkan hasil audit: Siti pemegang role analyst ternyata memegang pesanan:delete dari proyek migrasi tahun lalu, dan Dewi memegang produk:write sisa masa menggantikan engineer. Keduanya lolos bertahan karena tidak pernah direview — fenomena yang di industri disebut permission drift, dan kategori kesalahan akses seperti ini menempati peringkat teratas daftar OWASP Top Ten
. Setelah izin ekstra dipangkas, keempat pengujian ulang menolak — termasuk pesanan:delete milik Siti dan produk:write milik Dewi yang sebelumnya terbuka. Pruning semacam ini aman karena matriks role tidak tersentuh sama sekali — pengecualian memang seharusnya menjadi calon penghapusan pertama setiap kali audit berjalan.
Pola yang layak dipadukan adalah mencatat setiap keputusan izin — siapa meminta apa, disetujui siapa, dipakai kapan — sehingga audit berkala tidak bergantung pada ingatan orang. Pencatatan tersebut adalah bidang Chapter Audit Logging. Sebelum sampai di sana, kita perlu menghadapi ancaman yang tidak lewat gerbang izin sama sekali: berkas warehouse yang dicuri dari disk dan lalu lintas yang disadap di jaringan. Dua jalur itu ditutup oleh Chapter Encryption at Rest dan In Transit.