$ dbaguide.com / cheat-sheets / postgresql / security

PostgreSQL Güvenlik Hardening

Production Veritabanları için Uçtan Uca Güvenlik Sıkılaştırma Rehberi

PostgreSQL 15 / 16 / 17 uyumlu
Güncelleme: Ekim 2026 · Production-grade
01

Kimlik Doğrulama pg_hba.conf

En Kritik
MetotDurumAçıklama
scram-sha-256ÖNERİLENChallenge-response, tuzlu hash. Varsayılan (PG14+).
certÖNERİLENİstemci sertifikası ile doğrulama (hostssl).
peerLokalUnix socket — OS kullanıcı adı eşleşmesi.
md5ESKİZayıf hash, replay riski. PG18'de deprecated.
passwordYASAKParola ağda düz metin olarak gider.
trustYASAKParolasız giriş! Sadece izole localhost.
Güvenli pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD local all postgres peer local all all scram-sha-256 hostssl app_db app_user 10.0.1.0/24 scram-sha-256 hostssl all dba_team 10.0.9.0/28 cert hostssl replication repl 10.0.2.11/32 scram-sha-256 hostnossl all all 0.0.0.0/0 reject # KALDIR ↓ host all all 0.0.0.0/0 trust
Uygula & Doğrula
-- Yeniden başlatmadan uygula SELECT pg_reload_conf(); -- Kuralları ve hataları kontrol et SELECT line_number, type, database, user_name, address, auth_method, error FROM pg_hba_file_rules ORDER BY line_number; -- md5 hash'li kullanıcıları bul SELECT rolname FROM pg_authid WHERE rolpassword LIKE 'md5%';
⚠ Dikkat: pg_hba.conf ilk eşleşen satırı uygular — kısıtlayıcı kuralları üste yaz. Reload öncesi error kolonu boş olmalı; aksi halde kural yüklenmez.
02

Parola Politikası

Parametre / ÖzellikÖnerilen
password_encryptionYeni parolaların hash algoritması (postgresql.conf).scram-sha-256
passwordcheckZayıf parolaları reddeder. shared_preload_libraries ile yüklenir.Etkin
VALID UNTILParola son kullanma tarihi (insan hesapları).90 gün
CREATEROLERol oluşturma yetkisi — yalnızca yönetici rollerine.Kısıtla
LOGIN + NOINHERITServis hesapları üye rollerin yetkilerini otomatik devralmaz.Servis hesabı
auth_delay.millisecondsBaşarısız girişte gecikme — brute-force yavaşlatır.500
postgresql.conf
password_encryption = 'scram-sha-256' shared_preload_libraries = 'passwordcheck,auth_delay' auth_delay.milliseconds = 500 authentication_timeout = 30s
Rol & Parola Yönetimi
-- İnsan hesabı: süreli parola CREATE ROLE ali LOGIN PASSWORD 'G%7xQ!r2...' VALID UNTIL '2027-01-10'; -- Servis hesabı: miras yok, bağlantı limiti CREATE ROLE svc_api LOGIN NOINHERIT CONNECTION LIMIT 50 PASSWORD '...'; -- CREATEROLE yetkisini geri al ALTER ROLE app_admin NOCREATEROLE; -- Süresi dolan / dolacak parolalar SELECT rolname, rolvaliduntil FROM pg_roles WHERE rolcanlogin AND rolvaliduntil < now() + interval '14 days';
⚠ Dikkat: passwordcheck yalnızca düz metin gönderilen parolaları denetleyebilir. psql \password parolayı istemcide hash'ler — bu durumda kontrol atlanır.
✓ İyi Pratik: PG16+ ile CREATEROLE sahibi yalnızca ADMIN OPTION sahibi olduğu rolleri yönetebilir — yetki zincirini düzenli denetle.
03

Ağ Güvenliği postgresql.conf

