Files
llm-wiki/raw/blog-topics/logback-layer1-secret-masking-json-vs-pattern-2026-06-14.md

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
feature-log-management-contract
ca-tmpl
blog-topic
ca-tmpl
logback
logstash-encoder
masking
security
observability
redaction
2026-06-14 ready-for-canonical backend-engineer

blog-topic: logback-layer1-secret-masking-json-vs-pattern-2026-06-14

Layer: raw/blog-topics/ — 글감 원석. canonical wiki/blog 정제 전.

Parent / 부모

트리거 / 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 설계":

  1. 두 갈래 인코딩 경로: 사람이 읽는 PatternLayout(local/dev) vs 구조화 LogstashEncoder(staging/prod). %replace 는 전자에만 적용.
  2. JSON 경로의 올바른 도구: net.logstash.logback.mask.MaskingJsonGeneratorDecorator + ValueMasker — JSON 생성 시점에 모든 string value(message/MDC/stack trace)를 정규식으로 치환. <jsonGeneratorDecorator> 로 encoder 에 장착.
  3. pattern 경로: MessageConverter 를 상속한 custom converter(%maskedMsg)로 같은 정규식 적용.
  4. 단일 SSOT: 두 경로가 같은 LogMaskingPatterns(컴파일된 List<Pattern> + capture-group replacement)를 공유 → profile/포맷 전환이 마스킹 대상을 바꾸지 못함(D10 "가독성 전환이 secret 노출로 이어지지 않게").
  5. 정규식 설계: keyword(group1)+separator(group2)+value(group3) 로 캡처 후 $1$2**** 치환 → 키는 남기고 값만 가림. 부정 문자클래스([^\s"',&}]+)로 catastrophic backtracking 회피. Authorization/Bearer 별도 룰.
  6. 한계 명시: 정규식 기반은 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 역참조 치환으로 "키는 보존, 값만 마스킹" → 진단 가능성과 보안의 균형.

Outline seed

  1. PatternLayout %replace가 JSON encoder 경로를 우회하는 문제를 설명한다.
  2. MaskingJsonGeneratorDecorator와 custom %maskedMsg가 같은 SSOT regex를 공유하게 한다.
  3. 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 / 근거 후보

미해결 / 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을 분리한다.