PostgreSQL’de Rol ve Kullanıcı Yönetimi

Veritabanı güvenliğinin temeli, kimin neye erişebileceğini net bir şekilde tanımlamaktan geçer. PostgreSQL’de bu iş, rol ve kullanıcı yönetimi sistemi üzerinden yürür. Yıllarca “kullanıcı” ve “rol” kavramlarını ayrı düşünen DBA’lar, PostgreSQL 8.1 ile birlikte bu ikisinin aslında aynı mekanizmanın parçası olduğunu öğrendi. Bugün production ortamında sağlam bir erişim kontrolü kurmak istiyorsan, bu konuyu derinlemesine anlamak zorundasın.

Rol ve Kullanıcı Farkı Nedir?

PostgreSQL’de teknik olarak kullanıcı ve rol aynı şeydir. CREATE USER komutu aslında CREATE ROLE komutunun LOGIN yetkisiyle birlikte çalışan kısa yoludur. Yani her kullanıcı bir roldür, ama her rol bir kullanıcı değildir.

Bu ayrımı şöyle düşün: Rol, bir kimlik veya yetki kümesidir. Bazı roller doğrudan veritabanına bağlanabilir (kullanıcılar), bazıları ise sadece yetki gruplandırması için kullanılır (grup rolleri). Production ortamında genellikle şu yapıyı görürsün:

  • Grup rolleri: app_readonly, app_readwrite, reporting_team gibi isimler alır, LOGIN yetkisi yoktur
  • Kullanıcı rolleri: ali, deploy_user, app_service gibi isimler alır, LOGIN yetkisi vardır ve grup rollerine üye yapılır

Bu yapı, tek tek kullanıcılara yetki vermek yerine rolleri yönetmeyi çok daha kolay hale getirir.

Temel Rol Yönetimi Komutları

Yeni Rol ve Kullanıcı Oluşturma

-- Sadece grup rolü (LOGIN yetkisi yok)
CREATE ROLE app_readonly;

-- LOGIN yetkili kullanıcı (şifreyle)
CREATE ROLE ali WITH LOGIN PASSWORD 'guvenli_sifre_123';

-- Ya da kısa yol
CREATE USER fatma WITH PASSWORD 'baska_sifre_456';

-- Superuser rolü (dikkatli kullan!)
CREATE ROLE dba_admin WITH LOGIN PASSWORD 'super_sifre' SUPERUSER;

-- Bağlantı limiti olan kullanıcı
CREATE ROLE app_service WITH LOGIN PASSWORD 'servis_sifresi' CONNECTION LIMIT 20;

Mevcut Rolleri Listeleme

Hangi rollerin var olduğunu görmek için psql içinde du komutunu kullanabilirsin:

psql -U postgres -c "du"

Ya da doğrudan sistem kataloğundan sorgu atabilirsin:

psql -U postgres << 'EOF'
SELECT 
    rolname,
    rolsuper,
    rolinherit,
    rolcreaterole,
    rolcreatedb,
    rolcanlogin,
    rolconnlimit,
    rolvaliduntil
FROM pg_roles
ORDER BY rolname;
EOF

Bu sorgu sana tüm rollerin detaylı özelliklerini verir. rolcanlogin sütunu false olan roller grup rolleridir.

Rol Özelliklerini Değiştirme

-- Şifre değiştirme
ALTER ROLE ali WITH PASSWORD 'yeni_guvenli_sifre';

-- Rol özelliği ekleme/kaldırma
ALTER ROLE fatma WITH CREATEDB;
ALTER ROLE fatma WITH NOCREATEDB;

-- Şifre geçerlilik tarihi belirleme (güvenlik politikası için)
ALTER ROLE app_service VALID UNTIL '2025-12-31';

-- Bağlantı limitini güncelleme
ALTER ROLE app_service CONNECTION LIMIT 50;

-- Rolü devre dışı bırakma (silmeden)
ALTER ROLE eski_kullanici WITH NOLOGIN;

Yetki Sistemi: GRANT ve REVOKE

PostgreSQL’de yetkiler iki katmanda çalışır. Birincisi veritabanı seviyesi yetkiler (veritabanına bağlanma, şema oluşturma gibi), ikincisi nesne seviyesi yetkiler (tablo okuma, yazma, silme gibi).

Veritabanı Seviyesi Yetkiler

-- Veritabanına bağlanma yetkisi
GRANT CONNECT ON DATABASE uygulama_db TO app_readonly;
GRANT CONNECT ON DATABASE uygulama_db TO app_readwrite;

