← blog · 10 Eylül 2026

SaaS'ta Kimlik ve Yetkilendirme: Tek Oturum, Roller ve Kiracı Sınırları

Çok kiracılı bir SaaS üründe kimlik doğrulama, rol ve kiracı sınırı üç ayrı eksendir. Hangi kimlik modelini seçmeli, OIDC federasyonunda kiracı nasıl eşleşmeli, RBAC/ABAC/ReBAC arasında nasıl karar verilir ve kiracı sınırı neden yalnızca uygulama katmanına bırakılmamalı.

Kimlik doğrulama ile yetkilendirme aynı şey değil

Çok kiracılı bir SaaS ürününde en sık karışan iki kavram kimlik doğrulama (bu kullanıcı gerçekten kim) ve yetkilendirmedir (bu kullanıcı bu kiracının şu kaynağında ne yapabilir). Kimlik doğrulama çözüldüğünde iş bitmiş gibi görünür, çünkü kullanıcı artık oturum açmıştır ve arayüz sorunsuz çalışır. Asıl risk üçüncü bir eksende saklıdır: kiracı sınırı. Bir kullanıcının rolü doğru olsa bile, o rol başka bir kiracının verisine erişim izni veriyorsa sistem güvenli değildir. Bu üç eksenin (kimlik, rol, kiracı) birbirinden bağımsız ama birlikte doğrulanması gerekir; birini çözüp diğer ikisini varsayım olarak bırakmak SaaS mimarisinde en sık görülen açığın kaynağıdır.

Kimlik: kendi kullanıcı tablonuz mu, harici sağlayıcı mı