ParametreVarsayılanÖnerilen
listen_addressesSadece gerekli arayüzleri dinle; '*' kullanma.localhost'localhost,10.0.1.5'
portPort değişimi güvenlik değildir, ama tarama gürültüsünü azaltır.54325432 / özel
sslTLS şifrelemesini etkinleştir.offon
ssl_min_protocol_versionTLS 1.0/1.1 protokollerini engelle.TLSv1.2TLSv1.2+
ssl_ciphersZayıf şifre takımlarını hariç tut.HIGH:MEDIUM...HIGH:!aNULL
:!MD5:!3DES
ssl_prefer_server_ciphersSunucu şifre sırasını kullan.onon
max_connectionsDoS yüzeyini sınırla; pooler (PgBouncer) kullan.100ihtiyaca göre
SSL/TLS Yapılandırması
listen_addresses = 'localhost,10.0.1.5' ssl = on ssl_cert_file = 'server.crt' ssl_key_file = 'server.key' # chmod 600 ssl_ca_file = 'root.crt' ssl_min_protocol_version = 'TLSv1.2' ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES:!RC4'
Firewall (katmanlı savunma)
# Sadece uygulama alt ağı → 5432 ufw allow from 10.0.1.0/24 to any port 5432 proto tcp ufw deny 5432/tcp # firewalld alternatifi firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.1.0/24 port port=5432 protocol=tcp accept'
Aktif Bağlantılarda SSL Kontrolü
SELECT a.usename, a.client_addr, s.ssl, s.version, s.cipher FROM pg_stat_ssl s JOIN pg_stat_activity a USING (pid) WHERE a.backend_type = 'client backend';
✓ İyi Pratik: Firewall + listen_addresses + pg_hba.conf üçlü savunma katmanıdır. Biri hatalı yapılandırılsa bile diğerleri korur. Veritabanını asla doğrudan internete açma.
04

Rol ve Yetki Yönetimi

Hazır Rol (Predefined)Kullanım
pg_read_all_dataTüm tablolarda SELECT (PG14+) — raporlama
pg_write_all_dataTüm tablolarda INSERT/UPDATE/DELETE (PG14+)
pg_monitorİzleme araçları — superuser gerekmez
pg_signal_backendSorgu iptal / oturum sonlandırma
pg_checkpointCHECKPOINT çalıştırma (PG15+)
pg_maintainVACUUM, ANALYZE, REINDEX (PG17+)
Least Privilege + public Şeması
-- public şemasını kilitle (PG15+ CREATE varsayılan kapalı) REVOKE ALL ON SCHEMA public FROM PUBLIC; REVOKE ALL ON DATABASE app_db FROM PUBLIC; -- Grup rolü → kullanıcıya ata CREATE ROLE app_ro NOLOGIN; GRANT CONNECT ON DATABASE app_db TO app_ro; GRANT USAGE ON SCHEMA app TO app_ro; GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_ro; ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT ON TABLES TO app_ro; GRANT app_ro TO report_user;
Superuser Denetimi & SET ROLE
SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolbypassrls, rolcanlogin FROM pg_roles WHERE rolsuper OR rolcreaterole OR rolbypassrls; -- Geçici yetki yükseltme (NOINHERIT kullanıcı) SET ROLE dba_admin; -- işlemi yap RESET ROLE;
Row-Level Security (RLS)
ALTER TABLE orders ENABLE ROW LEVEL SECURITY; ALTER TABLE orders FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id')::int);
⚠ Dikkat: Tablo sahibi ve BYPASSRLS rolleri RLS'yi atlar. Sahip için FORCE ROW LEVEL SECURITY kullan; uygulama asla tablo sahibi rolüyle bağlanmamalı.
05

Denetim ve Loglama

