본문 바로가기
C.W.K.
Stream
Lesson 05 of 05 · published

다중 테넌트 격리

~20 min · ops, multi-tenant, security

Level 0Scout
0 XP0/41 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

위험 수준이 다른 세 가지 방식

1. 테넌트마다 컬렉션 하나

각 테넌트가 자기 Chroma 컬렉션이나 pgvector 테이블을 가져. 격리가 가장 강하지만 테넌트가 수천 개면 운영이 무거워질 수 있어.

2. 공유 컬렉션과 tenant_id 메타데이터

큰 컬렉션 하나를 쓰고 모든 청크에 metadata.tenant_id를 넣으며 모든 쿼리에 where={tenant_id}를 적용해. 저렴하고 수백만 테넌트까지 늘릴 수 있지만 필터 하나를 빠뜨리면 다른 테넌트의 데이터가 새어 나가. 엄격하게 테스트해야 해.

3. 테넌트마다 스키마 하나(pgvector)

Postgres 스키마로 테넌트의 이름 공간을 나눠. 연결 풀 하나를 공유하면서 메타데이터 방식보다 더 깔끔하게 격리할 수 있고, search_path로 쿼리 범위를 자동 지정할 수 있어.

유출을 막는 함수 계약

검색 함수를 tenant_id 매개변수를 반드시 요구하도록 감싸. 어떤 코드 경로에서도 tenant_id 없이 검색기를 호출할 수 없게 해야 해. 코드 검토가 놓칠 수 있는 실수를 형 검사기가 막게 하는 거야.

Code

테넌트 ID를 요구하는 검색 계약(파이썬 타입 힌트)·python
from typing import NewType

TenantId = NewType('TenantId', str)

def retrieve(question: str, tenant_id: TenantId, k: int = 5):
    return collection.query(
        query_embeddings=[embed(question)],
        n_results=k,
        where={'tenant_id': {'$eq': tenant_id}},
    )
pgvector에서 테넌트마다 스키마 나누기·sql
CREATE SCHEMA acme;
CREATE TABLE acme.chunks (LIKE public.chunks INCLUDING ALL);

-- request 별:
SET search_path = acme, public;
SELECT id, text FROM chunks ORDER BY embedding <=> $1 LIMIT 5;

External links

Exercise

규모에 맞춰 테넌트마다 컬렉션, 공유 컬렉션과 메타데이터, 테넌트마다 스키마 가운데 하나를 골라 구현해. 테넌트 사이 데이터 유출 테스트를 작성해 실행하고, 통과하면 격리가 작동하는 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.