← Tüm yazılar

MİMARİ

RAG mimarisinde erişim kontrolü: kim neyi görebilir?

Kurum dokümanları bir RAG sistemine verildiğinde mevcut yetki modeli çoğu kurulumda indekse taşınmaz. Erişim kontrolünün hangi katmanda uygulanacağı, kimliğin sorguya nasıl taşındığı ve yetki değişikliğinin indekse ne zaman yansıdığı üzerine bir uygulama notu.

Bir kurumda dokümanlar hiçbir zaman düz bir yığın değildir. İnsan kaynakları klasörünü herkes açamaz, hukuk yazışmaları belirli bir listeye kapalıdır, finans tarafındaki tabloların okuyucusu sayılıdır. Bu ayrım yıllar içinde dosya sunucusunda, SharePoint kitaplığında, LDAP gruplarında, SSO rollerinde birikmiştir. Sonra bu dokümanlar bir RAG sistemine verilir. Sorulması gereken ilk soru şudur: kurumun mevcut yetki modeli bu geçişte nereye gitti?

Cevap çoğu ilk kurulumda "hiçbir yere" olur. Doküman parçalanır, gömme vektörü çıkarılır, tek bir indekse yazılır. Kaynak sistemdeki izin bilgisi bu hattın hiçbir adımında taşınmadığı için, indeksin kendisi izinsiz bir düzlemdir. Bu yazı, o düzlemin nasıl yeniden katmanlandırılacağına dair uygulama notudur.

Tek indeks yetki modelini nasıl düzleştirir

En yalın kurulumda benzerlik araması korpusun tamamı üzerinde çalışır. Sorgu vektörü ile en yakın k parça döner; bu parçaların hangi klasörden, hangi kitaplıktan, hangi erişim listesinden geldiği sorgu anında bilinmez. Sonuçlar bağlam olarak modele verilir ve model, kendisine verilen her şeyi cevaplanabilir kabul eder. Kullanıcının hiçbir zaman açamayacağı bir dosyanın içeriği, doğal dille yeniden yazılmış hâlde cevaba girer.

OWASP Gen AI Security Project bunu LLM08:2025 "Vector and Embedding Weaknesses" maddesi altında adlandırır: çok kiracılı veya çok sınıflı ortamlarda tek bir vektör veritabanının paylaşılması, kullanıcılar ya da sorgular arasında bağlam taşmasına (context leakage) yol açar. Pratikte bu bir model davranışı meselesi değil, klasik bir erişim kontrolü meselesidir; madde yaygın olarak OWASP Top 10’daki Broken Access Control sınıfıyla birlikte değerlendirilir. Aynı kaynağın ilk önerisi de nettir: ince taneli erişim kontrolleri ve izin farkındalığı olan vektör depoları, veri kümelerinin indekste mantıksal ve erişimsel olarak ayrılması.

OWASP’ın RAG Security Cheat Sheet’i bir adım daha ileri gider ve metadatanın doküman değil parça seviyesinde tutulmasını şart koşar: sınıflandırma, sahip, izinli roller, izinli kiracı bilgisi her vektör parçasının yanında durmalıdır. Sebep pratiktir. Doküman seviyesinde tutulan izin, parçalama adımından sonra ilişkisini kaybedebilir; geriye izinsiz parçalar kalır.

Filtrenin uygulandığı katman

Erişim kontrolü üç ayrı noktada uygulanabilir ve üçü aynı şey değildir.

  • İndeksleme anında ayrıştırma: farklı gizlilik seviyeleri ayrı indekslere, ayrı koleksiyonlara veya ayrı namespace’lere yazılır. En güçlü izolasyon budur, çünkü yetkisiz içerik aramanın çalıştığı kümede hiç bulunmaz. Bedeli esneklik: karma yetkili bir sorgu birden çok indekse dağıtılmak zorunda kalır ve kaynak sistemde izinler değiştiğinde yeniden yerleştirme gerekir.
  • Sorgu anında metadata filtresi: içerik tek indekste durur, filtre yüklemi arama ile birlikte çalışır. İçerik tek indekste kaldığı ve filtre motorun içinde çalıştığı için işletme maliyeti en düşük yaklaşım budur.
  • Sonuç sonrası filtreleme: arama filtresiz çalışır, dönen liste uygulama tarafında kırpılır. Bu, güvenlik açısından en zayıf konumdur ve aşağıdaki sebeple ölçülebilir bir sonuç kaybı da üretir.