-- Şema kullanım yetkisi (bu olmadan tablolara erişilemiyor!)
GRANT USAGE ON SCHEMA public TO app_readonly;
GRANT USAGE ON SCHEMA public TO app_readwrite;

-- Şema oluşturma yetkisi
GRANT CREATE ON SCHEMA public TO app_readwrite;

Tablo Seviyesi Yetkiler

-- Sadece okuma yetkisi
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_readonly;

-- Okuma ve yazma
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_readwrite;

-- Sequence yetkisi (INSERT için genellikle gerekli)
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_readwrite;

-- Belirli bir tabloya özel yetki
GRANT SELECT ON TABLE musteri_listesi TO reporting_team;

-- Yetki geri alma
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM app_readonly;

Gelecekte Oluşturulacak Nesneler İçin Default Privileges

Bu konu çoğu sysadmin’in gözden kaçırdığı kritik bir detaydır. Bugün GRANT SELECT ON ALL TABLES desen bile yarın oluşturulan tablolar bu yetkiye dahil olmaz. Bunu çözmek için ALTER DEFAULT PRIVILEGES kullanmalısın:

-- postgres kullanıcısının oluşturacağı tablolar için otomatik yetki
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public
    GRANT SELECT ON TABLES TO app_readonly;

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_readwrite;

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public
    GRANT USAGE, SELECT ON SEQUENCES TO app_readwrite;

Bu komutu ekledikten sonra DBA postgres kullanıcısıyla yeni tablo oluşturduğunda yetkiler otomatik olarak verilecektir.

Rol Üyeliği: Kullanıcıları Gruplara Atama

-- Kullanıcıları gruplara ekle
GRANT app_readonly TO ali;
GRANT app_readwrite TO fatma;
GRANT app_readonly TO reporting_user;

-- Birden fazla kullanıcıya aynı anda
GRANT app_readonly TO ali, mehmet, ayse;

-- Üyelikten çıkarma
REVOKE app_readonly FROM ali;

-- Mevcut üyelikleri görme
SELECT 
    r.rolname AS rol,
    m.rolname AS uye
FROM pg_roles r
JOIN pg_auth_members am ON r.oid = am.roleid
JOIN pg_roles m ON am.member = m.oid
ORDER BY r.rolname;

Gerçek Dünya Senaryosu: E-Ticaret Uygulaması

Diyelim ki bir e-ticaret platformu kuruyorsun. Farklı ekiplerin farklı seviyelerde erişime ihtiyacı var:

  • Uygulama servisi: Sadece kendi şemasındaki tablolara okuma/yazma
  • Raporlama ekibi: Tüm veritabanını sadece okuyabilmeli
  • DBA ekibi: Tam kontrol
  • Geliştirici ekibi: Development ortamında kendi şemalarını yönetebilmeli
-- Önce veritabanını oluştur
CREATE DATABASE eticaret_db;

c eticaret_db

-- Şema oluştur
CREATE SCHEMA app_schema;
CREATE SCHEMA reporting_schema;

-- Grup rolleri oluştur
CREATE ROLE eticaret_app_rw;
CREATE ROLE eticaret_reporting_ro;
CREATE ROLE eticaret_dba;

-- Uygulama rolüne yetkiler
GRANT CONNECT ON DATABASE eticaret_db TO eticaret_app_rw;
GRANT USAGE ON SCHEMA app_schema TO eticaret_app_rw;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app_schema TO eticaret_app_rw;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA app_schema TO eticaret_app_rw;

-- Raporlama rolüne yetkiler
GRANT CONNECT ON DATABASE eticaret_db TO eticaret_reporting_ro;
GRANT USAGE ON SCHEMA app_schema, reporting_schema TO eticaret_reporting_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA app_schema TO eticaret_reporting_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA reporting_schema TO eticaret_reporting_ro;

-- Kullanıcı oluştur ve rollere ata
CREATE USER app_service WITH LOGIN PASSWORD 'app_sifre_2024' CONNECTION LIMIT 30;
CREATE USER rapor_kullanici WITH LOGIN PASSWORD 'rapor_sifre_2024';
CREATE USER dba_ahmet WITH LOGIN PASSWORD 'dba_sifre_2024' CREATEDB CREATEROLE;

GRANT eticaret_app_rw TO app_service;
GRANT eticaret_reporting_ro TO rapor_kullanici;

-- Default privileges ayarla
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA app_schema
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO eticaret_app_rw;

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA app_schema
    GRANT USAGE, SELECT ON SEQUENCES TO eticaret_app_rw;

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA app_schema
    GRANT SELECT ON TABLES TO eticaret_reporting_ro;