ParametreDeğerAçıklama
log_connectionsonBaşarılı/başarısız bağlantıları logla
log_disconnectionsonOturum süresi ile çıkışları logla
log_statement'ddl''mod' = DDL + DML yazma işlemleri
log_min_duration_statement10001 sn üzeri yavaş sorgular (ms)
log_lock_waitsondeadlock_timeout aşan kilit beklemeleri
log_file_mode0600Log dosyalarını sadece sahibi okusun
log_parameter_max_length0Bind parametrelerini (hassas veri) gizle
Önerilen log_line_prefix
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' # %t zaman · %p PID · %l satır no · %u kullanıcı # %d veritabanı · %a uygulama · %h istemci IP
pgaudit — Detaylı Audit Trail
# postgresql.conf (restart gerekir) shared_preload_libraries = 'pgaudit' pgaudit.log = 'ddl, role, write' pgaudit.log_catalog = off pgaudit.log_relation = on pgaudit.log_parameter = off # hassas veri sızmasın pgaudit.role = 'auditor'
CREATE EXTENSION pgaudit; -- Object-level audit: hassas tablo CREATE ROLE auditor NOLOGIN; GRANT SELECT, UPDATE ON customers_pii TO auditor; -- Sadece belirli kullanıcı için ek audit ALTER ROLE contractor SET pgaudit.log = 'read, write';
Örnek Audit Log Satırı
AUDIT: SESSION,1,1,DDL,DROP TABLE,TABLE,public.orders, DROP TABLE orders;,<not logged>
⚠ Dikkat: log_statement = 'all' ve pgaudit.log = 'all' production'da disk/I/O patlamasına yol açar ve parolaları loglara yazabilir. Logları merkezi SIEM'e gönder.
06

Şifreleme

KatmanYöntem
Aktarımdaki verissl=on + sslmode=verify-full
Kolon seviyesipgcrypto (pgp_sym_encrypt)
Durağan veri (TDE)pg_tde (PG17 · Percona)
Disk seviyesiLUKS / dm-crypt / cloud KMS
Yedeklerpg_dump | gpg · pgBackRest cipher
pgcrypto — Kolon Şifreleme
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Simetrik şifreleme (bytea kolon) INSERT INTO customers (name, tckn_enc) VALUES ('Ayşe', pgp_sym_encrypt('12345678901', :'key')); SELECT pgp_sym_decrypt(tckn_enc, :'key') FROM customers; -- Uygulama parolası: bcrypt hash SELECT crypt('s3cret', gen_salt('bf', 12));
pg_tde — Transparent Data Encryption
shared_preload_libraries = 'pg_tde' CREATE EXTENSION pg_tde; -- key provider + principal key tanımla, sonra: CREATE TABLE cards (...) USING tde_heap;
Şifreli Backup
pg_dump -Fc app_db | gpg --encrypt \ --recipient [email protected] > app_db.dump.gpg gpg --decrypt app_db.dump.gpg | pg_restore -d app_db # pgBackRest: repo1-cipher-type=aes-256-cbc
Sertifika & İstemci Doğrulama
ALTER SYSTEM SET ssl_cert_file = 'server.crt'; ALTER SYSTEM SET ssl_key_file = 'server.key'; SELECT pg_reload_conf(); # İstemci: MITM'e karşı tam doğrulama psql "host=db.corp.com dbname=app_db user=app_user sslmode=verify-full sslrootcert=root.crt"
⚠ Dikkat: pgcrypto anahtarını SQL'e gömme — log_statement ile loglara düşebilir. sslmode=require sertifikayı doğrulamaz; verify-full kullan. Community PostgreSQL'de yerleşik TDE yoktur.
07

Extension Güvenliği

