Role yang sudah dibuat belum bisa berbuat apa-apa terhadap objek database. Di PostgreSQL, setiap operasi — membaca tabel, memanggil function, mengambil nomor dari sequence — harus didukung privilege yang relevan pada objek itu, dan privilege tidak pernah diberikan secara otomatis kecuali beberapa bawaan yang sengaja dipilih desainer sistem. Chapter ini memetakan seluruh taksonomi privilege sebelum kita menyentuh mekanisme pemberiannya: privilege apa yang berlaku untuk tabel, schema, database, sequence, dan function; hak bawaan apa yang diterima role baru tanpa satu pun GRANT; serta bagaimana memeriksa siapa memiliki apa dengan \dp dan catalog. Pemahaman peta ini membuat perintah GRANT dan REVOKE di chapter berikutnya terasa seperti mengisi formulir yang sudah dikenal.
Taksonomi Privilege Per Jenis Objek #
Privilege tidak berlaku seragam untuk semua objek; setiap jenis objek mendefinisikan haknya sendiri. Tabel berikut merangkum yang paling sering dipakai sehari-hari:
| Objek | Privilege yang berlaku |
|---|---|
| Tabel dan view | SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER |
| Kolom (tabel) | SELECT, INSERT, UPDATE, REFERENCES — versi kolom dari hak tabel |
| Sequence | USAGE, SELECT, UPDATE |
| Schema | USAGE, CREATE |
| Database | CREATE, CONNECT, TEMP |
| Function/procedure | EXECUTE |
| Type/domain | USAGE |
Hak tabel seperti SELECT dan INSERT sudah akrab; REFERENCES diperlukan untuk membuat foreign key yang menunjuk tabel tersebut, TRIGGER untuk memasang trigger, dan TRUNCATE untuk mengosongkan tabel sekaligus. Pada sequence, USAGE mengizinkan nextval() dan currval(), SELECT mengizinkan membaca nilai terakhir, dan UPDATE mengizinkan setval(). Dua level pembungkus — CONNECT pada database serta USAGE pada schema — sering dilupakan pemula padahal menjadi gerbang ganda yang harus dilalui sebelum hak tabel bisa dipakai; schema privileges kita bahas tuntas di chapter khususnya.
Pemilik Objek dan Logika “Hak Tak Terbatas” #
Siapa yang membuat objek, dialah pemiliknya — dan pemilik tidak perlu GRANT apa pun untuk memakai objeknya sendiri. File pembuka menyiapkan bahan latihan lengkap (tabel, sequence, function) yang seluruhnya dibuat oleh postgres, lalu meminta daftar hak dari catalog:
-- Bahan latihan chapter Privileges: tabel, sequence, dan function,
-- semuanya dibuat oleh postgres sehingga berstatus pemilik.
DROP ROLE IF EXISTS kasir_tmj;
DROP ROLE IF EXISTS auditor_tmj;
CREATE ROLE kasir_tmj LOGIN;
CREATE ROLE auditor_tmj LOGIN;
CREATE TABLE penjualan (
id integer PRIMARY KEY,
produk text NOT NULL,
jumlah integer NOT NULL,
harga numeric(10,2) NOT NULL
);
INSERT INTO penjualan (id, produk, jumlah, harga) VALUES
(1, 'Kopi Gayo', 10, 85000.00),
(2, 'Teh Melati', 25, 35000.00),
(3, 'Gula Merah', 40, 15000.00);
CREATE SEQUENCE no_nota START 100;
CREATE FUNCTION hitung_baris() RETURNS bigint
LANGUAGE sql
RETURN (SELECT count(*) FROM penjualan);
-- Pemilik objek menikmati seluruh privilege tanpa satu pun GRANT.
-- Catalog information_schema mencatat semuanya atas nama postgres.
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'penjualan'
ORDER BY grantee, privilege_type;Output yang Dihasilkan:
DROP ROLE
DROP ROLE
CREATE ROLE
CREATE ROLE
CREATE TABLE
INSERT 0 3
CREATE SEQUENCE
CREATE FUNCTION
grantee | privilege_type
----------+----------------
postgres | DELETE
postgres | INSERT
postgres | REFERENCES
postgres | SELECT
postgres | TRIGGER
postgres | TRUNCATE
postgres | UPDATE
(7 rows)Query information_schema.role_table_grants menampilkan tujuh privilege tabel atas nama postgres padahal tidak ada satu baris GRANT pun di file ini. Itulah makna kepemilikan: hak penuh tercatat seolah-olah diberikan, tanpa bisa dicabut dengan REVOKE biasa. Kepemilikan berpindah lewat ALTER TABLE ... OWNER TO — perintah yang kita pakai di chapter Membuat dan Menghapus Role
saat menyiapkan role dengan tanggungan — dan satu-satunya peran lain yang setara adalah superuser yang melewati semua pemeriksaan.
Hak Bawaan yang Diterima Tanpa GRANT #
Desain PostgreSQL memilih beberapa hak diberikan sejak awal kepada pseudo-role PUBLIC — kumpulan semua role yang ada. File berikut memeriksa semuanya dari sudut pandang kasir_tmj yang belum menerima GRANT apa pun:
-- Hak bawaan yang role baru terima tanpa GRANT apa pun,
-- diperiksa dari tiga level objek: database, schema, dan objek di dalamnya.
-- Level database: CONNECT dan TEMP diberikan ke PUBLIC secara bawaan.
SELECT has_database_privilege('kasir_tmj', current_database(), 'CONNECT') AS bisa_koneksi,
has_database_privilege('kasir_tmj', current_database(), 'TEMP') AS bisa_tabel_sementara,
has_database_privilege('kasir_tmj', current_database(), 'CREATE') AS bisa_buat_skema;
-- Level schema: sejak PostgreSQL 15 PUBLIC hanya punya USAGE pada schema
-- public; hak CREATE sudah dicabut. Catalog menunjukkan ACL aslinya.
SELECT nspname, nspacl
FROM pg_namespace
WHERE nspname = 'public';
SELECT has_schema_privilege('kasir_tmj', 'public', 'USAGE') AS bisa_akses_schema,
has_schema_privilege('kasir_tmj', 'public', 'CREATE') AS bisa_buat_tabel;
-- Level objek: EXECUTE pada function diberikan ke PUBLIC secara bawaan,
-- sedangkan sequence tidak mendapat hak bawaan apa pun.
SELECT has_function_privilege('kasir_tmj', 'hitung_baris()', 'EXECUTE') AS bisa_panggil_fungsi;
SELECT has_sequence_privilege('kasir_tmj', 'no_nota', 'USAGE') AS seq_usage,
has_sequence_privilege('kasir_tmj', 'no_nota', 'SELECT') AS seq_select,
has_sequence_privilege('kasir_tmj', 'no_nota', 'UPDATE') AS seq_update;Output yang Dihasilkan:
bisa_koneksi | bisa_tabel_sementara | bisa_buat_skema
--------------+----------------------+-----------------
t | t | f
(1 row)
nspname | nspacl
---------+---------------------------------------------------------------
public | {pg_database_owner=UC/pg_database_owner,=U/pg_database_owner}
(1 row)
bisa_akses_schema | bisa_buat_tabel
-------------------+-----------------
t | f
(1 row)
bisa_panggil_fungsi
---------------------
t
(1 row)
seq_usage | seq_select | seq_update
-----------+------------+------------
f | f | f
(1 row)Tiga kelompok fakta terbaca dari hasilnya. Pertama, pada level database kasir_tmj boleh CONNECT dan membuat tabel sementara (TEMP) — keduanya hak bawaan PUBLIC — tetapi tidak boleh CREATE skema di database milik postgres. Kedua, pada schema public role itu hanya memegang USAGE; baris nspacl memperlihatkan mengapa: pg_database_owner memegang UC (USAGE + CREATE) sedangkan PUBLIC hanya U. Ketiga, EXECUTE pada function juga hak bawaan PUBLIC, sementara sequence no_nota tidak memberikan apa-apa — f pada tiga kolom terakhir.
Memeriksa Privilege dengan \dp dan Catalog #
Dua alat pemeriksa saling melengkapi. Meta-command \dp di psql memberi ringkasan visual satu objek dalam satu tampilan — termasuk versi kolomnya nanti — sedangkan catalog information_schema dan fungsi keluarga has_*_privilege bisa ditanyai dengan query biasa dan difilter sesuka hati. File berikut memberi privilege pertama kepada auditor_tmj, lalu memeriksa hasilnya dengan kedua alat:
-- Memberi privilege pertama sebagai pembuka jalan chapter GRANT dan REVOKE,
-- lalu memeriksa hasilnya dengan dua alat: meta-command \dp dan catalog.
GRANT SELECT ON penjualan TO auditor_tmj;
GRANT USAGE, SELECT ON SEQUENCE no_nota TO auditor_tmj;
-- \dp meringkas seluruh privilege pada satu objek dalam satu tampilan.
\dp penjualan
-- Catalog information_schema dapat ditanyai dengan query biasa
-- dan hanya menampilkan grant yang benar-benar diberikan.
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'penjualan'
ORDER BY grantee, privilege_type;
-- Verifikasi sequence lewat fungsi pemeriksa privilege.
SELECT has_sequence_privilege('auditor_tmj', 'no_nota', 'USAGE') AS seq_usage,
has_sequence_privilege('auditor_tmj', 'no_nota', 'SELECT') AS seq_select;Output yang Dihasilkan:
GRANT
GRANT
Access privileges
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+-----------+-------+----------------------------+-------------------+----------
public | penjualan | table | postgres=arwdDxtm/postgres+| |
| | | auditor_tmj=r/postgres | |
(1 row)
grantee | privilege_type
-------------+----------------
auditor_tmj | SELECT
postgres | DELETE
postgres | INSERT
postgres | REFERENCES
postgres | SELECT
postgres | TRIGGER
postgres | TRUNCATE
postgres | UPDATE
(8 rows)
seq_usage | seq_select
-----------+------------
t | t
(1 row)Mari kita baca kedua hasilnya. Kolom Access privileges dari \dp menampilkan dua entri: postgres=arwdDxtm/postgres untuk pemilik dan auditor_tmj=r/postgres untuk grantee. Huruf-huruf itu kode ringkas privilege — r SELECT, w UPDATE, a INSERT, d DELETE, D TRUNCATE, x REFERENCES, t TRIGGER, m MAINTAIN (fitur baru PostgreSQL 17 untuk VACUUM dan maintenance) — dan nama setelah garis miring adalah grantor. Sementara itu, query information_schema.role_table_grants mengembalikan bentuk panjang yang lebih mudah diproses programatik: delapan baris, tujuh milik pemilik dan satu SELECT milik auditor_tmj. Pemeriksaan sequence menutup file dengan konfirmasi bahwa USAGE dan SELECT kini dimiliki auditor.
Fungsi keluarga has_*_privilege pada file sebelumnya sebenarnya alat ketiga yang paling praktis untuk skrip pengecekan: has_table_privilege, has_schema_privilege, has_database_privilege, has_function_privilege, dan has_sequence_privilege menerima nama role dan objek lalu menjawab t/f — pasangan sempurna untuk pengujian otomatis konfigurasi hak akses.
Membersihkan Role Latihan #
Pola penutup yang sama berlaku untuk setiap chapter di section ini — DROP OWNED BY melepas seluruh privilege yang diterima role di database berjalan, lalu DROP ROLE menghapusnya dari cluster:
-- Membersihkan role latihan chapter ini.
DROP OWNED BY kasir_tmj;
DROP OWNED BY auditor_tmj;
DROP ROLE kasir_tmj;
DROP ROLE auditor_tmj;
SELECT count(*) AS sisa_role_latihan
FROM pg_roles
WHERE rolname IN ('kasir_tmj', 'auditor_tmj');Output yang Dihasilkan:
DROP OWNED
DROP OWNED
DROP ROLE
DROP ROLE
sisa_role_latihan
-------------------
0
(1 row)Peta privilege kini tergambar lengkap: jenis objek dengan haknya masing-masing, posisi istimewa pemilik, hak bawaan PUBLIC, dan cara memeriksanya. Yang belum kita bahas adalah kata kerjanya — bagaimana hak itu dibagikan dengan GRANT, dibatasi sampai tingkat kolom, diwariskan dengan GRANT OPTION, lalu dicabut kembali dengan REVOKE beserta efek kaskadenya. Semuanya menunggu di chapter GRANT dan REVOKE
.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
bersihkan.sql
Unduh berkas-- Membersihkan role latihan chapter ini.
DROP OWNED BY kasir_tmj;
DROP OWNED BY auditor_tmj;
DROP ROLE kasir_tmj;
DROP ROLE auditor_tmj;
SELECT count(*) AS sisa_role_latihan
FROM pg_roles
WHERE rolname IN ('kasir_tmj', 'auditor_tmj');
cek-hak.sql
Unduh berkas-- Memberi privilege pertama sebagai pembuka jalan chapter GRANT dan REVOKE,
-- lalu memeriksa hasilnya dengan dua alat: meta-command \dp dan catalog.
GRANT SELECT ON penjualan TO auditor_tmj;
GRANT USAGE, SELECT ON SEQUENCE no_nota TO auditor_tmj;
-- \dp meringkas seluruh privilege pada satu objek dalam satu tampilan.
\dp penjualan
-- Catalog information_schema dapat ditanyai dengan query biasa
-- dan hanya menampilkan grant yang benar-benar diberikan.
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'penjualan'
ORDER BY grantee, privilege_type;
-- Verifikasi sequence lewat fungsi pemeriksa privilege.
SELECT has_sequence_privilege('auditor_tmj', 'no_nota', 'USAGE') AS seq_usage,
has_sequence_privilege('auditor_tmj', 'no_nota', 'SELECT') AS seq_select;
hak-bawaan.sql
Unduh berkas-- Hak bawaan yang role baru terima tanpa GRANT apa pun,
-- diperiksa dari tiga level objek: database, schema, dan objek di dalamnya.
-- Level database: CONNECT dan TEMP diberikan ke PUBLIC secara bawaan.
SELECT has_database_privilege('kasir_tmj', current_database(), 'CONNECT') AS bisa_koneksi,
has_database_privilege('kasir_tmj', current_database(), 'TEMP') AS bisa_tabel_sementara,
has_database_privilege('kasir_tmj', current_database(), 'CREATE') AS bisa_buat_skema;
-- Level schema: sejak PostgreSQL 15 PUBLIC hanya punya USAGE pada schema
-- public; hak CREATE sudah dicabut. Catalog menunjukkan ACL aslinya.
SELECT nspname, nspacl
FROM pg_namespace
WHERE nspname = 'public';
SELECT has_schema_privilege('kasir_tmj', 'public', 'USAGE') AS bisa_akses_schema,
has_schema_privilege('kasir_tmj', 'public', 'CREATE') AS bisa_buat_tabel;
-- Level objek: EXECUTE pada function diberikan ke PUBLIC secara bawaan,
-- sedangkan sequence tidak mendapat hak bawaan apa pun.
SELECT has_function_privilege('kasir_tmj', 'hitung_baris()', 'EXECUTE') AS bisa_panggil_fungsi;
SELECT has_sequence_privilege('kasir_tmj', 'no_nota', 'USAGE') AS seq_usage,
has_sequence_privilege('kasir_tmj', 'no_nota', 'SELECT') AS seq_select,
has_sequence_privilege('kasir_tmj', 'no_nota', 'UPDATE') AS seq_update;
siapkan-privilege.sql
Unduh berkas-- Bahan latihan chapter Privileges: tabel, sequence, dan function,
-- semuanya dibuat oleh postgres sehingga berstatus pemilik.
DROP ROLE IF EXISTS kasir_tmj;
DROP ROLE IF EXISTS auditor_tmj;
CREATE ROLE kasir_tmj LOGIN;
CREATE ROLE auditor_tmj LOGIN;
CREATE TABLE penjualan (
id integer PRIMARY KEY,
produk text NOT NULL,
jumlah integer NOT NULL,
harga numeric(10,2) NOT NULL
);
INSERT INTO penjualan (id, produk, jumlah, harga) VALUES
(1, 'Kopi Gayo', 10, 85000.00),
(2, 'Teh Melati', 25, 35000.00),
(3, 'Gula Merah', 40, 15000.00);
CREATE SEQUENCE no_nota START 100;
CREATE FUNCTION hitung_baris() RETURNS bigint
LANGUAGE sql
RETURN (SELECT count(*) FROM penjualan);
-- Pemilik objek menikmati seluruh privilege tanpa satu pun GRANT.
-- Catalog information_schema mencatat semuanya atas nama postgres.
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'penjualan'
ORDER BY grantee, privilege_type;