
LLM API 트래픽을 위한 투명한 PII 삭제 프록시입니다. 애플리케이션과 LLM 제공자(현재 Anthropic) 사이에 위치하여, 아웃바운드 시 민감 데이터를 가명 처리하고 인바운드 시 복원합니다. FastAPI + httpx로 구축되었습니다.
LLM API 트래픽을 위한 투명한 PII 익명화 프록시입니다. 애플리케이션과 LLM 제공자 사이에 위치하여, 나가는 요청의 민감한 데이터를 가명화하고 돌아오는 응답에서 복원합니다.
LLM은 실제 이름, 이메일, IP, 도메인을 절대 보지 못합니다. 대신 [email protected]과 같은 구조화된 가명으로만 작업합니다. 애플리케이션은 투명하게 원래 값을 다시 받습니다.
보안 운영, 침해 대응, 또는 실제 고객 데이터를 다루는 작업에 LLM을 사용할 때, 타사 API로 PII가 전송될 위험이 있습니다. 이 프록시는 다음을 통해 문제를 해결합니다:
# 1. 설정 파일 생성
cp config.json.example config.json
# config.json을 내부 도메인, 알려진 엔티티 등으로 편집
# 2. Docker로 실행
docker build -t llm-token-proxy .
docker run -p 8090:8080 -v ./config.json:/app/config.json llm-token-proxy
# 3. 애플리케이션을 프록시로 연결
export ANTHROPIC_BASE_URL=http://localhost:8090/session/my-session/
이것으로 끝입니다. 이제 Anthropic API 호출이 PII가 삭제된 상태로 프록시를 통과합니다.

