v0.9.266
kubectl 이 남긴 주석 하나가 Secret 값 전체를 데이터베이스와 화면으로 가져왔습니다
수집기는 Secret 의 data 를 절대 저장하지 않습니다 — internal/kube/client.go 의 Secret 분기는 type 과 (TLS 인 경우) 공개 인증서만 남기고 tls.key 조차 버립니다. 그런데 metadata.annotations 는 그대로 저장됐고, kubectl apply -f secret.yaml 로 만든 Secret 에는 kubectl 이 적용한 객체 전체를 kubectl.kubernetes.io/last-applied-configuration 주석에 그대로 써 둡니다 — data 의 base64 값을 포함해서. 즉 저장하지 않기로 한 바로 그 payload 가 다른 문으로 들어와 있었습니다. 워크로드에서는 같은 주석이 모든 컨테이너 env 값의 사본입니다.
① 주석 사본이 저장되고 그대로 응답에 실렸습니다
GET /admin/k8s/inventory 는 저장된 행을 가공 없이 돌려주고, Manifest Viewer 는 "masked": true 와 "Secret 값, token, env 민감값은 자동 마스킹됩니다" 를 함께 붙여 응답합니다 — 마스킹했다고 말하면서 Secret 값을 그 안에 담아 보냈습니다. 수집 경로는 셋(실시간 수집·에이전트 push·오프라인 스냅샷 import)이지만 전부 UpsertK8sInventory 로 모이므로 저장 시점에 떨어냈고, 이미 수집된 행이 다음 수집 전까지 응답에 실리지 않도록 읽기 시점(scanK8sInventory)에도 떨어냅니다.
② Manifest Viewer 는 주석 값을 키 이름으로만 판단했습니다
키가 민감해 보이지 않으면 값을 그대로 복사했는데, 주석 값은 자유 형식 텍스트입니다 — 토큰이 붙은 webhook URL·DSN·bearer 헤더가 일상적으로 들어갑니다. Pod 지문 경로(maskedStringMapToStringMap)는 이미 주석 값에 analyzer.MaskSensitive 를 돌리고 있었으므로 같은 처리로 맞췄습니다.
③ Stack 필드 드리프트가 env 값을 평문으로 보여줬습니다
리비전 diff(maskRevisionDiff)는 "설정 변경이 자격증명을 흘리지 않도록" env 를 *** 로 가리고 Manifest Viewer 도 env 값을 가리는데, 같은 값을 선언본과 대조해 보여주는 DetectStackFieldDrift 만 DB_PASSWORD=... 를 양쪽 다 그대로 렌더해 관리자 UI 로 보냈습니다. 이제 비교는 원본으로 하고(드리프트 자체는 그대로 검출) 출력만 가립니다 — 이름은 남기므로 어떤 변수가 다른지는 보이고, LOG_LEVEL 처럼 민감하지 않은 값은 계속 읽힙니다. 자격증명 판정은 이 패키지가 이미 쓰는 looksSensitiveEnv/looksSensitiveEnvValue(값이 scheme://user:pw@host 형태인 경우)를 그대로 씁니다.
초록불을 믿지 않았습니다
신규 테스트 5개를 고치기 전 코드에 되돌려 붙여 확인했습니다 — 넷이 각 결함을 정확히 지목하며 실패했습니다(주석 사본의 저장·읽기, drift 의 평문 env, Manifest Viewer 의 주석 값).
검증: go build ./... · go vet ./... · go test ./... 전부 통과(21 패키지).
- 이미지:
clustara:v0.9.266 - 배포 압축본:
clustara-v0.9.266.tar.gz