Governance
거버넌스
한국 엔터프라이즈 규제 환경을 전제로 설계했습니다 — 프롬프트 본문은 저장하지 않고, 개인정보는 게이트웨이를 떠나기 전에 마스킹하며, 부서·키 단위 예산으로 지출을 통제합니다.
ZDR — Zero Data Retention
게이트웨이는 프롬프트·응답 본문을 절대 저장하지 않습니다. 사용량 원장(usage ledger)에는 메타데이터만 기록됩니다:
ts·keyId·orgId·endpointmodel·provider·tierpromptTokens·completionTokens·costUsd·savedUsdcacheHit·latencyMs·status
내부 디버그 로깅도 같은 정책을 따릅니다 — content, messages, input, prompt 필드는 로그 직전에 "[ZDR]"로 치환됩니다. 옵저버빌리티 연동(Langfuse)도 메타데이터만 전송합니다.
PII 마스킹
키에 piiMasking이 켜져 있으면, 요청이 업스트림 프로바이더로 나가기 전에 아래 5종의 개인정보를 유형별 토큰으로 치환합니다.
| 유형 | 패턴 | 치환 토큰 |
|---|---|---|
| 주민등록번호 (RRN) | YYMMDD-NNNNNNN — 날짜 유효성 검사 포함 | [MASKED:RRN] |
| 신용카드 | 13–19자리 (공백/대시 허용), Luhn 체크섬 통과 시에만 | [MASKED:CARD] |
| 휴대전화 | 01[016789]-XXXX-XXXX, +82 국제 표기 포함 | [MASKED:PHONE] |
| 이메일 | 표준 이메일 형식 | [MASKED:EMAIL] |
| 여권번호 | M/S + 8자리 숫자 | [MASKED:PASSPORT] |
입력: 제 번호는 010-1234-5678이고 메일은 kim@acme.co.kr입니다
전송: 제 번호는 [MASKED:PHONE]이고 메일은 [MASKED:EMAIL]입니다- 마스킹 순서는 RRN → CARD → PHONE → EMAIL → PASSPORT로 고정되어 오탐(카드 번호 속 전화번호 모양 등)을 방지합니다.
- 키 단위 on/off — 키 레코드의
piiMasking플래그로 제어하고, 요청 단위로는celon.no_pii_mask로 끌 수 있습니다. - 마스킹된 개수는 응답 메타
pii_masked로 확인합니다. - 마스킹은 단방향입니다 — 게이트웨이는 원문 복원용 매핑을 보관하지 않습니다 (ZDR).
티어드 가드레일 스택
위 PII 마스킹은 가드레일 스택의 1단계입니다. 요청은 업스트림으로 나가기 전에 빠른 것부터 순서대로 아래 탐지기를 통과합니다 — 저렴한 정규식 단계가 대부분을 걸러내고, 비싼 단계는 필요할 때만 켭니다. 탐지기별 on/off는 키의 guardrails.detectors 정책으로 제어합니다 (API 레퍼런스 참조).
| 단계 | 탐지기 | 지연 | 내용 |
|---|---|---|---|
| 1 | 구조적 PII detectors.pii | sub-ms | 정규식 — 주민등록번호·카드(Luhn)·전화·이메일·여권 (위 표와 동일) |
| 2 | 시크릿 / 엔트로피 detectors.secrets | ~1–2ms | API 키·클라우드 토큰 패턴 + 고엔트로피 문자열 (유출 크리덴셜) |
| 3 | Presidio NER detectors.presidio | 외부 호출 | 비정형 PII(이름·주소·조직) — 외부 Presidio 인스턴스, PRESIDIO_URL 설정 시에만 활성화 |
| 4 | 프롬프트 인젝션 휴리스틱 detectors.injection | sub-ms | jailbreak·명령 재정의 패턴 스크리닝 — Prompt Guard 2 연동 포인트 |
적용 모드 3종
무엇을 탐지할지와 별개로, 탐지 결과를 어떻게 처리할지는 키의 guardrails.mode로 정합니다.
| 모드 | 이름 | 동작 |
|---|---|---|
block | Validation | 위반 발견 시 요청을 즉시 거부합니다 — 본문 대신 위반 카테고리 요약만 반환됩니다. |
mask | Mutation | 탐지된 구간을 [MASKED:*] 토큰으로 자동 마스킹한 뒤 업스트림으로 전달합니다 (단방향, 복원 불가). |
shadow | Shadow | 요청은 그대로 통과시키고 탐지 결과만 Audit Trail에 기록(감사만)합니다 — 정책 도입 전 드라이런에 적합합니다. |
어느 모드든 요청별 결과는 응답 메타 guardrails.findings와 x-celon-guardrail-findings 헤더로 확인합니다 — 건수와 카테고리만 담기며 원문은 담기지 않습니다 (ZDR).
스트리밍 출력 가드레일
키에 guardrails.streamOutput이 켜져 있으면 모델의 출력도 검사합니다 — SSE 청크를 슬라이딩 버퍼에 모아 경계에 걸친 패턴까지 증분 검증하므로, 토큰 단위로 쪼개진 주민등록번호나 시크릿도 놓치지 않습니다. 위반이 확인되면 스트림을 finish_reason: "content_filter"로 즉시 중단합니다.
Audit Trail
모든 가드레일 판정은 불변(append-only) 메타데이터 로그로 남습니다 — 모드, 카테고리별 탐지 건수, 차단 여부, 요청 id만 기록되고 프롬프트·응답 본문은 저장되지 않습니다 (ZDR). 조회는 GET /admin/audit로 합니다 (API 레퍼런스 참조).
BYOK — Bring Your Own Key
조직이 이미 보유한 업스트림 계약(OpenAI, Anthropic 등)을 그대로 쓸 수 있습니다. 키 레코드의 byokKeys에 프로바이더별 키를 등록하면, 해당 프로바이더 호출 시 플랫폼 공용 키 대신 조직의 키가 사용됩니다 — chat, embeddings, fusion 전부에 적용됩니다.
등록은 admin API로 합니다 (마스터 키 필요, 자세한 스키마는 API 레퍼런스 참조):
curl -X POST http://localhost:8787/admin/keys \
-H "Authorization: Bearer $CELON_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{
"orgId": "org_abc123",
"name": "prod-backend",
"piiMasking": true,
"zdr": true,
"byokKeys": {
"openai": "sk-proj-…",
"anthropic": "sk-ant-…"
}
}'예산 정책
예산은 UTC 달력 월 기준으로 집계되며, 조직과 키 두 단계로 겁니다. null은 무제한을 의미합니다.
| 범위 | 초과 시 동작 |
|---|---|
| 조직 예산 | 하드 캡 — 항상 402 (budget_exceeded)로 거부합니다. 키 정책과 무관하게 우선합니다. |
| 키 예산 | 키의 overBudgetBehavior를 따릅니다 — "reject"는 402로 거부, "downgrade"는 celon/auto 요청을 Tier 3로 강제해 저비용으로 계속 서비스합니다. |
downgrade는celon/auto에만 적용됩니다 — 특정 모델을 명시한 요청은 명시한 모델이 우선합니다.- 임베딩에는 다운그레이드 개념이 없습니다 — 예산 초과 시
402로만 거부됩니다.