Mengatur Hak Akses Data di Tim Kecil: Peran, Skema, dan View
TL;DR
Buat ngatur hak akses data di tim kecil, bikin tiga role bertingkat (pembaca, analis, pengelola), pisahin tabel mentah dan tabel siap pakai ke skema berbeda, lalu kasih akses lewat view yang nyembunyiin kolom sensitif. Pola ini cukup buat tim 5 sampai 15 orang dan bisa dipasang dalam satu sore pakai belasan perintah GRANT.
Satu akun postgres dipakai bareng lima orang itu masalah yang nggak kelihatan sampai ada tabel kehapus.
Waktu itu kejadian, kamu nggak bisa jawab satu pertanyaan paling dasar: siapa yang ngelakuin. Log-nya ada, isinya postgres semua.
Buat tim 5 sampai 15 orang, kamu nggak butuh sistem izin bertingkat lima level. Tiga role, dua skema, dan beberapa view udah cukup. Semuanya bisa dipasang dalam satu sore.
Apa itu role di PostgreSQL dan bedanya sama user?
Role adalah kumpulan izin yang bisa dikasih ke akun lain. Di PostgreSQL, user dan role sebenernya objek yang sama. Bedanya cuma satu: user punya izin login, role biasa nggak.
Polanya begini. Izin dikasih ke role, bukan ke orang. Orang dimasukin ke role. Waktu ada anggota tim baru, kamu cukup satu perintah, bukan ngulang belasan GRANT per tabel.
CREATE ROLE pembaca_data NOLOGIN;
CREATE ROLE analis_data NOLOGIN;
CREATE ROLE pengelola_data NOLOGIN;
NOLOGIN bikin role ini nggak bisa dipakai masuk. Dia cuma wadah izin.
Tiga role di atas cukup buat sebagian besar tim kecil:
| Role | Boleh apa | Cocok buat |
|---|---|---|
pembaca_data | SELECT di skema analitik doang | Tim marketing, finance, ops |
analis_data | SELECT semua data, plus bikin tabel di ruang kerjanya sendiri | Analis, data scientist |
pengelola_data | Ubah struktur tabel di skema analitik | 1 sampai 2 orang saja |
Perhatiin bahwa nggak ada role yang boleh hapus database. Itu tetap di akun superuser yang cuma dipakai buat pemeliharaan, bukan buat kerja harian.
Kenapa data perlu dipisah ke skema yang berbeda?
Skema itu folder di dalam database. Tabel yang isinya sama-sama penting tapi beda tingkat kesiapannya sebaiknya nggak numpuk di satu tempat.
Pembagian yang paling kepakai:
CREATE SCHEMA mentah; -- hasil tarikan langsung dari sistem sumber
CREATE SCHEMA analitik; -- tabel yang udah dibersihin dan siap dipakai
CREATE SCHEMA kerja_analis; -- ruang coba-coba, boleh berantakan
Skema mentah isinya data hasil ETL yang belum disentuh. Kolomnya masih apa adanya, termasuk kolom sensitif kayak nomor telepon dan alamat.
Skema analitik isinya tabel yang kolomnya udah dipilih dan namanya udah diseragamkan. Ini yang dibuka ke orang non-teknis.
Skema kerja_analis tempat analis bikin tabel sementara tanpa ganggu siapa-siapa. Isinya boleh berantakan, dan boleh dihapus tiap bulan.
Sebelum ngatur izin, satu hal harus dilakukan duluan:
REVOKE ALL ON DATABASE toko_berkah FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM PUBLIC;
PostgreSQL secara bawaan ngasih akses ke role PUBLIC, yang artinya semua akun. Kalau ini nggak dicabut, semua pengaturan izin kamu di bawahnya jadi percuma.
Gimana cara ngasih izin baca ke satu skema?
Tiga perintah, plus satu perintah keempat yang paling sering kelupaan.
GRANT CONNECT ON DATABASE toko_berkah TO pembaca_data;
GRANT USAGE ON SCHEMA analitik TO pembaca_data;
GRANT SELECT ON ALL TABLES IN SCHEMA analitik TO pembaca_data;
Baris kedua sering dilewat. USAGE itu izin buat masuk ke skemanya. Tanpa itu, izin SELECT di baris ketiga nggak kepakai sama sekali, dan kamu bakal bingung kenapa error permission denied terus muncul.
Perintah keempat ngurus tabel yang belum ada:
ALTER DEFAULT PRIVILEGES IN SCHEMA analitik
GRANT SELECT ON TABLES TO pembaca_data;
GRANT ON ALL TABLES cuma berlaku buat tabel yang ada saat perintah dijalanin. Tabel yang dibikin besok nggak ikut. ALTER DEFAULT PRIVILEGES yang ngurus itu.
Tanpa baris ini, tiap kali ada tabel baru kamu harus inget jalanin GRANT lagi. Dan kamu bakal lupa.
Penjelasan lengkap semua tipe izin ada di dokumentasi GRANT PostgreSQL.
Gimana bikin role bertingkat biar izinnya nggak ditulis dua kali?
Role bisa dimasukin ke role lain. Analis otomatis dapat semua izin pembaca, tanpa kamu tulis ulang.
GRANT pembaca_data TO analis_data;
GRANT USAGE ON SCHEMA mentah TO analis_data;
GRANT SELECT ON ALL TABLES IN SCHEMA mentah TO analis_data;
GRANT ALL ON SCHEMA kerja_analis TO analis_data;
Lalu pengelola dapat semua izin analis, ditambah hak ngubah struktur:
GRANT analis_data TO pengelola_data;
GRANT ALL ON SCHEMA analitik TO pengelola_data;
GRANT ALL ON ALL TABLES IN SCHEMA analitik TO pengelola_data;
Bikin akun orangnya belakangan:
CREATE USER rina WITH PASSWORD 'ganti_password_ini';
GRANT analis_data TO rina;
Waktu Rina pindah tim, satu perintah:
REVOKE analis_data FROM rina;
GRANT pembaca_data TO rina;
Ini yang bikin pola role kepakai. Perubahan orang jadi satu baris, bukan audit belasan tabel.
Gimana cara nyembunyiin kolom sensitif pakai view?
Tabel pelanggan di skema mentah punya nomor telepon, alamat, dan tanggal lahir. Tim marketing butuh kota dan segmen, nggak butuh nomor telepon.
Bikin view yang cuma nyebut kolom yang boleh dilihat:
CREATE VIEW analitik.pelanggan_aman AS
SELECT id,
kota,
segmen,
tanggal_daftar
FROM mentah.pelanggan;
GRANT SELECT ON analitik.pelanggan_aman TO pembaca_data;
Lalu pastiin tabel aslinya nggak bisa diakses:
REVOKE SELECT ON mentah.pelanggan FROM pembaca_data;
Selama role itu nggak punya SELECT ke tabel dasarnya, dia nggak bisa nembus lewat view. View jalan pakai izin pemilik view, bukan izin pemanggilnya.
Buat pembatasan per baris, bukan per kolom, pakai row level security:
ALTER TABLE mentah.transaksi ENABLE ROW LEVEL SECURITY;
CREATE POLICY transaksi_per_cabang ON mentah.transaksi
FOR SELECT
TO staf_cabang
USING (cabang = current_setting('app.cabang', true));
Aplikasi kamu nyetel app.cabang waktu koneksi dibuka, lalu staf cabang Bandung cuma lihat baris cabang Bandung. Cara kerja dan batasannya dijelasin di dokumentasi row security policies PostgreSQL.
Gimana cara ngecek siapa punya akses ke apa?
Query ini nampilin semua izin di satu tabel:
SELECT grantee, privilege_type, grantor
FROM information_schema.table_privileges
WHERE table_schema = 'mentah'
AND table_name = 'pelanggan'
ORDER BY grantee;
Buat lihat siapa anggota role tertentu:
SELECT r.rolname AS role_induk, m.rolname AS anggota
FROM pg_auth_members am
JOIN pg_roles r ON r.oid = am.roleid
JOIN pg_roles m ON m.oid = am.member
ORDER BY r.rolname, m.rolname;
Jalanin dua query ini tiap kuartal. Terutama setelah ada orang keluar atau pindah tim, karena izin yang nggak pernah dicek biasanya menumpuk tanpa ada yang sadar.
Contoh kasus: 11 akun di database toko_berkah
Waktu aku rapiin izin di database latihan toko_berkah, kondisi awalnya begini: 11 akun aktif, 8 di antaranya punya izin ALL PRIVILEGES di semua tabel.
Dari 8 akun itu, cuma 2 yang beneran pernah nulis data dalam 90 hari terakhir. Enam sisanya cuma pernah SELECT.
| Kondisi | Sebelum | Sesudah |
|---|---|---|
| Akun dengan izin tulis | 8 | 2 |
| Akun yang bisa lihat nomor telepon pelanggan | 11 | 3 |
| Akun yang bisa DROP tabel | 8 | 1 |
| Baris GRANT yang perlu dirawat | 96 | 17 |
Angka terakhir yang paling kepakai buat aku. Sembilan puluh enam baris izin per orang per tabel turun jadi 17 baris yang semuanya ke role. Waktu ada anggota baru minggu berikutnya, prosesnya dua perintah dan selesai dalam dua menit.
Satu temuan yang nggak aku duga: dua akun ternyata milik orang yang udah resign 4 bulan sebelumnya. Passwordnya masih aktif. Ini yang bikin pemeriksaan berkala penting, terpisah dari soal role.
Sisi lain dari kerapian akses ini masuk ke urusan kualitas data. Kalau cuma dua akun yang bisa nulis, jumlah orang yang bisa diam-diam ngubah angka juga cuma dua.
Kesalahan umum waktu ngatur hak akses database
- Lupa cabut izin PUBLIC. Semua pengaturan role kamu jadi hiasan kalau
PUBLICmasih punya akses ke skemapublic. Cabut duluan sebelum ngapa-ngapain. - Kasih GRANT ke orang, bukan ke role. Kelihatan cepat di awal. Enam bulan kemudian kamu punya 90 baris izin yang nggak ada yang paham asal-usulnya.
- Lupa ALTER DEFAULT PRIVILEGES. Tabel baru bakal nggak keliatan sama tim, dan kamu bakal dapat pesan "kok datanya nggak ada" tiap minggu.
- Kasih USAGE tapi lupa CONNECT. Atau sebaliknya. Dua-duanya perlu, dan pesan errornya nggak selalu nunjuk yang mana yang kurang.
- Bikin view tapi tabel aslinya masih kebuka. View cuma ngefek kalau akses ke tabel dasarnya dicabut. Cek pakai query
table_privilegessetelah bikin view. - Password dibagi lewat chat grup. Pakai pengelola kata sandi, dan bikin password per orang. Akun bersama ngilangin seluruh manfaat pengaturan ini.
- Nggak pernah ngecek akun lama. Orang resign, akunnya tetap hidup. Masukin pemeriksaan akun ke daftar tugas offboarding, bukan ke ingatan.
FAQ
Tim aku cuma 6 orang, perlu banget atur hak akses?
Perlu, tapi versi ringan. Yang kamu butuh cuma tiga role dan dua skema, bukan sistem izin bertingkat lima level. Nilainya bukan cuma keamanan. Waktu ada tabel kehapus atau angka berubah, kamu bisa tahu akun mana yang ngelakuin. Dengan satu akun bersama, jejaknya hilang dan kamu cuma bisa nebak.
Bedanya GRANT ke role sama GRANT ke user apa?
Di PostgreSQL, user dan role itu objek yang sama, bedanya cuma user punya izin login. Kasih izin ke role, lalu masukin user ke role itu. Waktu ada anggota tim baru, kamu cukup satu perintah GRANT role ke dia, bukan ngulang belasan izin per tabel. Waktu dia keluar, cukup dicabut dari role-nya.
View bisa dipakai nyembunyiin kolom sensitif?
Bisa, dan itu cara paling sederhana. Bikin view yang cuma nyebut kolom yang boleh dilihat, lalu cabut akses ke tabel aslinya. Selama role itu nggak punya SELECT ke tabel dasar, dia nggak bisa nembus lewat view. Buat pembatasan per baris, bukan per kolom, pakai row level security.
Gimana cara ngecek siapa punya akses ke tabel tertentu?
Query tabel information_schema.table_privileges dengan filter nama tabelnya. Hasilnya nampilin siapa dapat izin apa, dan dari siapa izin itu dikasih. Jalanin pemeriksaan ini tiap kuartal, terutama setelah ada orang yang keluar atau pindah tim. Izin yang nggak pernah dicek biasanya menumpuk tanpa ada yang sadar.
Data pribadi pelanggan boleh disimpan di tabel analisis?
Simpan seminimal mungkin, dan kalau bisa jangan di tabel yang dipakai analisis harian. Nomor telepon, NIK, dan alamat lengkap jarang dibutuhkan buat ngitung omzet per kota. Ganti pakai id pelanggan yang nggak bisa ditelusuri balik. Buat aturan detailnya, cek kebijakan perusahaan kamu dan ketentuan UU Perlindungan Data Pribadi yang berlaku.
Penutup
Tiga hal yang bikin pengaturan ini jalan: izin dikasih ke role bukan ke orang, tabel mentah dipisah dari tabel siap pakai, dan kolom sensitif dibuka lewat view.
Kalau kamu mulai hari ini, jalanin dulu REVOKE ALL ON SCHEMA public FROM PUBLIC. Satu baris itu yang paling banyak nutup celah.
Mau latihan nulis GRANT dan view langsung tanpa install database? Coba latihan interaktif di NgulikSQL. Kalau datanya masih berupa file besar dan belum masuk database, cara ngolahnya ada di panduan DuckDB buat CSV 5 juta baris.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Pivot dinamis di SQL ngubah baris jadi kolom tanpa kamu hardcode nama kolomnya. Ini cara bikinnya pakai CASE WHEN dan versi yang kolomnya ngikut data.
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
YTD, QTD, dan MTD ngukur total dari awal tahun, kuartal, atau bulan sampai hari ini. Ini cara ngitungnya di SQL pakai DATE_TRUNC, plus satu query gabungan.
Gap and Island Analysis di SQL
Gap and island analysis di SQL nyari deret data yang berturut-turut (island) dan celah yang bolong (gap). Cocok buat hitung streak login atau cari tanggal transaksi yang hilang.