Bu yapıyla yeni bir geliştirici ekibe katıldığında sadece GRANT eticaret_app_rw TO yeni_kullanici; yazman yeterli.

pg_hba.conf ile Erişim Kontrolü

Rol yönetimi tek başına yeterli değil. pg_hba.conf dosyası kimlik doğrulama katmanını kontrol eder. Bu dosyada yapılan değişiklikler pg_reload_conf() ile devreye alınabilir:

# /etc/postgresql/15/main/pg_hba.conf

# Yerel bağlantılar için peer authentication
local   all             postgres                                peer

# Uygulama servisi sadece kendi veritabanına, sadece md5 ile bağlanabilir
host    eticaret_db     app_service     10.0.1.0/24            scram-sha-256

# Raporlama sunucusundan sadece okuma kullanıcısı
host    eticaret_db     rapor_kullanici 10.0.2.50/32           scram-sha-256

# DBA ekibi VPN üzerinden
host    all             dba_ahmet       10.0.0.0/8             scram-sha-256

# Tüm diğer bağlantıları reddet
host    all             all             0.0.0.0/0              reject
# Değişiklikleri uygula (restart gerekmez)
psql -U postgres -c "SELECT pg_reload_conf();"

Row Level Security (RLS) ile Gelişmiş Erişim Kontrolü

Bazen tablo bazlı yetki kontrolü yetmez, satır bazında kısıtlama gerekir. Örneğin, her müşteri temsilcisi sadece kendi müşterilerini görebilmeli:

-- RLS'yi aktifleştir
ALTER TABLE musteriler ENABLE ROW LEVEL SECURITY;

-- Policy oluştur
CREATE POLICY musteri_politikasi ON musteriler
    FOR ALL
    TO app_service
    USING (temsilci_id = current_user);

-- Raporlama için tüm satırları gören policy
CREATE POLICY raporlama_politikasi ON musteriler
    FOR SELECT
    TO eticaret_reporting_ro
    USING (true);

-- Superuser'lar RLS'yi bypass eder, ama bunu devre dışı bırakabilirsin
ALTER TABLE musteriler FORCE ROW LEVEL SECURITY;

Rol Özelliklerinin Detaylı İncelenmesi

Bir rolün sahip olabileceği temel özellikler şunlardır:

  • SUPERUSER / NOSUPERUSER: Tüm yetki kontrollerini atlar, çok dikkatli kullanılmalı
  • CREATEDB / NOCREATEDB: Yeni veritabanı oluşturma yetkisi
  • CREATEROLE / NOCREATEROLE: Yeni rol oluşturma ve yönetme yetkisi
  • INHERIT / NOINHERIT: Üye olduğu rollerden yetkileri otomatik miras alır
  • LOGIN / NOLOGIN: Doğrudan veritabanına bağlanabilme
  • REPLICATION / NOREPLICATION: Replication bağlantısı kurabilme
  • BYPASSRLS / NOBYPASSRLS: Row Level Security politikalarını atlama
  • CONNECTION LIMIT sayı: Eş zamanlı bağlantı sayısı limiti (-1 limitsiz)
  • PASSWORD ‘sifre’: Giriş şifresi
  • VALID UNTIL ‘tarih’: Şifre geçerlilik tarihi

Yetki Denetimi ve Sorun Giderme

Production’da “neden bu kullanıcı bu tabloya erişemiyor?” sorusuyla sık karşılaşırsın. Şu sorgular hayat kurtarır:

-- Bir kullanıcının tüm yetkilerini kontrol et
SELECT 
    grantee,
    table_schema,
    table_name,
    privilege_type
FROM information_schema.role_table_grants
WHERE grantee = 'app_service'
ORDER BY table_schema, table_name;

-- Şema bazında yetkiler
SELECT 
    nspname AS schema_adi,
    nspacl AS yetkiler
FROM pg_namespace
WHERE nspname NOT LIKE 'pg_%'
AND nspname != 'information_schema';

-- Hangi rollerin hangi rollere üye olduğu
SELECT 
    r.rolname AS uye_rol,
    p.rolname AS parent_rol,
    m.admin_option
FROM pg_roles r
JOIN pg_auth_members m ON r.oid = m.member
JOIN pg_roles p ON m.roleid = p.oid
ORDER BY parent_rol, uye_rol;

-- Belirli bir nesne üzerindeki tüm yetkiler
SELECT 
    grantee,
    privilege_type,
    is_grantable
FROM information_schema.role_table_grants
WHERE table_name = 'musteriler'
AND table_schema = 'app_schema';

Şifre Güvenliği ve Politikaları