Azure AI Search’in vectorFilterMode parametresi bu ayrımı resmî olarak adlandırır (bkz. Azure AI Search — Filters in vector search). preFilter modunda filtre yüklemi HNSW graf gezinmesi sırasında uygulanır ve dokümantasyonun ifadesiyle indekste varsa k sonucun döneceği garanti edilir. postFilter modunda her shard’da filtresiz gezinme yapılır, filtre sonra uygulanır; yüksek seçicilikte bu, geri çağırma oranını düşürür ve yanlış negatif üretir. strictPostFilter (önizleme) global top-k bulunduktan sonra filtreler ve seçici filtrelerde sıfır sonuç dönebilir. 15 Ekim 2023 dolayından sonra oluşturulan indekslerde varsayılan preFilter’dır.

Buradaki kritik çıkarım şudur: güvenlik filtreleri tipik olarak çok seçicidir. Bir kullanıcı çoğu zaman korpusun küçük bir yüzdesini görür. Post-filtering tam bu rejimde sessizce sonuç kaybettirir. Prefiltering’in bedeli ise gecikmedir ve Microsoft bunu aynı dokümanda sayılarla yayımlamıştır: 1M vektör ve 1536 boyutta, veri kümesinin %30’undan fazlası filtrelendiğinde prefilter yaklaşık %30 daha yavaş, %2’den azı filtrelendiğinde yaklaşık 7 kat daha yavaştır. 100.000 vektörde %0,1’in altındaki filtrelemede yaklaşık %50 daha yavaş. Bu, gecikme bütçesinin güvenlik modeliyle birlikte planlanması gerektiği anlamına gelir.

Metadata filtresi ile güvenlik kırpma

En yaygın somut kalıp, her parçaya izinli grup kimliklerinin filtrelenebilir bir koleksiyon olarak yazılmasıdır. Azure AI Search’in security filter deseninde (Azure AI Search — Security filters for trimming results) alan şu şekilde tanımlanır.

json
{
  "name": "group_ids",
  "type": "Collection(Edm.String)",
  "filterable": true,
  "retrievable": false
}

retrievable alanının false verilmesi bilinçlidir: yetki metadatası filtrelemede kullanılır, cevap gövdesinde geri dönmez. Sorgu anında filtre şu biçimi alır.

text
group_ids/any(g: search.in(g, 'grp-finance, grp-legal-readers'))

Aynı dokümantasyon, bunun yerine Id eq ’id1’ or Id eq ’id2’ biçiminde eşitlik zinciri kurmanın hata payı taşıdığını ve bakımının güç olduğunu, yüzlerce ya da binlerce değere çıkıldığında yanıt süresini saniyeler mertebesine taşıdığını, search.in ile ise saniyenin altında yanıt beklendiğini belirtir. Aynı kaynak sınırı da açıkça söyler: bu filtrede güvenlik ilkesi üzerinden bir kimlik doğrulama veya yetkilendirme yoktur, ilke yalnızca bir dizedir. Yani filtre, kimliğin doğru şekilde türetildiği varsayımı üzerine kuruludur; kimlik doğrulama işi hâlâ üstteki katmandadır.

İlişkisel tarafta aynı işi Postgres’in satır seviyesi güvenliği yapar. Supabase’in pgvector belgeleri (Supabase — RAG with Permissions), politikaların document_sections tablosuna uygulanmasını ve anlamsal aramanın bu politikalara uymaya devam etmesini anlatır.

sql
alter table document_sections enable row level security;