Küçük ölçekte kendi kullanıcı tablonuzu (e-posta, şifre hash'i, oturum) yönetmek makul bir başlangıçtır. Ürün büyüdükçe, özellikle kurumsal müşteri kazanmaya başladığınızda, müşterilerin kendi kimlik sağlayıcılarıyla (Okta, Azure AD, Google Workspace) federe olma talebi gelir. Burada iki yol vardır:

Kendi kimlik yönetiminizi sürdürüp üstüne OIDC/SAML federasyonu eklemek, orta ölçekli SaaS ürünlerinin çoğunda doğru tercihtir. Kullanıcı tablonuz sizde kalır, harici sağlayıcı yalnızca "bu kişi doğrulandı" bilgisini taşır.

Kimlik yönetimini tamamen dışarıya (Auth0, Keycloak, Zitadel gibi bir kimlik sunucusuna) devretmek, çok sayıda kurumsal müşteriniz ve karmaşık federasyon gereksinimleriniz varsa zaman kazandırır. Bedeli, kimlik akışlarındaki her özel davranış için sağlayıcının esneklik sınırlarına çarpmanızdır.

Hangi yolu seçerseniz seçin, kimlik sağlayıcısının döndürdüğü bilgi yalnızca "kim" sorusuna cevap verir. "Hangi kiracıda" ve "o kiracıda ne yapabilir" sorularının cevabı sizin sisteminizde, sağlayıcının dışında tutulmalıdır. Kimlik sağlayıcısına rol ve kiracı bilgisini yazmak, sağlayıcı değiştiğinde ya da birden fazla sağlayıcı desteklemeniz gerektiğinde sizi kilitler.

Tek oturumla girerken kiracı eşleşmesi

OIDC ile federasyon kurarken en kritik karar, gelen kullanıcının hangi kiracıya ait olduğunu nasıl belirleyeceğinizdir. Üç yaygın desen var:

Kiracı başına ayrı OIDC istemcisi: her kiracının kendi client_id'si ve geri dönüş adresi vardır, kiracı bilgisi giriş akışının başında bellidir. Kurumsal müşteri sayısı sınırlıysa en temiz çözümdür.

Tek istemci, e-posta alan adı eşleşmesi: kullanıcı giriş yaptıktan sonra e-posta alan adına bakıp hangi kiracıya ait olduğuna karar verirsiniz. Ölçeklenmesi kolaydır ama bir tuzağı vardır: aynı alan adını paylaşan iki farklı organizasyon (örneğin bir danışmanlık şirketinin müşterileri) yanlışlıkla aynı kiracıya düşebilir.

Davetle katılım: kullanıcı önce bir kiracıya davet edilir, kimlik doğrulama bu davetin üzerine biner. Kiracı ataması asla otomatik alan adı eşleşmesine bırakılmaz. Güvenlik açısından en sağlam yöntem budur, ama kullanıcı deneyimi ek bir adım gerektirir.

Otomatik hesap oluşturma (just-in-time provisioning) açıkken, e-posta alan adı doğrulanmadan kiracı ataması yapmak ciddi bir sızıntı yoludur. Bir kullanıcı kendi e-posta sağlayıcısında istediği alan adını iddia edebiliyorsa (örneğin kurumsal olmayan bir e-posta ile), yanlış kiracıya sızabilir. JIT provisioning açıksa, kiracı eşlemesi mutlaka doğrulanmış bir alan adı listesine ya da açık bir davet kaydına dayanmalıdır.

Yetkilendirme modeli: RBAC, ABAC, ReBAC

Rol tabanlı erişim kontrolü (RBAC), "bu kullanıcı editördür, editörler şu işlemleri yapabilir" mantığıyla çalışır. Rollerin sayısı sınırlıysa ve izinler kaynak bağımsızsa yeterlidir, uygulaması da denetlemesi de kolaydır. Çoğu SaaS ürünü için doğru başlangıç noktası budur.

Öznitelik tabanlı erişim kontrolü (ABAC), kararı yalnızca role değil, kaynağın ve isteğin özniteliklerine dayandırır: "editör, yalnızca kendi departmanının belgelerini düzenleyebilir." RBAC'ın izin sayısını patlatan durumlarda (departman, proje, bölge gibi ek kısıtlar eklendiğinde) devreye girer.

İlişki tabanlı erişim kontrolü (ReBAC), izni nesneler arası ilişki grafiği üzerinden tanımlar: "bu kullanıcı bu belgeyi düzenleyebilir çünkü bu klasörün üyesidir ve bu klasör bu projeye bağlıdır." Google'ın Zanzibar makalesinden sonra popülerleşen bu model, iç içe geçmiş paylaşım hiyerarşileri (klasör, alt klasör, paylaşılan bağlantı) olan ürünlerde RBAC ve ABAC'ın ikisinin de yetersiz kaldığı yerde işe yarar.

Üçünü aynı anda kurmaya çalışmak gereksiz karmaşıklıktır. Ürününüzün izin modeli "kim, hangi role sahip" sorusuyla tarif edilebiliyorsa RBAC yeterlidir; "kim, hangi role sahip, hangi kaynak için" sorusu gerekiyorsa ABAC'a geçin; paylaşım zincirleri iç içe geçiyorsa ReBAC'ı düşünün. Sıralamayı atlayıp doğrudan ReBAC ile başlamak, çoğu ürün için hiç ihtiyaç duyulmayacak bir grafik sorgu katmanı bakımı anlamına gelir.

Kiracı sınırını nerede uygulamalısınız

Yetkilendirme kararını uygulama kodunda (middleware, controller öncesi kontrol) vermek yaygın ve gereklidir, ama tek katman olarak bırakılırsa kırılgandır: bir geliştiricinin unuttuğu tek bir WHERE tenant_id = ? koşulu, tüm kiracıların verisini karşı tarafa açar. Bu sınıf hatalar (yetkisiz doğrudan nesne referansı, IDOR) çok kiracılı sistemlerde en sık görülen veri sızıntısı nedenidir.

Bu yüzden kiracı sınırını uygulama katmanına ek olarak veritabanı katmanında da uygulamak savunma derinliği sağlar. PostgreSQL'de satır düzeyi güvenlik (row-level security) tam bunun için var:

ALTER TABLE documents ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON documents
    USING (tenant_id = current_setting('app.current_tenant')::uuid);

Uygulama, her istek başında bağlantı üzerinde SET app.current_tenant = '...' çalıştırır; bu ayardan sonra o bağlantı üzerinden çalışan hiçbir sorgu, geliştirici WHERE koşulunu unutsa bile başka kiracının satırlarını göremez. Şema başına kiracı (her kiracıya ayrı PostgreSQL şeması) yaklaşımı aynı izolasyonu farklı bir maliyetle sağlar: sızıntı riski daha düşüktür ama şema sayısı arttıkça migration ve bağlantı havuzu yönetimi ağırlaşır. Az sayıda büyük kiracınız varsa şema başına izolasyon, çok sayıda küçük kiracınız varsa satır düzeyi güvenlik ile paylaşılan şema genellikle daha sürdürülebilirdir.

Tuzaklar

İzinleri JWT içine gömüp önbelleklemek, rol değişikliğinin token süresi dolana kadar etkisiz kalmasına yol açar. Bir kullanıcının erişimi anında kesilmesi gerekiyorsa (işten çıkarma, güvenlik ihlali), token'a gömülü izinler yerine her istekte taze bir kontrol ya da kısa ömürlü token artı sunucu taraflı iptal listesi gerekir.

Süper admin ya da destek rolünün kiracı sınırını atlaması, çoğu yetkilendirme şemasında ayrı bir yol olarak yazılır ve bu yol genellikle audit edilmez. Destek ekibinin bir müşteri hesabına "impersonation" ile girmesi gerekiyorsa, bu işlem kendi audit kaydını üretmeli ve süresi kendiliğinden dolmalıdır; sınırsız süren bir "admin her şeyi görür" bypass'ı, bir gün destek arayüzünün kendisi ele geçirildiğinde tüm kiracıları aynı anda açığa çıkarır.

Rol kontrolünü yalnızca arayüzde (belirli bir düğmeyi gizlemek) yapıp API'de tekrarlamamak, arayüzü atlayan herhangi bir istemcinin (doğrudan API çağrısı, tarayıcı geliştirici araçları) yetkisiz işlem yapmasına izin verir. Yetkilendirme kararı her zaman sunucu tarafında, isteğin geldiği her uç noktada tekrar doğrulanmalıdır.

JIT provisioning ile e-posta alan adı eşleşmesini birlikte kullanıp alan adı doğrulamasını atlamak, yukarıda anlatıldığı gibi yanlış kiracıya sızmaya açık kapı bırakır.

Rol hiyerarşisini kod içinde if role == 'admin' or role == 'owner' gibi dağınık koşullarla kontrol etmek, yeni bir rol eklendiğinde tüm kod tabanının taranmasını gerektirir. İzin kontrolünü tek bir merkezi noktadan (bir yetkilendirme kütüphanesi veya servis) geçirmek, yeni rol eklemeyi tek dosyalık bir değişikliğe indirger.

Ne zaman bu kadarına gerek yok

Tek kiracılı bir ürün ya da kiracı sayısı çok az ve hepsi güvenilir dahili ekipler ise (örneğin bir şirketin kendi departmanları için kurduğu iç araç), satır düzeyi güvenlik ve ReBAC gibi katmanlar gereksiz karmaşıklık ekler. Basit rol kontrolü ve uygulama katmanında tek bir tutarlı sorgu yardımcısı (her sorguya otomatik tenant_id ekleyen bir ORM scope'u gibi) çoğu zaman yeterlidir. Karmaşıklığı, gerçekten çok kiracılı hale geldiğinizde ve kiracılar arasında güven sınırı oluştuğunda ekleyin; baştan itibaren en ağır modeli kurmak, hiç kullanılmayacak bir soyutlamanın bakımını üstlenmek anlamına gelir.