티스토리 뷰
장애가 났다. 응답이 갑자기 느려져 로그를 열어 prompt를 들여다본 순간, 사용자가 본인 확인을 위해 입력한 주민등록번호 뒷자리와 카드번호가 그대로 찍혀 있다. 모델 응답 로그에는 내부 시스템 프롬프트에 있던 DB 접속 정보까지 따라 나왔다. 디버깅을 위해 켜둔 평범한 로그 하나가, 그 순간부터 개인정보 유출 사고가 된다.
LLM을 서비스에 붙이는 일은 점점 쉬워지고 있다. 그러나 로그와 관측성(Observability) 설계는 일반 웹 애플리케이션 시절의 감각으로 접근하기 어렵다. 입력과 출력 자체가 자유 형식의 자연어이기 때문에, 어떤 데이터가 들어올지 사전에 정의할 수 없고, 어떤 데이터가 나갈지도 보장하기 어렵다. 이 글은 LLM 서비스를 운영할 때 로그에 절대로 그대로 남기면 안 되는 데이터 5가지와, 그 대안을 정리한다.
요약
LLM 애플리케이션의 로그는 일반 웹 로그와 달리 자유 형식의 민감 데이터가 무제한으로 흘러 들어갈 수 있다. 사용자 prompt, RAG로 가져온 내부 문서, 모델 출력, 시스템 프롬프트, 툴 호출 인자에는 PII, 비밀, 정책 정보가 섞이기 쉽다. 운영자는 "원문 보관 vs 메타데이터 보관"의 경계를 명확히 정의하고, 게이트웨이 계층에서 일관되게 마스킹·해시·토큰 카운트 기반 로깅을 적용해야 한다.
이 글이 필요한 사람
LLM이나 RAG 기능을 사내 서비스나 고객용 서비스에 붙이고 있고, 로그/관측성/감사 설계를 책임지는 백엔드 엔지니어, 플랫폼 엔지니어, 보안 담당자.
왜 지금 이 주제인가
OWASP는 2025년 LLM Top 10에서 **Sensitive Information Disclosure(LLM02)**를 가장 흔히 관측되는 취약점 중 하나로 꼽았다. 초기 배포에서 시스템 프롬프트에 자격 증명이나 비즈니스 로직이 박혀 있는 경우가 많고, 이것이 로그·트레이스·재현 데이터로 흘러나가는 사례가 반복되고 있다.
문제의 본질은 단순하다. 일반 API는 입력 스키마가 정해져 있어서 어떤 필드가 민감한지 사전에 알 수 있다. 반면 LLM은 사용자 입력이 자유 자연어이고, 모델 응답도 자유 자연어다. "사용자가 무엇을 입력할지" 그리고 "모델이 무엇을 답할지"를 예측할 수 없는 상태에서, 평범한 디버그 로그 한 줄이 GDPR·개인정보보호법·금융 규제 위반의 출발점이 된다.
여기에 RAG가 더해지면 더 까다로워진다. 사내 위키, 인사 문서, 계약서를 벡터화해 검색하고, 그 결과를 prompt에 붙여 모델에 보낸다. 이 단계의 "retrieved context"를 그대로 로그에 남기면, 권한이 없는 운영자가 인사 평가나 고객 계약 내용을 들여다보게 되는 구조가 만들어진다.
로그에 그대로 남기면 안 되는 5가지 데이터
1. 사용자 원문 prompt
가장 자주 놓치는 항목이다. 디버깅을 위해 사용자 입력을 통째로 INFO 레벨로 남기는 패턴이 많다. 그러나 사용자는 "내 카드번호 1234-... 결제 내역 확인해줘"처럼 PII와 결제 정보를 prompt에 그대로 넣는다. 자유 입력이라는 점이 핵심이다. 어떤 필드가 위험한지 미리 정의할 수 없다.
대안:
- 원문은 짧은 TTL(예: 24시간)로 별도 저장소에 분리 저장하고, 일반 애플리케이션 로그에는 해시값과 토큰 수, 분류 결과(예: contains_pii=true)만 남긴다.
- 디버깅이 필요한 prompt는 PII 검출/마스킹 파이프라인을 통과한 redacted 버전을 사용한다. 구조화 PII(주민번호, 카드번호, 이메일)는 정규식과 체크섬으로 1차 차단하고, 이름·주소처럼 자유 형식은 NER 모델로 마스킹한다.
2. RAG로 가져온 retrieved context
prompt에 붙인 검색 결과는 사용자가 본 적 없는 사내 문서일 수 있다. 로그에 그대로 남기면 두 가지 문제가 동시에 생긴다. 첫째, 로그 열람 권한이 문서 열람 권한과 분리되어 권한 경계가 무너진다. 둘째, 같은 문서가 여러 사용자 세션의 로그에 복제되면서 데이터 노출 표면이 커진다.
대안:
- retrieved chunk 본문 대신 문서 ID, 청크 ID, 권한 태그, 유사도 점수만 남긴다.
- 본문이 꼭 필요하면 검색 인덱스의 원본 권한 정책을 따르는 별도 안전 저장소에 보관하고, 로그에서는 참조 ID만 사용한다.
3. 시스템 프롬프트와 그 안의 자격 증명
시스템 프롬프트에는 종종 "다음 DB의 사용자 테이블을 조회할 수 있다", "API_KEY=..." 같은 운영 정보가 들어간다. 모델 호출 트레이스에 전체 prompt(system + user + tools)를 그대로 남기면, 로그가 곧 secret 저장소가 된다.
대안:
- 시스템 프롬프트는 버전 ID(prompt_version=v1.4.2)만 로그에 남기고, 원문은 별도 prompt registry에 보관한다.
- 자격 증명은 시스템 프롬프트에 넣지 않고, 런타임에 IAM Role·Managed Identity·Secret Manager로 주입한다. 로그에는 사용된 ARN이나 Service Principal ID만 남긴다.
4. 모델 출력 원문
모델 응답도 자유 자연어이므로 PII가 그대로 흘러나올 수 있다. 특히 RAG 응답에는 검색된 사내 문서 내용이 인용 형태로 따라 나오기 쉽다. 출력 로깅을 켜둔 채로 운영하면 입력보다 출력에서 더 많은 민감 데이터가 새어 나가는 경우가 적지 않다.
대안:
- 출력도 DLP/PII 필터를 통과한 redacted 버전으로 로그에 남긴다.
- 원문 출력이 필요하면 평가(eval)·재현 용도로 짧은 TTL과 강한 접근 제어를 둔 별도 저장소에 격리한다.
- "어떤 redaction 규칙이 발동했는가"를 함께 남겨서 사후 감사를 가능하게 한다.
5. 툴 호출 인자
Agent가 외부 도구를 호출할 때, 인자 안에 자격 증명·결제 정보·고객 식별자가 들어간다. tool call trace를 그대로 남기면 데이터베이스 쿼리, 결제 API 호출, 이메일 발송 본문이 모두 평문 로그가 된다. Prompt Injection 사고 분석에는 도움이 되지만, 그 자체로 새로운 데이터 노출 표면이 된다.
대안:
- 인자 중 식별자(예: user_id)는 그대로, 자유 텍스트(예: email body, query string)는 마스킹하거나 길이/해시만 남긴다.
- 결제·계약·삭제처럼 부작용이 큰 호출은 별도 감사 로그(audit log)로 분리하고, 일반 애플리케이션 로그에서 제외한다.
로그에 반드시 남겨야 하는 메타데이터
원문을 잘라낸 만큼, 사후 추적이 가능하도록 메타데이터는 더 풍부하게 남긴다. NIST AI RMF의 Manage 함수는 LLM 파이프라인 로그가 사고 대응과 위험 재평가에 충분한 맥락을 갖춰야 한다고 권고한다. 최소한 다음 필드를 갖추는 것이 안전하다.
- request_id, session_id, user_id(가명 처리)
- model_name, model_version
- prompt_version, policy_version
- redaction_action(어떤 규칙이 적용되었는지)
- input_tokens, output_tokens, latency_ms
- tool_calls[].name, tool_calls[].status
- retrieval[].doc_id, retrieval[].score
- safety_filter_triggered, content_classification
이렇게 남기면 원문 없이도 "어떤 사용자가, 어떤 정책 버전으로, 어떤 모델에 요청을 보냈고, 어떤 도구가 어떤 결과로 끝났는지"가 재구성된다.
AWS / Azure 관점
LLM 게이트웨이 계층에서 일관되게 마스킹과 정책 적용을 하는 패턴이 권장된다. 클라우드별로 운영자가 활용할 수 있는 1차 도구는 다음과 같다.
AWS:
- Amazon Bedrock Guardrails: 입력·출력 단계에서 PII 마스킹과 거부 정책을 적용한다. 어떤 PII 카테고리(이메일, 신용카드, 이름 등)에서 어떤 액션(BLOCK·ANONYMIZE)이 발동했는지가 응답 메타데이터에 남는다.
- Amazon Macie: S3에 쌓이는 prompt/응답 로그에서 PII 노출을 사후 탐지하는 안전망으로 둔다.
- CloudWatch Logs / OpenSearch: 원문 로그 그룹은 KMS 고객 관리 키, 짧은 보존 기간, IAM 분리, S3 Lifecycle로 격리한다.
Azure:
- Azure AI Content Safety의 PII detection을 게이트웨이에서 호출해 입력과 출력 모두에 마스킹을 적용한다.
- Microsoft Purview로 prompt/응답 저장소에 라벨과 DLP 정책을 적용해 부서 간 접근을 차단한다.
- Log Analytics / Sentinel에서는 민감 데이터가 흘러갔는지 사후 탐지 룰을 운영한다.
공통 원칙은 같다. 애플리케이션 코드 곳곳에서 개별적으로 마스킹하지 말고, 모델 호출을 감싸는 게이트웨이 한 곳에서 마스킹·로깅·감사 기록을 표준화한다. 게이트웨이 없이 각 애플리케이션이 직접 모델을 호출하면 그림자 AI(shadow AI)가 늘어나고, 통제와 감사 자체가 불가능해진다.
실무 체크리스트
- 사용자 prompt 원문은 일반 애플리케이션 로그에 남기지 않는다. 별도 저장소에 짧은 TTL과 강한 접근 제어로 격리한다.
- 모든 모델 호출은 게이트웨이를 거치도록 강제하고, 마스킹 규칙은 게이트웨이에서 단일 정책으로 관리한다.
- 입력과 출력 양쪽에 PII/Secret 탐지를 적용한다. 출력 누락이 더 흔하다.
- RAG retrieved chunk는 문서 ID와 권한 태그만 로그에 남기고 본문은 별도 저장소를 둔다.
- 시스템 프롬프트는 prompt registry에 저장하고 로그에는 버전 ID만 남긴다. 자격 증명은 시스템 프롬프트에 넣지 않는다.
- 부작용이 있는 tool call(결제, 삭제, 외부 전송)은 audit log로 분리하고 보존 기간·접근 권한을 별도로 둔다.
- 로그 저장소에 KMS·CMK 기반 암호화와 IAM 최소 권한, S3/Blob Lifecycle, 보존 기간 정책을 적용한다.
- 사고 발생 시 재현이 가능하도록 메타데이터(model_version, prompt_version, policy_version, redaction_action)를 표준 스키마로 남긴다.
흔한 실수
- INFO 레벨에 prompt 통째로 남기기: 디버깅 의도로 시작했다가 그대로 운영에 살아남는다. 처음부터 redacted 필드와 원문 필드를 분리한 스키마로 시작한다.
- 마스킹을 애플리케이션마다 따로 구현: 정책이 어긋나고, 새 서비스에서 빠진다. 게이트웨이에서 강제한다.
- 출력은 마스킹하지 않음: 입력만 통제하면 충분하다고 착각하는 경우가 많다. 출력에서 더 많이 새어 나간다.
- RAG 본문을 trace에 그대로 첨부: LangSmith, Langfuse, Arize 같은 trace 도구에 chunk 원문이 그대로 올라가면, 그 도구의 권한 모델이 곧 사내 문서 권한 모델이 된다.
- 자격 증명을 시스템 프롬프트에 박기: 한 번 박힌 키는 모든 trace, 캐시, 평가 데이터셋에 복제된다. 회수 비용이 크다.
- 보존 기간이 너무 김: 디버깅 목적이라면 며칠이면 충분하다. 90일·1년짜리 prompt 로그는 거의 항상 사고 표면이다.
마무리
LLM 로그 설계는 보안 부서가 뒤늦게 막아주는 영역이 아니라, 서비스를 처음 만들 때 게이트웨이와 스키마 수준에서 결정해야 하는 영역이다. "원문은 남기지 않는다, 메타데이터는 풍부하게 남긴다, 마스킹은 한곳에서 한다." 이 세 원칙만 지켜도, 평범한 디버그 로그가 사고가 되는 가장 흔한 경로는 차단된다.
이 글이 유용했다면 다음 편도 확인해보세요.
다음 글: RAG 시스템의 권한 경계: 검색 결과가 사용자 권한을 넘어서면 안 되는 이유
References
- OWASP LLM Top 10 (2026)
- OWASP Top 10 for LLM Applications 2025 (PDF)
- How to Prevent PII Leaks in AI Systems — Gravitee
- Prevent Sensitive Data Leakage with LLMs — Kiteworks
- PII Redaction in LLM Pipelines: Gateway vs Application — TrueFoundry
- Advanced LLM security: Preventing secret leakage — Doppler
- Building An LLM Privacy Audit Framework — Protecto
'AI' 카테고리의 다른 글
| RAG 시스템의 권한 경계: 검색 결과가 사용자 권한을 넘어서면 안 되는 이유 (0) | 2026.06.25 |
|---|---|
| AI Agent 보안에서 Prompt Injection보다 먼저 봐야 할 것 (0) | 2026.06.23 |
| AI Agent가 데모에서는 잘 되는데 운영에서는 무너지는 이유: 런타임 계층이 빠졌을 때 (0) | 2026.06.20 |
| 데이터 레이크를 구축했는데 분석이 여전히 느리다면: Lakehouse가 해결하는 문제 (0) | 2026.06.19 |
| AIOps는 모니터링을 대체하지 않는다: 운영자가 알아야 할 진짜 역할 (0) | 2026.06.16 |
- Total
- Today
- Yesterday