ExtensionAmaçRisk
pgauditAudit trailGÜVENLİ
pgcryptoKriptografik fonksiyonlarGÜVENLİ
pg_stat_statementsSorgu istatistikleriGÜVENLİ
postgres_fdw / dblinkUzak bağlantı — kimlik bilgisi sızıntısıDİKKAT
adminpack / file_fdwSunucu dosya sistemine erişimYÜKSEK
plpython3u / plperluUntrusted dil — OS komutu çalıştırırYÜKSEK
shared_preload_libraries Whitelist
# Sadece onaylı kütüphaneler — restart gerekir shared_preload_libraries = 'pg_stat_statements,pgaudit,passwordcheck' # Mevcut değer: SHOW shared_preload_libraries;
Kurulum & Fonksiyon Erişimi
-- Yetki kontrolü: extension'ı dedicated şemaya kur CREATE SCHEMA ext AUTHORIZATION postgres; CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA ext; -- Fonksiyonlar varsayılan olarak PUBLIC'e açıktır! REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA ext FROM PUBLIC; GRANT EXECUTE ON FUNCTION ext.pgp_sym_decrypt(bytea, text) TO app_secure; ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC; -- Kurulu extension envanteri SELECT e.extname, e.extversion, n.nspname AS schema, r.rolname AS owner FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace JOIN pg_roles r ON r.oid = e.extowner;
SECURITY DEFINER Fonksiyonlar
CREATE FUNCTION app.rotate_key() RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog, pg_temp -- zorunlu! AS $$ ... $$;
Trusted extensions (PG13+): trusted = true olan extension'lar, veritabanında CREATE yetkisi olan superuser olmayan kullanıcılarca kurulabilir. Daha sıkı kontrol için pgextwlist ile whitelist uygula.
⚠ Dikkat: Untrusted diller (*u) ve COPY ... PROGRAM superuser'a OS seviyesinde komut çalıştırma imkânı verir — bu yüzden superuser = OS kullanıcısı postgres demektir.
08

Güvenlik Kontrol Listesi

Go-Live Öncesi
Kontrol MaddesiÖncelik
pg_hba.conf — trust kaldırıldıpg_hba_file_rules WHERE auth_method='trust'Kritik
scram-sha-256 aktif, md5 hash kalmadıSHOW password_encryption;Kritik
SSL/TLS etkin, TLSv1.2+ zorunluSHOW ssl; · pg_stat_sslKritik
Superuser sayısı ≤ 2SELECT count(*) FROM pg_roles WHERE rolsuper;Kritik
public şeması kısıtlandı\dn+ publicÖnemli
pgaudit kurulu ve aktifSHOW pgaudit.log;Önemli
Parola politikası uygulandı (passwordcheck + VALID UNTIL)SHOW shared_preload_libraries;Önemli
Backup şifrelemesi aktifgpg / repo1-cipher-typeÖnemli
RLS kritik tablolarda etkinpg_class WHERE relrowsecurityÖnerilen
log_connections açıkSHOW log_connections;Önerilen
Kritikhemen düzelt Önemlibu sprint Önerilenplanla
Tek Sorguda Güvenlik Denetimi
-- dbaguide.com · security quick audit SELECT name, setting, CASE WHEN name = 'ssl' AND setting = 'on' THEN '✓' WHEN name = 'password_encryption' AND setting = 'scram-sha-256' THEN '✓' WHEN name IN ('log_connections', 'log_disconnections') AND setting = 'on' THEN '✓' WHEN name = 'shared_preload_libraries' AND setting LIKE '%pgaudit%' THEN '✓' WHEN name = 'listen_addresses' AND setting <> '*' THEN '✓' ELSE '✗ KONTROL ET' END AS status FROM pg_settings WHERE name IN ('ssl', 'password_encryption', 'log_connections', 'log_disconnections', 'shared_preload_libraries', 'listen_addresses'); -- RLS kapalı kritik tablolar SELECT relname FROM pg_class WHERE relkind = 'r' AND NOT relrowsecurity AND relnamespace = 'app'::regnamespace;
✓ İyi Pratik: Bu kontrolleri CI/CD veya cron ile haftalık çalıştır, sonuçları izleme sistemine gönder. Her major upgrade sonrası listeyi baştan uygula.