POWER BI ROW LEVEL SECURITY

Power BI Row Level Security konseptini anlatan sarı RLS kalkanı ve veri satırı filtreleme sembolü

Yaygın bir yanlış var: "RLS sadece tabloya filtre koymak demek." Bu cümle, Row-Level Security'yi anlamamış pek çok ekibin başına iş açıyor. RLS aslında bir filtre değil — Power BI semantic model üzerinde çalışan, DAX ile yazılmış bir role expression'dır. Bu ifade her sorgu çalıştığında değerlendirilir, kullanıcının kim olduğuna göre yeniden hesaplanır ve modeldeki tüm ilişkili tablolara çapraz filtre olarak yayılır. Dolayısıyla "bir kolona WHERE koymak" ile RLS arasındaki fark, basit bir SQL filtresi ile dinamik yetkilendirme katmanı arasındaki fark kadar büyüktür.

RLS Neden "Sadece Filtre" Değildir?

Bir Power BI raporunda kullanıcı bazlı erişim kontrolü kurmaya çalıştığınızda, ilk akla gelen yaklaşım genellikle şudur: "Slicer'a kullanıcı ismini koyalım, kendi verisini görsün." Bu güvenlik değil, görsel filtredir. URL'yi değiştiren, raporu Desktop'ta açan ya da DAX studio ile sorgulayan herhangi biri tüm veriyi görür. RLS ise farklıdır:

  • Semantic model katmanında çalışır — görsel katmanın altındadır
  • Sorgu motoruna (VertiPaq/DirectQuery) gömülür, bypass edilemez
  • Tek yönlü ilişkiler üzerinden cross-filter olarak yayılır
  • Hem import hem DirectQuery modellerde çalışır
  • Workspace Viewer rolüne sahip kullanıcılar bile kuralı atlatamaz

Yani RLS, "kullanıcı X şu satırları görür" cümlesinin DAX ile yazılmış, sorgu sırasında değerlendirilen ve modelin tüm ilişki grafiğine yayılan bir ifadesidir. Power BI üzerinde daha güçlü bir temele sahip olmak için Power BI eğitimi içeriğinden yararlanabilirsiniz.

DAX Role Expression: RLS'nin Kalbi

Bir rol oluşturduğunuzda, Power BI Desktop'ta "Manage Roles" ekranında her tablo için bir DAX ifadesi yazarsınız. Bu ifade boolean dönmek zorundadır — TRUE dönen satırlar görünür, FALSE dönenler gizlenir.

En basit haliyle statik bir rol şöyle yazılır:

  • [Region] = "Marmara" → Sadece Marmara bölgesini gören rol
  • [Department] IN {"Finance", "HR"} → İki departmanı birden gören rol
  • [Year] >= 2024 → Sadece son iki yılın verisi

Bu statik yaklaşımın sorunu açık: her bölge için ayrı bir rol oluşturmak, 40 bölgeli bir şirkette 40 rol yönetmek demektir. İşte burada dynamic RLS devreye girer.

Power BI RLS dynamic role yapısında UserAccess tablosu USERPRINCIPALNAME ve Sales satır filtresi akışı

Dynamic RLS: Tek Rol, Binlerce Kullanıcı

Dynamic RLS'in temel fikri şudur: rolün içine kullanıcının kimliğini sabit yazmak yerine, çalışma anında o kullanıcının kim olduğunu öğreniriz ve bu kimliği veriyle eşleştirmek için bir user-permission tablosu kullanırız.

Tipik mimari şu üç bileşenden oluşur:

  1. UserAccess tablosu: Kullanıcının e-postası ve erişebileceği bölge/departman/müşteri eşleşmesi
  2. İlişki: UserAccess[Region] ile Sales[Region] tablosu arasında tek yönlü ilişki
  3. DAX rolü: UserAccess tablosuna kullanıcıyı filtreleyen ifade

Rol ifadesi tek satırla biten bir şey değildir — modelin ilişki grafiği boyunca cross-filter yayılır. Yani UserAccess tablosuna yazdığınız bir filtre, oradan Region tablosuna, oradan Sales tablosuna otomatik akar. Bu da modelleme disiplini gerektirir: ilişkilerin yönü, kardinalitesi ve "ambiguous path" hataları RLS davranışını doğrudan etkiler.

USERPRINCIPALNAME Kapsamı

Dynamic RLS'in temel fonksiyonu USERPRINCIPALNAME()'dir. Bu fonksiyon, raporu çalıştıran kullanıcının Microsoft Entra ID (eski Azure AD) e-posta adresini döner. Tipik kullanım:

[UserEmail] = USERPRINCIPALNAME()

