4.6 KiB
4.6 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label, target_audience, inspiration_url, archive_url
| title | source_type | status | related_branches | related_projects | tags | created | status_label | target_audience | inspiration_url | archive_url | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| blog-topic / logback-layer1-secret-masking-json-vs-pattern-2026-06-14 | blog-topic | raw |
|
|
|
2026-06-14 | ready-for-canonical | backend-engineer |
blog-topic: logback-layer1-secret-masking-json-vs-pattern-2026-06-14
Layer:
raw/blog-topics/— 글감 원석. canonicalwiki/blog정제 전.
Parent / 부모
- raw/branch-notes/feature-log-management-contract — Redaction Layer 1(DRIFT-2) 구현에서 파생.
트리거 / Trigger
"ERROR/WARN 로그에 token/password/Authorization 헤더를 **** 로 가린다"는 계약을 %replace(%msg){...} 한 줄로 끝내려다, 운영 포맷이 LogstashEncoder(JSON) 임을 깨달음. %replace 는 PatternLayout converter 인데 JSON encoder 는 PatternLayout 을 우회한다 → JSON 로그에는 마스킹이 안 걸린다. 정작 가려야 할 production(JSON) 경로가 무방비.
글감 / Topic seed
"Logback 에서 secret 마스킹을 제대로 하려면 — %replace 가 JSON 을 못 가리는 이유와 단일 정규식 SSOT 설계":
- 두 갈래 인코딩 경로: 사람이 읽는
PatternLayout(local/dev) vs 구조화LogstashEncoder(staging/prod).%replace는 전자에만 적용. - JSON 경로의 올바른 도구:
net.logstash.logback.mask.MaskingJsonGeneratorDecorator+ValueMasker— JSON 생성 시점에 모든 string value(message/MDC/stack trace)를 정규식으로 치환.<jsonGeneratorDecorator>로 encoder 에 장착. - pattern 경로:
MessageConverter를 상속한 custom converter(%maskedMsg)로 같은 정규식 적용. - 단일 SSOT: 두 경로가 같은
LogMaskingPatterns(컴파일된List<Pattern>+ capture-group replacement)를 공유 → profile/포맷 전환이 마스킹 대상을 바꾸지 못함(D10 "가독성 전환이 secret 노출로 이어지지 않게"). - 정규식 설계: keyword(group1)+separator(group2)+value(group3) 로 캡처 후
$1$2****치환 → 키는 남기고 값만 가림. 부정 문자클래스([^\s"',&}]+)로 catastrophic backtracking 회피. Authorization/Bearer 별도 룰. - 한계 명시: 정규식 기반은 obfuscated 인코딩(Base64URL blob, prefix 없는 토큰)을 놓칠 수 있음 → 1차 방어는 여전히 "logger 가 payload/body 인자를 안 받음(by construction)". 마스킹은 defence-in-depth.
핵심 주장 후보 / Claim candidates
%replace만으로 "로그 마스킹 했다"는 JSON 운영에서 거짓 안심이다 — encoder 가 PatternLayout 을 우회하면 무력.- 마스킹 정규식은 인코딩 경로마다 중복하지 말고 단일 Java SSOT 로 두고 decorator/converter 두 어댑터가 참조해야 한다 — 그래야 profile 전환이 보안 동작을 못 바꾼다.
- value 캡처 그룹 +
$n역참조 치환으로 "키는 보존, 값만 마스킹" → 진단 가능성과 보안의 균형.
관련 / Related
- raw/branch-notes/feature-log-management-contract
- 동반 면접 노트(드롭 메트릭 결정론 테스트 + 마스킹 Q): raw/interviews/deterministic-logback-asyncappender-drop-metric-test-2026-06-14
Outline seed
- PatternLayout
%replace가 JSON encoder 경로를 우회하는 문제를 설명한다. MaskingJsonGeneratorDecorator와 custom%maskedMsg가 같은 SSOT regex를 공유하게 한다.- regex masking의 한계와 logger signature의 by-construction 방어를 분리한다.
Canonical 전환 후보 / Canonical extraction candidates
wiki/projects/ca-tmpl/observability-log-metric-trace-runbook.md후보:- Logback JSON vs pattern masking Layer 1 글감.
- 필요한 추가 검증:
- 현재
LogMaskingPatterns, JSON decorator, pattern converter 구현 여부.
- 현재
Sources / 근거 후보
- raw/branch-notes/feature-log-management-contract
- raw/interviews/deterministic-logback-asyncappender-drop-metric-test-2026-06-14
미해결 / Unknown
- 아직 확인해야 할 사실: 현재 ca-tmpl 코드에 JSON masking decorator와 pattern converter가 존재하는지.
- 과장하면 안 되는 부분: regex masking이 모든 secret 형태를 잡는다고 쓰지 않는다.
Decision / 처리 결정
- 액션:
promote-to-canonical - 이유:
wiki/projects/ca-tmpl/observability-log-metric-trace-runbook.md에 Logback JSON/pattern masking 글감으로 반영한다. - 다음 단계: blogify 전 masking 구현 등급과 payload logging 금지 rule을 분리한다.