create policy "read permitted sections"
on document_sections for select
to authenticated
using (
  document_id in (
    select id from documents
    where owner_id = auth.uid()
  )
);

Kimlik REST tarafında auth.uid(), doğrudan Postgres bağlantısında current_setting() oturum değişkeni ile taşınır. Belgeler, Foreign Data Wrapper kullanıldığında satır seviyesi güvenliğin gecikmeye duyarlı olduğunu ve production öncesi sorgu planı analizinin şart olduğunu ayrıca not eder.

Motor içi filtreleme ile uygulama tarafında kırpma arasındaki tercih yalnızca hız meselesi değil. Azure dokümantasyonunun gerekçesi şu: motor içi filtreleme, iç içe grup çözümlemesi ve çok seviyeli ACL gezinmesi gibi özel kodları da ortadan kaldırır. O kod bir kez yazıldıktan sonra kurumun yetki modelinin ikinci bir kopyası hâline gelir ve iki kopya zamanla ayrışır.

Kimliğin sorguya taşınması

Filtre değerinin nereden geldiği, filtrenin kendisi kadar önemlidir. İstemcinin gönderdiği grup listesine güvenmek, filtreyi işlevsiz bırakır; kırpma, çağıranın kendi belirlediği bir değere dayanır. Doğru akış, kimliğin doğrulanmış bir token’dan türetilmesidir.

Azure AI Search’in native ACL yolunda (Azure AI Search — Document-level access control) kullanıcı token’ı x-ms-query-source-authorization başlığında taşınır. Servis token’dan kullanıcı, grup ve kapsam iddialarını çıkarır, indeksteki izin metadatasıyla karşılaştırır ve yalnızca yetkili dokümanları döndürür. Buna ek olarak istemci uygulamanın Search Index Data Reader rolüne sahip olması ayrıca kontrol edilir; iki aşamalı bir kontrol söz konusudur. Bu yetenekler önizleme REST API sürümü kapsamındadır; sürüm numarasını çağrıya yazmadan önce güncel Microsoft Learn dokümanından doğrulayın. Servisin dört resmî yaklaşımı vardır: API’den bağımsız çalışan güvenlik filtreleri (GA), POSIX benzeri ACL ile RBAC kapsamları, Microsoft Purview hassasiyet etiketleri ve SharePoint M365 ACL’leri (son üçü önizleme).

Google Vertex AI Search tarafında (Google Cloud — Vertex AI Search: data source access control) ACL’ler ingestion sırasında doküman metadatasındaki acl_info alanıyla verilir; yapı readers → principals → group_id veya user_id şeklindedir. Kimlik için Google Identity ya da Workforce Identity Federation (Microsoft Entra ID, Okta, Ping) desteklenir ve google.subject niteliği dış sağlayıcıdaki e-posta alanına eşlenmelidir. İki sınır tasarımı doğrudan etkiler: doküman başına 3000 reader, ve ACL yapılandırmasının data store oluşturulurken belirlenip sonradan değiştirilememesi.

Yetki değiştiğinde indekste ne olur

Bu, mimarinin en çok gözden kaçan noktasıdır. Kullanıcı bir gruptan çıkarıldığında kaynak sistemde etki anındadır; indekste değildir. Azure dokümantasyonu bunu açıkça yazar: önizleme API’sinin erişim veya izin kısıtlarındaki değişiklikleri tanıması öncesinde bir zamanlama gecikmesi oluşur. Kaynak sistemdeki izin değişiklikleri — Entra grup üyeliği, ADLS Gen2 ACL’leri, Purview etiket atamaları veya SharePoint ACL’leri — yalnızca bu metadata kaynağa özgü mekanizmayla, yani sonraki bir indexer çalışması, bir push API güncellemesi ya da Purview kaynaklı bir yenileme yoluyla indekse senkronlandıktan sonra arama sonuçlarına yansır.

