티스토리 뷰
Python으로 공부하는 OpenAI 30편 — FastAPI + OpenAI 멀티테넌트 SaaS, 고객별 데이터와 권한은 어떻게 나눠야 할까?
octo54 2026. 6. 11. 13:25Python으로 공부하는 OpenAI 30편 — FastAPI + OpenAI 멀티테넌트 SaaS, 고객별 데이터와 권한은 어떻게 나눠야 할까?
한 줄 요약
FastAPI + OpenAI 서비스를 여러 고객이 함께 쓰는 SaaS로 키우려면, 제일 먼저 해야 할 일은 기능 추가가 아니라 고객별 데이터 경계, 프로젝트 분리, 서비스 계정, 키 권한, 저장 정책을 정하는 것입니다. OpenAI는 새 프로젝트에 Responses API를 권장하고, 프로젝트 단위 서비스 계정과 API 키 권한, 데이터 보존 제어, 데이터 레지던시 같은 운영 옵션을 제공합니다. 즉, 멀티테넌트 단계에서는 “한 앱에 다 태운다”보다 어디까지를 고객별로 분리할지가 훨씬 중요합니다. (OpenAI Developers)
왜 멀티테넌트가 되면 갑자기 어려워질까?
혼자 쓰는 MVP나 소규모 팀 도구일 때는 별문제가 안 보입니다.
그런데 고객이 둘, 셋, 다섯으로 늘어나기 시작하면 갑자기 이런 질문이 생깁니다.
- A 고객의 문서가 B 고객 검색 결과에 섞일 수 있나?
- 운영 키 하나로 모든 고객 요청을 다 보내도 되나?
- 어떤 고객은 저장을 싫어하고, 어떤 고객은 장기 저장이 필요하면?
- background 작업 결과가 어느 고객 데이터인지 어떻게 구분하지?
- 고객별 usage와 비용을 어떻게 따로 보지?
OpenAI 문서 기준으로 Responses API는 기본적으로 강한 멀티툴·멀티모달 인터페이스고, project 단위 service account는 프로젝트 범위 안에서만 쓸 수 있으며, 데이터 보존 제어도 조직·프로젝트 단위로 설정할 수 있습니다. 이 말은 곧 앱 설계도 고객 경계를 기준으로 다시 봐야 한다는 뜻입니다. (OpenAI Developers)
먼저 결론부터: 멀티테넌트에서는 이 5가지를 먼저 나눠야 합니다
제가 추천하는 우선순위는 이렇습니다.
- OpenAI 프로젝트 경계
- 서비스 계정과 키 권한
- 문서/벡터 스토어 경계
- 저장·보존 정책
- usage / cost / eval 경계
이 다섯 가지가 안 나뉘면,
기능은 멀쩡해 보여도 운영은 점점 불안해집니다.
1. 고객별 경계를 어디에 둘지 먼저 정해야 합니다
멀티테넌트 SaaS에서 제일 먼저 해야 할 질문은 이겁니다.
고객마다 OpenAI 프로젝트를 따로 쓸 것인가,
아니면 우리 서비스가 한 프로젝트 안에서 논리적으로만 나눌 것인가?
OpenAI Help Center 문서에 따르면 service account는 project scope만 가지며, 프로젝트 밖에서는 쓸 수 없습니다. 또 data retention controls도 조직 수준뿐 아니라 project level로 설정할 수 있습니다. 데이터 레지던시 역시 프로젝트 설정 옵션으로 설명됩니다. (OpenAI Help Center)
그래서 현실적인 기준은 보통 이렇습니다.
하나의 OpenAI 프로젝트로 묶어도 되는 경우
- 고객 수가 적고
- 문서/검색이 고객별로 엄격히 섞이지 않게 앱에서 통제 가능하고
- 데이터 보존 정책이 고객마다 크게 다르지 않고
- usage 분리가 앱 로그만으로도 충분한 경우
고객별 OpenAI 프로젝트 분리를 검토할 경우
- 고객마다 데이터 보존 요구사항이 다르고
- project 단위 usage/cost 추적이 필요하고
- 일부 고객은 ZDR/MAM/data residency 요구가 있고
- 문서 검색·파일 업로드·background 작업의 격리가 매우 중요한 경우
즉, 기술적으로 가능하냐보다 운영·계약·보안 요구가 다르냐가 기준이 됩니다. (OpenAI Help Center)
2. 서비스 계정은 사람 계정 대신 시스템 경계로 써야 합니다
이건 진짜 중요합니다.
OpenAI 프로젝트 문서에 따르면 service account는 시스템 접근을 위한 pseudo-user이고, 조직/프로젝트 owner만 만들 수 있으며, project scope에만 묶입니다. 기본적으로 해당 프로젝트 API 리소스에 read/write 권한을 갖지만, API key permissions에서 조정할 수 있습니다. (OpenAI Help Center)
즉, 멀티테넌트 SaaS에서는 이런 식이 훨씬 낫습니다.
- 개발자 개인 키로 운영 서버 돌리기 ❌
- prod 전체가 하나의 인간 계정 키에 묶이기 ❌
- 기능/환경 기준 서비스 계정 쓰기 ⭕
예를 들면:
- prod-api-service-account
- prod-worker-service-account
- staging-api-service-account
이렇게 나누면 좋습니다.
왜냐하면 사고가 나도 범위를 줄일 수 있고, 누가 무엇을 썼는지 추적도 쉬워지기 때문입니다. (OpenAI Help Center)
3. API 키 권한은 “일단 All”로 두고 끝내면 안 됩니다
OpenAI Help Center의 API key permissions 문서는 키 권한을 All, Restricted, Read Only로 설명하고, Restricted에서는 리소스/엔드포인트별 세부 권한을 줄 수 있다고 안내합니다. (OpenAI Help Center)
이게 왜 중요하냐면,
멀티테넌트 SaaS는 한 키가 너무 많은 걸 할수록 위험해지기 때문입니다.
예를 들어
- API 서버는 /responses 위주 권한
- 문서 관리 워커는 files/vector stores 관련 권한
- 관리용 배치 작업은 별도 키
- 읽기 전용 모니터링 툴은 read-only
이렇게 나누는 게 훨씬 건강합니다.
솔직히 초기엔 귀찮습니다.
근데 고객이 늘고 팀이 늘면,
“그냥 하나로 다 해”가 나중에 제일 비싸게 돌아옵니다.
4. 문서와 벡터 스토어는 고객 경계를 가장 먼저 타는 영역입니다
RAG가 붙은 서비스라면 이 부분은 특히 중요합니다.
OpenAI data controls 문서에 따르면 /v1/vector_stores와 /v1/files는 application state를 보존하며, files는 수동 삭제나 expires_after로 자동 삭제를 설정할 수 있습니다. 또 file search/vector store 같은 객체는 삭제하지 않으면 유지될 수 있습니다. (OpenAI Developers)
즉, 멀티테넌트 SaaS에서는 최소한 이 기준이 필요합니다.
꼭 나눠야 하는 것
- 고객별 vector store ID
- 고객별 file 업로드 레코드
- 고객별 source/citation 노출 범위
- 고객별 문서 삭제 정책
절대 피해야 하는 것
- 모든 고객 문서를 하나 vector store에 몰아넣고 앱 로직으로만 필터링
- source UI에서 고객 경계 확인 없이 filename 노출
- 삭제 요청이 왔는데 OpenAI 파일/벡터 객체를 같이 안 지우는 구조
이 단계부터는 RAG가 “검색 기능”이 아니라 데이터 경계 문제가 됩니다.
5. Responses 저장 정책은 고객 요구사항에 따라 다르게 봐야 합니다
이건 2년차 이후 꽤 자주 마주치는 질문입니다.
OpenAI data controls 문서에 따르면, 기본적으로 abuse monitoring logs는 최대 30일 보존될 수 있고, /v1/responses는 기본적으로 또는 store=true일 때 30일 application state retention이 있습니다. ZDR가 승인된 조직/프로젝트에서는 /v1/responses의 store가 항상 false로 처리됩니다. 또한 background mode는 polling을 위해 응답 데이터를 약 10분 정도 디스크에 저장합니다. (OpenAI Developers)
이 사실이 왜 중요하냐면,
고객마다 요구가 다를 수 있기 때문입니다.
예
- 일반 고객: 기본 보존 허용
- 민감 고객: store=false 선호
- 높은 규제 고객: ZDR/MAM 검토 필요
- 긴 작업 고객: background mode 사용 시 보존 특성 이해 필요
즉, “우리는 그냥 기본값 씁니다”가 아니라
고객 요구와 OpenAI 저장 동작을 함께 설명할 수 있어야 합니다. (OpenAI Developers)
6. Background mode는 멀티테넌트에서 더 조심해서 써야 합니다
OpenAI background mode 문서는 긴 작업을 비동기로 실행하고 polling으로 상태를 확인할 수 있게 해주며, roughly 10 minutes 동안 응답 데이터를 저장한다고 설명합니다. 또 ZDR와는 호환되지 않는다고 명시합니다. (OpenAI Developers)
이 말은 곧 이런 뜻입니다.
- 모든 고객에게 background mode를 똑같이 적용하면 안 될 수 있다
- 어떤 고객은 긴 리포트를 원하지만, 어떤 고객은 저장 특성 때문에 background를 꺼야 할 수 있다
- background 결과를 우리 DB와 어떻게 연결하는지도 고객 경계 기준으로 봐야 한다
그래서 추천 기준
- 고객 설정에 allow_background_mode 같은 정책 두기
- 긴 작업이 필요한 기능만 background로 분리
- 작업 레코드에는 tenant_id / project_id / policy를 함께 저장
- ZDR/MAM 요구 고객은 별도 경로 검토
이렇게 해야 운영이 덜 꼬입니다.
7. 데이터 레지던시와 규제 요구는 “나중에 오면 보자”가 잘 안 됩니다
OpenAI data controls 문서는 data residency controls가 project configuration option이라고 설명하고, 미국 외 리전에 대해서는 abuse monitoring controls와 ZDR amendment가 필요할 수 있다고 안내합니다. 또한 일부 region에는 추가 승인도 필요할 수 있습니다. (OpenAI Developers)
이건 왜 중요하냐면,
고객이 늘면 어느 순간 이런 질문이 오기 때문입니다.
- 데이터가 어디에 저장되나요?
- 우리 프로젝트만 별도 보존 정책을 줄 수 있나요?
- region을 분리할 수 있나요?
이 질문이 들어온 뒤에 구조를 바꾸려면 꽤 아픕니다.
그래서 2년차에는 최소한:
- tenant metadata에 residency/policy 필드 두기
- 고객별 OpenAI project 분리 가능성 열어두기
- runbook에 data controls 설명 추가하기
이 정도는 해두는 편이 좋습니다.
8. 멀티테넌트 SaaS에서 “플랫폼에 맡기기 vs 직접 구현”의 현실적인 기준
여기서 가장 많이 헷갈립니다.
플랫폼에 맡기기 좋은 것
- Responses 실행 인터페이스
- background 실행 엔진
- batch 처리 엔진
- flex 저비용 처리 경로
- project / service account / key permission
- 기본 데이터 보존 옵션
- file / vector object lifecycle 일부
우리 서비스가 직접 가져가야 하는 것
- tenant_id 매핑
- 고객별 플랜 정책
- 어떤 기능이 어떤 프로젝트/키를 쓸지 라우팅
- source/citation 노출 정책
- 고객별 삭제 요청 흐름
- audit log
- billing/usage 표시 방식
즉,
OpenAI 플랫폼은 실행과 보안 경계를 도와주고
우리 앱은 고객 비즈니스 경계를 책임진다
이렇게 보면 편합니다.
지금 바로 써볼 수 있는 “테넌트별 OpenAI 경로 선택” 예제 코드
아래 코드는 아주 단순하지만,
멀티테넌트 SaaS에서 고객별 정책에 따라 어떤 경로를 쓸지 결정하는 감각을 보여주기 좋습니다.
from dataclasses import dataclass
from typing import Literal
ProcessingMode = Literal["realtime", "background", "batch", "flex"]
@dataclass
class TenantPolicy:
tenant_id: str
openai_project: str
allow_background_mode: bool
allow_file_search: bool
requires_store_false: bool
priority: Literal["high", "normal", "low"]
def choose_processing_mode(
policy: TenantPolicy,
task_type: str,
estimated_runtime_seconds: int,
requires_immediate_result: bool,
) -> ProcessingMode:
if requires_immediate_result:
return "realtime"
if task_type in {"bulk_embedding", "nightly_summary", "large_backfill"}:
return "batch"
if estimated_runtime_seconds > 30 and policy.allow_background_mode:
return "background"
if policy.priority == "low":
return "flex"
return "realtime"
def build_response_options(policy: TenantPolicy) -> dict:
options = {
"project": policy.openai_project,
"store": not policy.requires_store_false,
}
return options
if __name__ == "__main__":
tenant = TenantPolicy(
tenant_id="acme-enterprise",
openai_project="proj_acme_prod",
allow_background_mode=False,
allow_file_search=True,
requires_store_false=True,
priority="high",
)
mode = choose_processing_mode(
policy=tenant,
task_type="long_report",
estimated_runtime_seconds=45,
requires_immediate_result=False,
)
options = build_response_options(tenant)
print("selected_mode:", mode)
print("response_options:", options)
실행 방법
python tenant_routing.py
예상 결과
selected_mode: realtime
response_options: {'project': 'proj_acme_prod', 'store': False}
이 코드가 좋은 이유는,
멀티테넌트 정책을 감으로 처리하지 않고 tenant policy로 명시하게 해준다는 점입니다.
멀티테넌트 SaaS 체크리스트
고객 경계
- tenant_id가 모든 핵심 로그/작업/문서에 붙는가
- 고객별 vector store를 분리하는가
- source 노출이 고객 경계를 넘지 않는가
권한
- 서비스 계정을 쓰는가
- 키 권한이 Restricted/Read Only로 나뉘는가
- prod와 staging 키가 섞이지 않는가
보존 정책
- store 정책을 고객 요구사항에 맞게 조정 가능한가
- background mode 저장 특성을 이해하고 쓰는가
- 삭제 요청 시 files/vector store까지 정리되는가
운영
- 고객별 usage/cost를 나눠 볼 수 있는가
- 고객별 eval 또는 최소 대표 사례가 있는가
- runbook에 data controls / residency 설명이 있는가
FAQ
Q. 고객마다 OpenAI 프로젝트를 무조건 따로 써야 하나요?
무조건은 아닙니다.
고객 수가 적고 보존 정책, usage 추적, 문서 경계 요구가 비슷하면 하나의 프로젝트 안에서 앱 레벨로 나눌 수도 있습니다. 하지만 data controls, residency, usage 분리 요구가 커질수록 고객별 또는 고객군별 프로젝트 분리를 검토할 가치가 커집니다. (OpenAI Help Center)
Q. background mode는 멀티테넌트에서 그냥 공통으로 켜도 되나요?
권장하지 않습니다. background mode는 긴 작업에 유용하지만 polling을 위해 응답 데이터를 약 10분 저장하고, ZDR와도 호환되지 않습니다. 고객 정책에 따라 켜고 끄는 편이 더 안전합니다. (OpenAI Developers)
Q. service account와 개인 키의 가장 큰 차이는 뭔가요?
service account는 사람 계정이 아니라 시스템용 pseudo-user이고 project scope에만 묶입니다. 운영 서버나 worker에는 개인 키보다 service account가 훨씬 자연스럽습니다. (OpenAI Help Center)
Q. store=false만 쓰면 데이터 보존 문제는 끝인가요?
그렇게 단순하지 않습니다. Responses는 기본적으로 30일 application state retention이 있고, ZDR 프로젝트에서는 store가 항상 false로 처리됩니다. 하지만 background mode, files, vector stores, third-party MCP 같은 항목은 별도 보존 특성이 있으니 기능별로 같이 봐야 합니다. (OpenAI Developers)
핵심 요약
- 멀티테넌트 SaaS에서는 기능보다 고객 경계, 프로젝트 경계, 키 권한, 보존 정책을 먼저 정해야 합니다. (OpenAI Help Center)
- service account는 project scope 시스템 계정이라 운영 서버/worker에 더 적합합니다. (OpenAI Help Center)
- API 키는 All보다 Restricted/Read Only 기준으로 나누는 편이 훨씬 안전합니다. (OpenAI Help Center)
- Responses 저장 정책, background mode 저장 특성, ZDR/MAM/data residency는 고객 요구와 함께 설명할 수 있어야 합니다. (OpenAI Developers)
- 플랫폼은 실행과 기본 보안 경계를 도와주고, 우리 서비스는 tenant policy와 UX를 책임지는 구조가 가장 현실적입니다. (OpenAI Developers)
출처
- OpenAI Responses migration guide — Responses API를 unified interface로 설명하고 built-in tools, stateful context, lower costs 등을 안내. (OpenAI Developers)
- OpenAI Background mode guide — 긴 작업을 비동기로 실행하고 polling할 수 있으며, roughly 10 minutes 저장 특성이 있다고 설명. (OpenAI Developers)
- OpenAI Prompt caching guide — 자동 동작, exact prefix match, 최대 latency/cost 절감 가능성을 설명. (OpenAI Developers)
- OpenAI Batch guide — 50% lower costs, higher rate limits, 24-hour turnaround, 최대 50,000 requests/200MB 설명. (OpenAI Developers)
- OpenAI Flex processing guide — lower costs 대신 slower response와 occasional unavailability, async/low-priority workloads 적합하다고 설명. (OpenAI Developers)
- OpenAI Data controls guide — abuse monitoring 30일, Responses 30일 application state retention, ZDR 시 store=false, project-level data controls and data residency 설명. (OpenAI Developers)
- OpenAI Help Center: Managing projects — service account는 pseudo-user이며 project scope, default read/write permissions 설명. (OpenAI Help Center)
- OpenAI Help Center: Assign API Key Permissions — All, Restricted, Read Only 권한 설명. (OpenAI Help Center)
Python, OpenAI, FastAPI, 멀티테넌트 SaaS, OpenAI Projects, service account, API key permissions, Responses API, Data controls, Zero Data Retention, data residency, File Search, Vector Store, AI 백엔드 운영, 주니어 개발자
'study > Python으로 시작하는 OpenAI 개발 입문' 카테고리의 다른 글
- Total
- Today
- Yesterday
- 웹개발
- node.js
- 딥러닝
- Express
- REACT
- SpringBoot
- SEO최적화
- CI/CD
- JWT
- JAX
- seo 최적화 10개
- fastapi
- 주니어개발자
- 백엔드개발
- NestJS
- Python
- Next.js
- Prisma
- 쿠버네티스
- 생성형AI
- PostgreSQL
- flax
- llm
- DevOps
- rag
- LangChain
- 개발블로그
- nextJS
- kotlin
- nodejs
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