Burada kritik bir nokta var: bu fonksiyon yalnızca Power BI Service'te bir kullanıcı bağlamında çalıştığında doğru değer döner. Bilmesi gereken farklar:

  • Power BI Desktop'ta: "View as role" ile test ederken manuel e-posta girmeniz gerekir
  • Power BI Service'te: Otomatik olarak giriş yapan kullanıcının UPN'ini döner
  • Embedded senaryolarda: EffectiveIdentity parametresiyle override edilebilir
  • Service Principal'lar için: UPN dönmez — bu durumlar için CUSTOMDATA() düşünülmelidir
  • Büyük/küçük harf: UPN karşılaştırması case-insensitive değildir; UPPER() veya LOWER() ile normalize etmek best practice

Bir diğer fonksiyon olan USERNAME() on-premise senaryolarda DOMAIN\user formatı döner; bulut senaryolarında ise USERPRINCIPALNAME ile aynı sonucu verir. Karışıklığı önlemek için bulut tabanlı projelerde her zaman USERPRINCIPALNAME tercih edilmelidir.

Hiyerarşik RLS: Yönetici Kendi Ekibini Görsün

Gerçek hayat senaryoları nadiren "kullanıcı = bölge" kadar düzdür. Yönetici, kendi ekibini ve ekibinin altındaki tüm seviyeleri görmek ister. Bu, RLS'de parent-child hierarchy ile çözülür.

PATH(), PATHCONTAINS() ve LOOKUPVALUE() fonksiyonları burada birlikte kullanılır. Örneğin bir Employee tablosunda her çalışanın ManagerID'si varsa, PATH ile her çalışan için kök yöneticiye giden hiyerarşik yol üretilir. Sonra PATHCONTAINS ile o yolda raporu açan kişinin olup olmadığı kontrol edilir. Bu, ROW LEVEL'in nasıl ORGANIZATION LEVEL'a evrildiğinin klasik örneğidir.

RLS Test Etmek ve Yaygın Hatalar

RLS, "yazdım, herhalde çalışır" denilebilecek bir özellik değildir. Power BI Desktop'ın "View as Roles" özelliği ile her rol için manuel test yapılmalıdır. Service'te ise rolün üyelerini ayarladıktan sonra "Test as role" seçeneği vardır. Konfigürasyon adımları ve rol yönetim senaryoları için resmi dokümantasyona başvurmak yaygın tuzakları görmenize de yardımcı olur.

Yaygın hatalar şunlardır:

  • İlişkilerin both direction olması — RLS'i beklenmedik tablolara yayar
  • UserAccess tablosunun model dışından (ör. Excel) gelmesi ve refresh sırasında kırılması
  • USERPRINCIPALNAME'in Desktop'ta test edilirken e-posta yerine kullanıcı adı sanılması
  • Rolün workspace düzeyinde değil, semantic model düzeyinde atanması gerektiğinin unutulması
  • Object-level security (OLS) ile RLS'in karıştırılması — OLS sütun gizler, RLS satır filtreler
  • Aggregation tabloları kullanılan modellerde RLS'in agregat tablolara da yayılmasının atlanması
Üç farklı kullanıcının aynı satış tablosunda yalnızca kendi bölgesinin satırlarını gördüğü RLS karşılaştırma diyagramı

RLS Performansı: Sessiz Maliyet

DAX role expression, her sorguda değerlendirilir. Yani basit bir [Region] = "X" dahi her görsel için sorgu planına eklenir. Karmaşık dynamic RLS'lerde, özellikle PATH/PATHCONTAINS gibi text işlemlerinde performans düşüşü gözlemlenebilir.

Performansı korumak için:

  • UserAccess tablosunu mümkün olduğunca dar tutun (gereksiz sütun bulundurmayın)
  • İlişki kardinalitesini doğru ayarlayın — many-to-many ilişkiler RLS davranışını yavaşlatır
  • LOOKUPVALUE yerine ilişki + RELATED kullanmayı tercih edin
  • RLS'i test ederken DAX Studio ile sorgu sürelerini ölçün

Detaylı DAX yapılarını ve modelleme tekniklerini daha derinlemesine kavramak isteyenler, Power BI eğitimi kapsamındaki konuları inceleyebilir.

RLS Ne Değildir?

Kapatmadan önce bir kez daha vurgulamak gerekirse: RLS, kullanıcının hangi satırları göreceğini belirler. Hangi sütunları göreceğini değil (bu OLS'tir). Hangi raporu açabileceğini değil (bu workspace izinleridir). Hangi semantic model'a bağlanabileceğini değil (bu build izinleridir). Bu katmanlar birbirini tamamlar; biri diğerinin yerine geçmez. RLS'i "filtre" diye düşünmeyi bıraktığınız an, onu bir yetkilendirme katmanı olarak doğru tasarlamaya başlarsınız.