Peran dan Hak Akses
CREATE ROLE aplikasi LOGIN PASSWORD 'rahasia-kuat';
GRANT CONNECT ON DATABASE toko TO aplikasi;
GRANT USAGE ON SCHEMA publik TO aplikasi;
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA publik TO aplikasi;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA publik TO aplikasi;
-- WAJIB: berlaku juga untuk tabel yang dibuat NANTI
ALTER DEFAULT PRIVILEGES IN SCHEMA publik
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO aplikasi;
-- Peran khusus baca untuk dasbor & analitik
CREATE ROLE pembaca;
GRANT CONNECT ON DATABASE toko TO pembaca;
GRANT USAGE ON SCHEMA publik TO pembaca;
GRANT SELECT ON ALL TABLES IN SCHEMA publik TO pembaca;
CREATE ROLE analis LOGIN PASSWORD 'lain' IN ROLE pembaca;
GRANT ... ON ALL TABLES hanya berlaku untuk tabel yang sudah ada saat itu. Tabel yang dibuat migrasi berikutnya tidak akan terjangkau, dan aplikasi tiba-tiba mendapat "permission denied" setelah rilis. ALTER DEFAULT PRIVILEGES menutup celah ini — tetapi perhatikan bahwa ia hanya berlaku untuk objek yang dibuat oleh peran yang menjalankan perintah tersebut.
Row Level Security
RLS menegakkan penyaringan baris di dalam basis data, sehingga tidak bergantung pada aplikasi selalu menuliskan klausa WHERE yang benar.
CREATE TABLE dokumen (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
penyewa_id bigint NOT NULL,
judul text,
isi text
);
ALTER TABLE dokumen ENABLE ROW LEVEL SECURITY;
CREATE POLICY isolasi_penyewa ON dokumen
USING (penyewa_id = current_setting('app.penyewa_id')::bigint);
CREATE POLICY sisip_penyewa ON dokumen
FOR INSERT
WITH CHECK (penyewa_id = current_setting('app.penyewa_id')::bigint);
-- Aplikasi menetapkan konteks di awal tiap transaksi BEGIN; SET LOCAL app.penyewa_id = '42'; SELECT * FROM dokumen; -- otomatis hanya milik penyewa 42 COMMIT;
Dengan connection pooler, koneksi dipakai bergantian oleh permintaan yang berbeda. SET biasa bertahan setelah transaksi selesai, sehingga permintaan berikutnya bisa mewarisi konteks penyewa yang salah — kebocoran data lintas penyewa yang sangat serius. SET LOCAL otomatis hilang saat transaksi berakhir.
Secara bawaan, pemilik tabel dan peran SUPERUSER melewati semua kebijakan RLS. Bila aplikasi Anda terhubung sebagai pemilik tabel, RLS tidak melindungi apa pun. Aplikasi harus memakai peran terpisah yang bukan pemilik. Untuk memaksa RLS berlaku bahkan pada pemilik:
ALTER TABLE dokumen FORCE ROW LEVEL SECURITY;
Kolom Sensitif
-- Hak akses per kolom
GRANT SELECT (id, nama, email) ON pengguna TO analis;
-- kolom lain seperti nik dan tanggal_lahir tidak terjangkau
-- View sebagai lapisan penyamaran
CREATE VIEW pengguna_publik AS
SELECT id, nama,
left(email, 2) || '***@' || split_part(email, '@', 2) AS email
FROM pengguna;
GRANT SELECT ON pengguna_publik TO analis;
Enkripsi & Autentikasi
-- pg_hba.conf hostssl toko aplikasi 10.0.0.0/8 scram-sha-256 host all all 0.0.0.0/0 reject -- postgresql.conf ssl = on password_encryption = scram-sha-256
Metode autentikasi md5 sudah lama dianggap lemah. Gunakan scram-sha-256 untuk semua entri pg_hba.conf. Perlu diingat bahwa mengubah password_encryption saja tidak cukup — password yang sudah ada tetap tersimpan dalam format lama sampai disetel ulang.
Audit
ALTER SYSTEM SET log_connections = on; ALTER SYSTEM SET log_disconnections = on; ALTER SYSTEM SET log_statement = 'ddl'; -- semua perubahan skema -- Memeriksa siapa punya hak apa SELECT grantee, table_name, privilege_type FROM information_schema.table_privileges WHERE table_schema = 'publik' ORDER BY grantee, table_name;