일반적인 흐름: 애플리케이션 → Token Proxy (PII 가명화) → LLM API (가명만) → Token Proxy (원본 복원) → 애플리케이션
[email protected]에서 admin)가명은 세션 내에서 결정적입니다. 동일한 실제 값은 항상 동일한 가명에 매핑됩니다.
LLM이 보안 로그를 분석할 때 IP 주소의 호스팅 제공자와 지리적 위치는 중요합니다. 독일 Hetzner IP에서의 로그인과 미국 가정용 ISP에서의 로그인은 다른 이야기를 전달합니다. 문서 범위 IP(예: 198.51.100.x)로 단순 대체하면 이 맥락이 파괴됩니다.
선택적 MaxMind GeoLite2-ASN 데이터베이스를 사용하면 프록시가 실제 IP를 동일한 ASN 및 서브넷의 다른 IP로 대체합니다. LLM은 동일한 호스팅 제공자와 대략적인 지리적 위치를 가진 실제처럼 보이는 IP를 보지만, 실제 주소는 아닙니다.
10.99.99.x에 매핑 (보존할 ASN 맥락 없음)198.51.100.x (문서 범위)로 대체대체 IP는 세션별 솔트를 사용한 HMAC을 통해 결정적으로 선택되므로, 동일한 실제 IP는 세션 내에서 항상 동일한 대체 IP에 매핑되지만 다른 세션에서는 다른 매핑을 생성합니다.
프록시는 빈 config.json과 함께 제공됩니다. 내장 단어 목록이나 도메인별 가정이 없습니다. 포함된 config.json.example은 Microsoft Sentinel 및 Entra ID를 사용하는 보안 운영에 맞춰져 있습니다 (8,000개 이상의 KQL 테이블/컬럼 이름, Graph API 권한 용어, 보안 참조 도메인). 해당 사용 사례에 맞다면 필요한 부분을 복사하십시오. 다른 도메인(의료, 법률, 금융 등)에서 프록시를 사용하는 경우 빈 설정에서 시작하여 자체 목록을 구축하십시오.
config.json{
"internal_domains": ["yourcompany.com"],
"partner_domains": ["partnercorp.com"],
"internal_ip_ranges": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
"known_persons": ["John Smith"],
"known_orgs": ["YourCompany"],
"known_hostnames": ["DC01", "FS01"],
"ner_enabled": true,
"ner_skiplist": [],
"redaction_enabled": true
}
_internal_ 가명 획득)spacy + en_core_web_sm 필요)false이면 프록시가 순수 패스스루가 됨false이면 도메인이 수정 없이 통과 (이메일, IP, 이름은 여전히 가명화됨). 도메인 이름이 LLM에 중요한 맥락을 제공할 때 유용 (예: outlook.com과 protonmail.com 구분)하며 민감하지 않은 것으로 간주될 때 사용.재시작 없이 화이트리스트를 관리하고 가명화를 토글:
# 모든 화이트리스트 보기
curl http://localhost:8090/token-proxy/config/whitelist
# NER 스킵리스트에 용어 추가 (오탐지 감소)
curl -X POST http://localhost:8090/token-proxy/config/whitelist \
-H "Content-Type: application/json" \
-d '{"category": "ner_skiplist", "values": ["EvoSTS", "Hetzner"]}'
# 도메인을 허용 목록에 추가 (절대 가명화하지 않음)
curl -X POST http://localhost:8090/token-proxy/config/whitelist \
-H "Content-Type: application/json" \
-d '{"category": "domain_allowlist", "values": ["github.com"]}'
# 가명화 비활성화 (패스스루 모드)
curl -X POST http://localhost:8090/token-proxy/config/status \
-H "Content-Type: application/json" \
-d '{"redaction_enabled": false}'
화이트리스트 카테고리: ner_skiplist, domain_allowlist, known_persons, known_orgs, known_hostnames
프록시가 실시간으로 무엇을 하는지 검사:
# 활성 세션 목록
curl http://localhost:8090/token-proxy/sessions
# 세션의 가명 매핑 보기
curl http://localhost:8090/token-proxy/sessions/{session_id}/mappings
# 가명화 활동 로그 보기
curl http://localhost:8090/token-proxy/sessions/{session_id}/log
# 매핑 검색
curl http://localhost:8090/token-proxy/sessions/{session_id}/search?q=admin
# 캡처된 페이로드 보기 (LLM이 실제로 본 내용)
curl http://localhost:8090/token-proxy/sessions/{session_id}/payloads
# 세션의 토큰 사용량 (모든 요청의 입력/출력 토큰)
curl http://localhost:8090/token-proxy/sessions/{session_id}/usage
# 전체 통계 (모든 세션의 총 토큰 포함)
curl http://localhost:8090/token-proxy/stats
프록시는 전달하는 모든 요청에 대해 input_tokens와 output_tokens를 기록합니다. 비스트리밍(응답 usage 객체에서 읽음) 및 스트리밍(message_start 및 message_delta SSE 이벤트에서 파싱) 모두 지원합니다. 프록시가 애플리케이션과 LLM 사이에 있으므로, 각 클라이언트를 계측하지 않고도 프록시를 공유하는 모든 클라이언트의 소비를 측정할 수 있는 단일 체크포인트를 제공합니다.
curl http://localhost:8090/token-proxy/sessions/my-session/usage
# {
# "session_id": "my-session",
# "request_count": 3,
# "input_tokens": 1240,
# "output_tokens": 587
# }
curl http://localhost:8090/token-proxy/stats | jq .total_tokens
# { "input_tokens": 48213, "output_tokens": 19044 }
요청별 사용량은 /token-proxy/sessions/{session_id}/log의 usage_counts에도 포함됩니다. 원시 토큰 수만 추적되며, 가격 책정은 호출자에게 맡깁니다.
프록시는 SSE 스트리밍(stream: true)을 지원합니다. 가명은 SSE 청크 간에 분할될 수 있는 상황을 처리하는 테일 버퍼 접근 방식을 사용하여 실시간으로 복원됩니다.
프록시는 제공자 어댑터 패턴을 사용합니다. 현재 지원:
/v1/messages)추가 제공자(OpenAI, Google Gemini 등) 지원을 추가하는 방법은 CONTRIBUTING.md를 참조하십시오.
en_core_web_sm)은 영어 인물/조직 이름을 탐지합니다. 다른 언어의 이름은 설정의 known_persons/known_orgs에 추가하지 않으면 누락될 수 있습니다.admin [at] acme.com, 전화번호, 실제 주소)는 탐지되지 않습니다. 탐지 파이프라인은 구조화된 IT/보안 데이터에 맞춰져 있습니다./token-proxy/config/* 및 /token-proxy/sessions/* 엔드포인트에 인증이 없습니다. 프록시는 신뢰할 수 있는 내부 네트워크용으로 설계되었습니다. 이러한 엔드포인트를 신뢰할 수 없는 네트워크에 노출하지 마십시오.# 개발 의존성 설치
pip install -e ".[dev,ner]"
python -m spacy download en_core_web_sm
# 테스트 실행
pytest
# 린트
ruff check token_proxy/ tests/
Apache 2.0 — LICENSE 참조.
| Entity Type | Internal Example | External Example |
|---|
[email protected] | [email protected] | |
| Domain | domain-internal-001.com | domain-external-001.net |
| IP | 10.99.99.1 (RFC1918) | ASN 인식 대체 IP (아래 참조) |
| Person | person_internal_001 | person_external_001 |
| Org | org_internal_001 | org_external_001 |
| Hostname | host_001 | host_001 |
| Variable | Default | Purpose |
|---|
ANTHROPIC_API_BASE | https://api.anthropic.com | 업스트림 Anthropic API URL |
TOKEN_PROXY_CONFIG_PATH | /app/config.json | 설정 파일 경로 |
LOG_LEVEL | info | 로깅 수준 |
GEOIP_ASN_DB_PATH | /app/data/GeoLite2-ASN.mmdb | MaxMind GeoLite2-ASN 데이터베이스 (선택 사항) |