--- title: blog-topic / trivy-suppression-governance-static-gate source_type: blog-topic status: raw related_branches: [feature-dependency-vulnerability-management-contract] related_projects: [ca-tmpl] tags: [blog-topic, ca-tmpl, security, supply-chain, ci] created: 2026-06-20 status_label: ready-for-canonical target_audience: backend-engineer inspiration_url: archive_url: --- # blog-topic: trivy-suppression-governance-static-gate > Layer: `raw/blog-topics/` — 작업·트러블슈팅에서 나온 블로그 글감 원석. > `status_label`: `captured` ## Parent / 부모 - [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] — D5 를 구현하며 "suppression 거버넌스를 빌드 게이트로 강제"한 경험에서 도출. ## 트리거 / Trigger - 트리거 유형: `branch-work` - 트리거 날짜: 2026-06-20 - 트리거 연결 노트: [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] ## 글감 / Topic seed - 한 문장 요지: 취약점 스캐너의 suppression 파일(`.trivyignore.yaml`)은 그대로 두면 *만료일·사유 없는 영구 silent bypass* 가 되기 쉬운데, 이걸 100줄짜리 Gradle 정적 게이트 하나로 빌드 차원에서 강제할 수 있다. - 예상 제목 후보: - "`.trivyignore` 가 백도어가 되지 않게: Gradle 정적 게이트로 suppression 거버넌스 강제하기" - "보안 게이트의 게이트: suppression 에 만료일과 사유를 코드로 강제한 이야기" ## 핵심 주장 후보 / Claim candidates - 사실 후보: - Trivy 는 `expired_at` 이 없으면 suppression 을 **영구 유효**로 취급한다 — 근거 후보: [[raw/official-docs/trivy-filtering-suppression-policy]] C4. - "정책(policy)"과 "강제(enforcement)"는 분리된다: 정책 문서(`dependency-vulnerability-policy.md`)는 사람이 읽고, 강제는 `verifyTrivyignore` gate + CODEOWNERS 가 한다 — 근거 후보: [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] D5 §3. - 경험 후보: - line-based parser(YAML 라이브러리 없이, repo 의 `verifyEnvKeys` 스타일 답습)로 게이트를 만들고 6-케이스로 pass·fail 검증 — 근거 후보: 동 branch §진행 중 메모 2026-06-20. - `subprojects { check { dependsOn } }` 배선으로 `./gradlew check` 에 자동 편입 — 기존 4번째 verify 게이트로 합류. - 의견/해석 후보: - 보안 게이트를 도입할 때 *우회 경로*(suppression/ignore)를 같이 설계하지 않으면, 게이트는 도입 첫날부터 무력화될 수 있다. suppression governance 는 스캐너 도입의 후순위가 아니라 동시 작업이어야 한다. ## Outline seed 1. 문제: suppression 파일은 보안 게이트의 합법적 우회구 — 그러나 만료일·사유 없이 추가되면 영구 백도어 → 핵심 메시지: 우회구에도 통제가 필요하다. 2. Trivy `.trivyignore.yaml` 포맷과 `expired_at` 의 함정(누락=영구) → 핵심 메시지: 기본값이 "안전"의 반대. 3. 이중 통제 설계: CI field-gate(`verifyTrivyignore`) + merge-gate(CODEOWNERS)가 왜 둘 다 필요한가 → 핵심 메시지: "누가 바꾸나"와 "무엇이 갖춰졌나"는 다른 축. 4. 100줄 Gradle 게이트 구현 — line-based parser, 90일 창, 만료/창초과 검사, 6-케이스 검증 → 핵심 메시지: 가벼운 정적 게이트로 충분하다. 5. 한계와 정직한 등급: `locally-verified` vs CI 실증(`needs-confirmation`) → 핵심 메시지: 게이트가 도는 것과 운영에서 막는 것은 다르다. ## Canonical 전환 후보 / Canonical extraction candidates - `wiki/projects/ca-tmpl/dependency-vulnerability-suppression-gate.md` 후보: - `verifyTrivyignore` 게이트 설계 + 이중 통제 + UNSUPPORTED_IMPL_DECISION(90일) 의 ca-tmpl 적용 사실. - `wiki/concepts/security-gate-suppression-governance.md` 후보: - "보안 게이트의 우회 경로도 거버넌스 대상" 이라는 일반 개념(스캐너 무관). - 필요한 추가 검증: - CI 러너에서 워크플로 + CODEOWNERS 실제 차단 실증, lockfile 커밋 후 Trivy fs 가 Gradle deps 를 실제로 스캔하는지. ## Sources / 근거 후보 - [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] — D5, §구현가이드 §3, §진행 중 메모. - [[raw/official-docs/trivy-filtering-suppression-policy]] — `expired_at`/`statement` 시맨틱. - [[raw/interviews/trivy-suppression-dual-control-governance-2026-06-20]] — 같은 주제의 면접 질문. ## 미해결 / Unknown - 아직 확인해야 할 사실: 만료된 suppression 이 release 직전 빌드를 깨뜨릴 때의 운영 흐름. - 과장하면 안 되는 부분: 게이트는 `locally-verified` 다. "운영에서 취약점 우회를 막았다"는 아직 `needs-confirmation`. - 블로그로 쓰기 전에 필요한 canonical 정제: ca-tmpl 적용 사실 → `wiki/projects/`, 일반 개념 → `wiki/concepts/` 분리. ## Decision / 처리 결정 - 액션: `promote-to-canonical` - 이유: `wiki/projects/ca-tmpl/devops-ci-supply-chain-dx.md` 에 Trivy suppression governance static gate 글감으로 반영했다. - 다음 단계: target canonical이 아직 `draft` 이므로 `blogify` 전 review/verify가 필요하다. 운영에서 취약점 우회를 막았다고 쓰지 않는다. ## Related / 관련 - 관련 branch: [[raw/branch-notes/feature-dependency-vulnerability-management-contract]] - 관련 interview prep: [[raw/interviews/trivy-suppression-dual-control-governance-2026-06-20]] - derived blog: 생성 전. 생성 시 `wiki/blog/-2026-06-20.md` 후보