SharePoint için ayrım daha da incedir: eşsiz izinlere sahip öğelerdeki değişiklikler her başarılı indexer çalışmasında artımlı yakalanır, ancak site, kitaplık, liste veya klasör kapsamından miras alınan değişiklikler açık bir yenileme gerektirir — options: ["permissions"] ile /resync veya /resetdocs. Yani bir kitaplık seviyesinde yapılan izin daraltması, indexer düzenli çalışıyor olsa bile kendiliğinden yansımayabilir.

Elasticsearch aynı problemi farklı bir mimariyle ele alır (Elasticsearch — Document level security ve connector access control sync). İki ayrı senkron türü vardır: içerik senkronu (search- ön ekli indekse) ve erişim kontrol senkronu (.search-acl-filter-<INDEX-NAME> ön ekli gizli indekse). İçerik dokümanlarındaki alan _allow_access_control’dür; kullanıcının erişim kontrol dokümanındaki en az bir öğe bu alandaki bir öğeyle eşleşirse erişim verilir, boş değer dokümanı herkese kapatır.

json
{
  "title": "Q3 tedarik notu",
  "body": "...",
  "_allow_access_control": [
    "group:finance-readers",
    "group:procurement"
  ]
}

İzin değişikliği için belgelenen yöntem, Elasticsearch API anahtarına expiration verilmesi ve erişim kontrol senkronunun tekrarlayan şekilde zamanlanmasıdır; kullanıcının izni değiştiğinde anahtarın güncellenmesi ya da yeniden oluşturulması gerekir. Genel DLS davranışında bir kullanıcının aynı indeks için birden fazla rolü varsa rol sorguları OR ile birleşir; tek bir rolün eşleşmesi dokümanı görünür kılar. DLS yazma API’lerine uygulanmaz ve her sorguda çalıştığı için küçük bir performans bedeli taşır.

Buradan çıkan tasarım kuralı basit: yenileme aralığı bir güvenlik parametresidir. Yetki değişikliğinin indekse yansıma süresi, sistemin sözleşmesinin parçası olarak yazılmalı ve gizlilik seviyesine göre seçilmelidir.

Parçalama sırasında metadatanın düşmesi

Çok kiracılı depolarda bölümleme stratejisi de bu tabloya girer. Qdrant, gömme modeli başına tek koleksiyon ve payload tabanlı bölümleme önerir (Qdrant — Multitenancy); v1.11.0’dan itibaren keyword indeksinde is_tenant: true parametresi bir kiracının vektörlerini birlikte konumlandırır, ölçekte hnsw_config içinde payload_m verilip global m sıfırlanarak kiracı başına bağımsız indeksleme kurulur. Aynı dokümantasyon, grup filtresi olmayan global sorguların tüm grupları taramak zorunda kaldığı için yavaşladığını not eder. Pinecone kiracı izolasyonu için namespace önerir ve metadata filtresinde $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $and, $or operatörlerini tanımlar; filtre ifadesinin en üst seviyesinde yalnızca $and ve $or kullanılabilir. Weaviate çok kiracılıkta her kiracıyı kendi shard’ında ve kendi vektör indeksiyle izole eder. Amazon Bedrock Knowledge Bases erişim kontrolünü metadata filtreleriyle kurar ve doküman başına 10 KB’a kadar özel metadata dosyasına izin verir.

Hangi depo seçilirse seçilsin, sık atlanan bir yapılandırma adımı var. Azure dokümantasyonu, skillset dokümanı parçalıyorsa (örneğin Text Split skill veya integrated vectorization) izin metadatası alanlarının indexer field mapping’lerinden index projection’lara taşınması gerektiğini belirtir. Purview etiketleri için ifade açıktır: bu projeksiyon olmadan parça seviyesindeki referanslar filtrelenmez. Parçalama adımı, doğru yapılandırılmadığında yetki metadatasını düşürür ve elde filtresiz parçalar kalır. Bu, dışarıdan görünmeyen bir yapılandırma hatasıdır: indeks çalışır, arama çalışır, yalnızca filtre boşa düşer.

Denetim izi ve üretim aşaması