PostgreSQL 10 ile birlikte gelen scram-sha-256 yöntemi, eski md5‘e göre çok daha güvenlidir. postgresql.conf dosyasında şu ayarı yapmalısın:

# postgresql.conf
password_encryption = scram-sha-256

Mevcut md5 şifreli kullanıcıları scram-sha-256’ya geçirmek için:

# Önce konfigürasyonu değiştir ve reload et
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();

# Sonra kullanıcı şifrelerini yenile (şifreyi bilmen gerekiyor)
ALTER ROLE ali WITH PASSWORD 'mevcut_veya_yeni_sifre';

# Doğrulama
SELECT rolname, rolpassword 
FROM pg_authid 
WHERE rolname = 'ali';
-- scram-sha-256 ile başlıyorsa başarılı

Şifre politikası için passwordcheck extension’ını kullanabilirsin:

# postgresql.conf
shared_preload_libraries = 'passwordcheck'

Bu extension aktifken zayıf şifreler reddedilir.

Rol Silme ve Temizlik

Bir kullanıcı sistemden ayrıldığında sadece rolü silmek yetmez, sahip olduğu nesnelerin de devredilmesi gerekir:

-- Önce başka bir role devret
REASSIGN OWNED BY eski_kullanici TO postgres;

-- Sahip olunan nesneleri sil (dikkatli!)
DROP OWNED BY eski_kullanici;

-- Sonra rolü sil
DROP ROLE eski_kullanici;

-- Ya da daha güvenli yaklaşım: önce devre dışı bırak
ALTER ROLE eski_kullanici WITH NOLOGIN;
-- Bir süre bekle, emin ol, sonra sil

Otomasyon: Rol Yönetimi Script’i

Büyük ortamlarda elle yönetim yetersiz kalır. İşte basit bir Bash script’i:

#!/bin/bash
# create_app_user.sh - Yeni uygulama kullanıcısı oluşturur

DB_HOST="localhost"
DB_PORT="5432"
DB_NAME="eticaret_db"
ADMIN_USER="postgres"

if [ $# -ne 2 ]; then
    echo "Kullanim: $0 <kullanici_adi> <rol_tipi>"
    echo "Rol tipleri: readonly, readwrite"
    exit 1
fi

USERNAME=$1
ROLE_TYPE=$2
TEMP_PASSWORD=$(openssl rand -base64 16)

case $ROLE_TYPE in
    readonly)
        GROUP_ROLE="eticaret_reporting_ro"
        ;;
    readwrite)
        GROUP_ROLE="eticaret_app_rw"
        ;;
    *)
        echo "Gecersiz rol tipi: $ROLE_TYPE"
        exit 1
        ;;
esac

psql -h $DB_HOST -p $DB_PORT -U $ADMIN_USER << EOF
CREATE ROLE ${USERNAME} WITH LOGIN PASSWORD '${TEMP_PASSWORD}' 
    CONNECTION LIMIT 10 
    VALID UNTIL '$(date -d "+90 days" +%Y-%m-%d)';
GRANT ${GROUP_ROLE} TO ${USERNAME};
EOF

if [ $? -eq 0 ]; then
    echo "Kullanici olusturuldu: ${USERNAME}"
    echo "Gecici sifre: ${TEMP_PASSWORD}"
    echo "Sifre gecerlilik suresi: 90 gun"
    echo "Lutfen kullaniciyi ilk giriste sifresini degistirmesi icin bilgilendirin."
else
    echo "HATA: Kullanici olusturulamadi!"
    exit 1
fi

Sonuç

PostgreSQL rol ve kullanıcı yönetimi, ilk bakışta basit görünse de production ortamında doğru uygulamak ciddi dikkat gerektiriyor. En çok yapılan hatalar şunlar: superuser yetkisini gereğinden fazla dağıtmak, default privileges’ı unutmak ve pg_hba.conf’u ihmal etmek.

İyi bir yetki mimarisi için şu prensipleri aklında tut: her uygulama bileşeni için ayrı kullanıcı oluştur, kullanıcılara doğrudan yetki vermek yerine grup rolleri kullan, ve least privilege prensibini uygula yani her kullanıcı sadece işini yapacak kadar yetkiye sahip olsun. Şifreleme yöntemi olarak scram-sha-256’ya geç ve bağlantı limitlerini belirle.

Düzenli olarak pg_roles ve information_schema sorgularıyla mevcut yetki dağılımını denetlemek, güvenlik açıklarını önceden fark etmeni sağlar. Rol yönetimini bir kere doğru kurduğunda, sonraki her yeni kullanıcı ekleme işlemi dakikalar içinde tamamlanır.

Yorum yapın