Erişim kontrolünün ikinci yarısı, hangi sorgunun hangi dokümana değdiğinin kaydıdır. OWASP RAG Security Cheat Sheet bunu madde madde tanımlar: her retrieval, sorgulayan kullanıcı ya da ajanın kimliği ve dönen parçaların erişim kontrol metadatasıyla birlikte loglanmalı; iz tüm boru hattını kapsamalı — sorgunun alınması, dönen parçalar (doküman kimlikleri ve erişim metadatasıyla), modele verilen girdinin kurulması, üretilen çıktı ve tetiklenen araç çağrıları. Sık atlanan nokta cache’tir: cache hit’ler taze retrieval ile aynı ayrıntıda loglanmalıdır, aksi hâlde iz kopar. İndeks üzerindeki tüm ekleme, güncelleme ve silme işlemleri zaman damgası ve değiştiren kimliğiyle kayda geçmelidir. LLM08:2025’in dördüncü önerisi de aynı yöne bakar: retrieval etkinliğine dair ayrıntılı ve değiştirilemez loglar.

Son katman üretim aşamasıdır. Retrieval doğru filtrelenmiş olsa bile, çok adımlı bir akışta özet, ara not veya araç çıktısı yoluyla kapsam dışı içerik cevaba karışabilir. OWASP’ın bu aşama için normatif önerileri şunlar: tüm model çıktılarının döndürülmeden önce doğrulanması, PII ve sır niteliğindeki veriler için politika filtreleri ve redaksiyon, sorgulayan kullanıcının erişim seviyesine göre dinamik redaksiyon, ve kaynak atıf verisinin üretimden sonra değiştirilemeyecek şekilde imzalanması. Pratik karşılığı: cevabın dayandığı her parçanın kimliği taşınmalı ve son kontrol, cevabı üreten modelden bağımsız bir katmanda yapılmalıdır.

Özetleme yoluyla içerik taşması konusunda ölçülmüş kamuya açık bir çalışma bilinmiyor. Bu, ampirik bir bulgu olarak değil, tasarım varsayımı olarak ele alınmalı: modelin bağlamına giren her şey cevaba çıkabilir kabul edilir ve kontrol retrieval katmanında yapılır.

Toparlarsak: RAG’de erişim kontrolü yeni bir güvenlik disiplini değil, mevcut yetki modelinin yeni bir veri yoluna taşınmasıdır. İşin tamamı dört soruda toplanır. İzin metadatası parça seviyesinde mi duruyor? Filtre motorun içinde ve arama gezinmesi sırasında mı uygulanıyor? Kimlik doğrulanmış bir token’dan mı türetiliyor, yoksa istemciden mi geliyor? Ve kaynak sistemdeki bir izin değişikliğinin indekse yansıma süresi kaç dakika? Bu dördü yazılı olarak cevaplanabiliyorsa sistem denetlenebilir; cevaplanamıyorsa indeksin ne döndürdüğü sorusunun cevabı da yoktur.

Kaynaklar

  • OWASP Gen AI Security Project — LLM08:2025 Vector and Embedding Weaknesses
  • OWASP — RAG Security Cheat Sheet
  • Azure AI Search — Filters in vector search (vectorFilterMode, prefilter/postfilter gecikme ölçümleri)
  • Azure AI Search — Security filters for trimming results
  • Azure AI Search — Document-level access control (ACL, RBAC kapsamları, Purview etiketleri, SharePoint indexer)
  • Supabase — RAG with Permissions (pgvector ve row level security)
  • Google Cloud — Vertex AI Search: data source access control
  • Elasticsearch — Document level security ve connector access control sync
  • Qdrant — Multitenancy
  • Pinecone — Namespaces ve metadata filtering
  • Weaviate — Multi-tenancy
  • Amazon Bedrock Knowledge Bases — Metadata filtering

Diğer yazılar

Bir sisteminiz mi var, kurulacak mı?

Sunum gerekmez. 20 dakika. Sonrası size kalmış.