etcd·cloudnative-pg·apisix-ingress-controller 가 GO_BUILDER_TAG=1.26.5-trixie 에 핀돼
있어 새로 공개된 stdlib 차단 CVE 8건에 걸린다. 전부 Go 1.26.6 에서 고쳐졌다.
소스는 하나도 안 바꿨다 — CVE 데이터가 갱신됐을 뿐이다. 자체 빌드 이미지는 이렇게
가만히 있어도 게이트를 벗어난다는 것이 이번 사례의 요지다.
발견 경위
--------
PR #34(문서 전용)가 images/** 를 건드려 검증 빌드가 돌면서 드러났다. 오늘 날짜로
재빌드하니 etcd·cloudnative-pg 가 각각 실효 0/8 로 FAIL 했고, 기능 검증(verify.sh)은
둘 다 VERIFY-OK 였다 — 게이트만 실패했다. 대조군으로 어제 1.26.6 으로 올린 argocd 는
같은 실행에서 PASS 했다.
값은 손으로 고르지 않았다
------------------------
python3 scripts/build/suggest-go-upgrades.py --reports <trivy-reports>
→ GO_BUILDER_TAG=1.26.6-trixie / 모듈 업그레이드 제안 없음(stdlib 전용)
FixedVersion 의 `1.25.13, 1.26.6, 1.27.0-rc.3` 은 브랜치별 대안이라 최대값을 고르면
프리릴리스를 정식 버전으로 오독한다. 스크립트가 그 규칙을 처리한다.
apisix-ingress-controller 는 이번 검증 빌드 대상이 아니었다
--------------------------------------------------------
PR #34 가 이 이미지 파일을 건드리지 않아 매트릭스에서 빠졌을 뿐, 같은 툴체인 핀이다.
trivy 는 바이너리에 박힌 Go 버전으로 stdlib 을 판정하므로 1.26.5 로 빌드한 Go 바이너리는
예외 없이 해당된다. 이 PR 의 검증 빌드가 셋 다 돌려 확인한다.
각 build.env 주석에 "이 값은 go.mod 최소 요구가 아니라 stdlib 차단 CVE 를 해소하는
지점으로 정한다" 를 적어뒀다 — 다음 사람이 go.mod 만 보고 되돌리지 않게 하기 위함이다.
Refs #35
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
images/·manifests/helm/·.claude/ 의 20개 파일이 doc/decisions·doc/analysis 등 **이 레포에
존재한 적 없는 경로 15종을 48곳에서** 인용하고 있었다. security-catalog 에서 포팅할 때
따라온 것인데, 그 레포는 개인 레포(github.com/wbsong111/security-catalog)라 팀 구성원은
접근조차 못 한다 — "security-catalog 에 있으나 이관되지 않았다" 는 안내가 아무 역할을
하지 못했다.
원문을 통째로 복사하지 않았다
----------------------------
원본 문서들이 서로를 근거로 인용한다. decisions/0001 하나만 봐도 analysis/cnpg-image-baseline.md
· analysis/vendor-unassessed-data-sources.md 처럼 **인용 목록에 없던 또 다른 미이관 문서**를
가리킨다. 복사는 문제를 옮기는 것이지 없애는 게 아니다.
그리고 대부분은 애초에 dip-catalog 가 더 나은 것을 갖고 있다. 7곳에서 인용되던
analysis/sles-oval-measurement.md 는 원문 스스로 "이 문서는 결정하지 않는다. 재측정하면
갱신된다" 고 밝히는 스냅샷인데, dip-catalog 는 같은 측정을 CoverageProbe 로 매 스캔마다
자동으로 한다. 문서를 복사하는 것보다 게이트를 가리키는 것이 정확하다.
그래서 성격별로 나눴다
---------------------
재측정으로 복원 안 되는 것 → doc/decisions/ 에 자립적 ADR 로 다시 씀 (4건)
이미 단일 출처가 있는 것 → 그쪽으로 인용 교체 (11종 경로)
ADR 4건은 security-catalog 0001·0005·0006·0007 이 원본이고, 결론과 근거만 추려
dip-catalog 맥락으로 새로 썼다 — **레포 밖을 가리키는 링크가 0이다.** 번호는 이 레포에서
0001~0004 로 다시 붙였고 원본 대응은 각 문서와 README 에 적었다. 왜 안 가져온 것은 안
가져왔는지도 README 표에 남겼다.
인용 교체는 카테고리별로:
analysis/*-cve.md, cnpg-image-vuln-comparison.md → 해당 ADR · images/<image>/README.md
analysis/sles-oval-measurement.md → 게이트 CoverageProbe (doc/sbom-pipeline.md)
cve-zero-pipeline.md, architecture/build-pipeline.md → doc/sbom-pipeline.md
image-selection.md → .claude/image-authoring.md
charts/*/deploy-test.md → scripts/deploy-test/*.sh + 절차 문서
찾은 오류 2건
-------------
- images/cloudnative-pg/source.build.env 가 인용한 decisions/0004-cloudnative-pg-operator-self-build.md
는 **번호 오기**다. 원본 0004 는 postgresql-chart-selection 이고 이 결정은 0005 다.
- cnpg-cluster values.yaml·templates/database.yaml 이 인용한 doc/deploy-test-cnpg.md 는
**원본 레포에도 없다.** CREATE EXTENSION 함정 설명은 주석 자체에 이미 있어 인용만 뺐다.
검증
----
우리 파일의 깨진 doc/ 인용 0건 (전수 스캔)
새 문서·수정 문서의 로컬 링크 전부 실재 확인
helm template cnpg-cluster · etcd · cloudnative-pg 정상 렌더
남은 doc/health-checking.md(144곳)·doc/integration/*(2곳)은 업스트림 CRD·차트 안의 문자열로
우리가 쓴 인용이 아니다 — 건드리지 않았다.
Closes#33
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
MEMORY.md 는 3번째 줄에서 "지금 시점의 상태와 다음에 할 일만 담는다" 고 스스로 선언하는데
실제로는 완료 기록이 쌓여 264줄이 됐고, 이슈 참조가 한 건도 없었다. 그 결과:
- SBOM_PIPELINE_IMAGE 재빌드가 파일 안에서 3번 반복된다 (215·234·262줄)
- 게이트 강제력 전환이 2번 반복되고, 그 내용은 이미 이슈 #7 체크리스트와 #19 에 있다
- argo-cd 절 55줄은 커밋 33e91c0 메시지의 요약본이다
- 베이스 OS 정책·"벤더 릴리스 노트 믿지 말 것" 은 본문이 스스로 "이미 image-authoring.md /
skill 에 있다" 고 밝히면서 중복 서술한다
같은 사실이 여러 곳에 있으면 나중에 어느 쪽이 맞는지가 새 문제가 된다.
성격별로 목적지를 정하고 내보냈다
---------------------------------
추적이 필요한 미결 → GitHub 이슈 (#29~#33 발행, MEMORY.md 엔 한 줄 링크)
재발 방지 교훈 → .claude/ 문서·skill
단순 완료 기록 → 삭제 (커밋·PR·images/<image>/README.md 가 권위 있는 기록)
교훈 이관 — 아직 어디에도 없던 것만 옮겼다:
- image-authoring.md: 베이스 OS 를 CVE 수치만으로 고르면 배포에서 죽는다.
cp --update=none(coreutils 9.3+) 실측과, 차트가 실행하는 명령을 verify.sh 에서
재현하라는 규칙. 원칙 2 의 "BCI 버전은 실측해서 정한다" 바로 뒤에 붙였다.
- self-build-image skill: 같은 날 재빌드하면 태그가 겹쳐 노드 캐시가 반영을 막는다.
근본 해결은 #31, 여기엔 우회법만.
- cve-remediation skill: 레버 표를 보기 전에 "이 컴포넌트가 필요하긴 한가" 를 먼저 묻는다.
dex 가 한 줄로 차단 57건(58%)이었다. 가장 값싼 레버인데 표에 없어서 새 단계로 넣었다.
유지 규칙을 명시했다
--------------------
트리거는 시간이 아니라 상태다 — "1달 지났으니 정리" 는 아무도 시작하지 않고, 날짜로 자르면
오래됐지만 유효한 미결까지 잘린다. 항목이 "다음에 할 일" 이 아니게 되는 순간 내보낸다.
다만 놓친 것을 걷어내기 위해 월 1회 점검하고 파일 상단의 점검 날짜를 갱신한다.
규칙은 MEMORY.md 자체와 CLAUDE.md("작업 기록을 어디에 남기는가") 양쪽에 뒀다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
argo-cd 절의 수치·상태는 전부 재확인해 그대로 뒀다(게이트 574→337→280→239, 10.4.0 0건,
BCI 16.0 빌드 PASS/CoverageProbe ok, 7.7.0 삭제·7.8.11 잔존).
- airflow 비결정적 렌더: 재렌더 조건을 "ArgoCD 재시작·hard refresh" 로 적어뒀는데, 이후
실측에서 **일반 refresh 로도** 새 ReplicaSet 이 생겼다. 조건을 정정하고, 정해진 조치
방향(dip-values placeholder + dip-console-api DeployPreInstall 치환)과 아직 커밋 전이라는
것, 기존 테넌트는 재배포해야 적용된다는 것을 함께 적는다.
- define-chart-resources: "신규 차트 3종의 리소스 프로파일이 없다 / 규칙을 못 지켰다" 는
사실이 아니다. 세 차트 모두 dip-resources-quotas.yaml 에 small/medium/large 를 갖고 있고
차트 도입 커밋(6878b61)에 함께 들어갔다. 남은 건 문서에 전용 절이 없다는 것뿐이라
그렇게 고쳐 적는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 apisix 작업에서 만들어 실제로 적용한 skill 인데 커밋되지 않은 채 로컬에만
있었다. MEMORY.md 와 CLAUDE.md 가 .claude/skills/cve-remediation/SKILL.md 를 가리키므로
레포만 보는 사람에게는 깨진 링크였다.
CLAUDE.md 의 skill 표에도 같은 이유로 빠져 있던 줄을 넣는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
업스트림 quay.io/argoproj/argocd 의 차단 CVE 는 대부분 OS 패키지가 아니라 바이너리에
정적 링크된 Go 모듈이라, 상위 태그 교체(이미 최신)로도 베이스 OS 교체로도 잡히지 않는다.
부분 조치는 효과가 없었다 — 같은 stdlib·x/crypto 취약점이 다섯 바이너리(argocd·helm·
kustomize·git-lfs·pebble)에 각각 들어있어 본체만 고치면 거의 줄지 않는다. 업스트림
Dockerfile 이 helm/kustomize/git-lfs 를 hack/install.sh 로 **미리 빌드된 릴리스 바이너리**
로 내려받기 때문에 그 바이너리의 Go 버전을 우리가 통제할 수도 없다. 그래서 넷 다 소스에서
다시 컴파일한다.
- images/argocd/ 신규 (Go 4개 + C 2개 + Node UI — 기존 자체 빌드 중 가장 크다)
- 최종 베이스 ubuntu → SUSE BCI(원칙 2). ubuntu 가 딸려오던 pebble 도 함께 사라진다
- tini·connect-proxy 는 SLE_BCI 에 없어 소스 빌드 — 기능을 빼지 않기 위해
- UI 는 업스트림과 동일하게 node 로 빌드(Go embed 라 생략 불가)
- manifests/helm/argo-cd/10.4.0/custom-values.yaml 이 이 이미지를 가리킨다
global.image 하나로 argocd 바이너리를 쓰는 5개 컴포넌트가 공유한다
재사용 설계 — Dockerfile 에 버전을 박지 않는다
---------------------------------------------
이 이미지는 앞으로도 CVE 조치를 반복해서 받는다. 모듈 목록·패키지 목록을 전부 값으로 빼서
다음 조치에서 바뀌는 것이 source.build.env 한 곳뿐이게 했다. 이전 방식이라면 모듈 하나
추가에 build.env·ARG 선언·go get 목록·BUILD_ARGS 네 곳을 고쳐야 했다.
- scripts/build/suggest-go-upgrades.py 신규 — 스캔 리포트의 FixedVersion 에서
GO_MODULE_UPGRADES / GO_BUILDER_TAG 를 산출한다. 사람이 CVE 를 훑어 최대값을 고르지
않는다. 빌드 시점에 최신을 당기는 방식(go get -u)은 재현성을 버리므로 택하지 않았다 —
값은 제안만 하고 채택은 사람이 커밋한다.
- images/argocd/go-mod-upgrade.sh 신규 — 목록 하나를 네 프로젝트에 재사용한다.
go get 은 의존성에 없는 모듈도 go.mod 에 추가하므로 그래프에 있는 것만 골라 적용한다.
실측 함정 — verify.sh 에 반영했다
--------------------------------
차트의 repo-server init 컨테이너가 `cp --update=none` 을 쓴다. 이 형식은 GNU coreutils
9.3+ 에서만 되는데, BCI 15.7 로 빌드한 이미지가 게이트도 verify.sh 도 통과하고 **배포
시점에** Init:CrashLoopBackOff 로 죽었다. BCI 16.0(coreutils 9.6)으로 올려 해소했고,
verify.sh 가 이 명령과 copyutil 흐름을 직접 재현하도록 해서 다음엔 빌드 단계에서 걸린다.
16.0 의 패키지 가용성과 trivy 커버리지(CoverageProbe=ok, EOSL 아님)도 확인했다.
검증
----
게이트 PASS — 실효 CRITICAL/HIGH 0건, CoverageProbe ok
기능 VERIFY-OK (심볼릭 링크 9개 · 번들 도구 3종 · LFS 필터 · copyutil 흐름)
배포 docker.io/paasup 에 push 후 운영 argocd 교체 — 파드 8종 Running,
admin 로그인, Application 2건 Synced/Healthy, repo-server 렌더링 확인
(서버가 go1.26.6 · helm v4.2.4 로 보고 — 우리 빌드가 맞다)
카탈로그 차단은 574 → 239 건이 됐고(7.7.0 삭제 · dex 비활성 · 이 커밋), 남은 239 건은
전부 동결된 7.8.11 몫이다. 운영에 쓰는 10.4.0 은 0 건이다. 경과·미결은 MEMORY.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CVE 게이트 실측에서 ghcr.io/dexidp/dex:v2.45.1 이 혼자 차단 57 건을 만들고 있었다.
argo-cd 10.4.0 전체 98 건의 58% 다. 그런데 이 dex 는 인증 경로에 전혀 관여하지
않는 상태였다.
차트 기본값 dex.enabled = true
운영 argocd-cm oidc.config 있음(Keycloak 직접) / dex.config 없음
dipup tpl 항상 configs.cm.oidc.config — dex 참조 0건
ArgoCD 는 oidc.config 가 있으면 dex 를 우회하고 dex.config 를 쓸 때만 dex 가
관여한다. 즉 쓰이지도 않는 파드가 떠서 차단 CVE 의 절반 이상을 만들고 있었다.
대응 레버를 순서대로 검토한 결과 이 방법이 먼저였다.
태그 교체 소진 — dex v2.45.1(2026-03-03) · argocd v3.5.1(2026-08-12) 모두 최신.
번들 도구도 git-lfs 3.7.1 · kustomize 5.8.1 로 이미 최신이고,
낡은 Go 는 각 업스트림 프로젝트의 선택이라 버전으로 해결되지 않는다.
베이스 OS 무의미 — 차단 98 건 중 9 건(9%)만 OS 패키지다. 89 건이 Go 모듈이라
바이너리에 컴파일돼 들어가 있어 베이스를 바꿔도 남는다.
미사용 제거 ← 이것. 한 줄로 57 건(58%).
자체 빌드 남은 41 건 대상. 별건으로 검토한다.
검증:
게이트 재실행 차단 337 → 280 건 (10.4.0 몫 98 → 41)
배포 테스트 PASS — 워크로드 7종 → 6종, dex-server 사라짐, /api/version v3.5.1
dex 기반 SSO 로 전환하려면 dex.enabled 를 true 로 되돌리고 configs.cm.dex.config 를
채운다. 그때 dex 이미지의 CVE 가 다시 잡히므로 대응 계획이 함께 필요하다 —
CUSTOM-README 에 근거와 함께 적어뒀다.
7.8.11(구버전)의 dex 는 건드리지 않았다. released 된 버전이라 동결한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
벤더 C/H · NVD C/H · 실효 C/H 세 열이 나란히 놓여 어느 것이 판정값인지 헷갈렸다.
실제로 "벤더 5 / NVD 11 인데 실효가 15" 를 어떻게 읽어야 하는지 질문이 나왔다 —
세 열이 같은 CVE 집합을 세지 않기 때문이다. 실효는 CVE 마다 max(벤더, NVD) 를
적용한 결과라 합집합이 된다(5 + 11 − 교집합 1 = 15). 가로로 더하거나 빼서
검산되지 않는 숫자들을 나란히 두는 것이 혼란의 원인이었다.
판정 기준은 실효 C/H 하나뿐이므로 그것만 남기고, 벤더·NVD 의 불일치는
`하향` 열(벤더가 NVD 보다 낮게 매긴 CVE 수)로 대신 드러낸다. 개별 CVE 목록은
이미 `⚠️ 벤더 하향 등급` 절에 있어 집계 열은 중복이었다.
이전: | 벤더 C/H | NVD C/H | 실효 C/H | 차단 | 예외 |
이후: | 실효 C/H | 차단 | 예외 | 하향 |
- 범례(SUMMARY_LEGEND) 를 상수로 빼서 render_md 와 render_brief_md 양쪽에 붙였다.
Job Summary(render_brief_md)에는 범례가 아예 없어서, 새 `하향` 열이 설명 없이
노출될 뻔했다.
하향 신호를 열로 남긴 이유 — 실측:
argocd:v2.14.5 (ubuntu 24.04) 하향 43건
argocd:v3.5.1 (ubuntu 26.04) 하향 1건
dex:v2.45.1 (alpine) 하향 4건 ← 전부 SeveritySource=ghsa (Go 모듈)
redis 2개 (alpine) 하향 0건 ← Alpine 은 자체 등급을 제공하지 않는다
os-pkgs 의 등급 출처를 세어보면 ubuntu 332건은 SeveritySource=ubuntu 인데
alpine 150건은 nvd 이거나 출처 없음이다. 즉 Alpine 이미지에서 "벤더" 열은
NVD 를 그대로 되비추는 값이라 비교 자체가 성립하지 않았다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
카탈로그가 한 차트의 여러 버전을 들고 있어서, 게이트 요약표에 버전 정렬이 없으면
최신 버전과 구버전이 위험도 순으로 섞여 "지금 쓸 버전이 어느 정도인가" 를 한눈에
볼 수 없었다. 실측 사례 — argo-cd 10.4.0 이 구버전 7.8.11 사이에 끼어 표시됐다.
변경 전 (chart asc → 실효 C/H desc)
argo-cd@7.8.11 argocd:v2.14.5 14/101
argo-cd@7.8.11 redis:7.4.2 5/60
argo-cd@10.4.0 dex:v2.45.1 5/52 ← 최신이 구버전 사이에
argo-cd@7.8.11 dex:v2.42.0 4/55
argo-cd@10.4.0 argocd:v3.5.1 1/40
변경 후 (chart asc → 버전 desc → 실효 C/H desc)
argo-cd@10.4.0 dex:v2.45.1 5/52
argo-cd@10.4.0 argocd:v3.5.1 1/40
argo-cd@10.4.0 redis:8.6.4 0/0
argo-cd@7.8.11 argocd:v2.14.5 14/101
argo-cd@7.8.11 redis:7.4.2 5/60
argo-cd@7.8.11 dex:v2.42.0 4/55
- scripts/pipeline/cve-gate.py
- version_sort_key() 추가. 문자열 비교로는 "10.4.0" < "7.8.11" 이 되어 최신이
아래로 내려간다. 숫자 구간을 정수로 파싱한다.
프리릴리스는 코어와 분리해 다룬다 — 단순히 구간을 이어붙이면 리스트가 긴 쪽이
커져 "1.2.0-rc1" 이 "1.2.0" 보다 최신으로 정렬된다(단위 테스트로 실측).
semver 규칙대로 프리릴리스 없는 정식 릴리스를 더 크게 본다.
- 정렬은 안정 정렬을 3번 겹쳐 만든다. 버전만 내림차순이라 reverse=True 가
필요해 한 번에 튜플 하나로 묶을 수 없다.
- manifests/helm/argo-cd/7.7.0 제거
게이트 차단 574건 중 237건이 이 버전의 이미지 3개였다
(argocd:v2.13.0 117 / dex:v2.41.1 61 / redis:7.2.4-alpine 59 — 뒤 둘은 EOSL).
제거 후 차단 337건.
doc/catalog-stack-classification.md 의 버전 목록도 갱신했다(10.4.0 이 빠져 있어
이미 stale 이었다). doc/chart-restructure-plan.md 는 과거 이관 기록이라 두었다.
로컬 파이프라인으로 검증했다(extract → generate → scan → gate, argo-cd 범위).
이미지 6개 / SBOM 6개 성공 / 커버리지 전부 ok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
k8s 1.33 에서 Deployment/ReplicaSet 에 추가된 .status.terminatingReplicas 를
ArgoCD v2.14.5(k8s 라이브러리 0.31/0.32)가 몰라, 클러스터가 1.33 이상이면
ServerSideApply=true 인 Application 이 전부 아래 오류로 죽는다.
ComparisonError: failed to calculate diff: error calculating structured
merge diff: .status.terminatingReplicas: field not declared in schema
v3.5.1 은 k8s 라이브러리 0.36.1 을 써서 해소된다. dev 클러스터(1.35.7+rke2r1)
에서 실제 발생·해소를 확인했다.
- manifests/helm/argo-cd/10.4.0/ 추가 (chart_updater 로 생성)
- custom-values.yaml 을 실제 배포 기준(dipup argo-cd-values.yaml.tpl)에 맞춤:
kong → apisix, server.extraArgs(--insecure), configs.cm/rbac 추가
- configs.params.controller.resource.health.persist=true 지정 —
ArgoCD v3.0 부터 리소스 health 를 CR 에 저장하지 않는 것이 기본값인데,
dip-console-api 가 .status.resources[].health 를 읽는다
- CUSTOM-README.md 는 현재 차트 기준 배포 가이드로 재작성.
승계된 cert-manager 예시가 10.4.0 에 없는 구버전 스키마(hosts/tls 리스트)라
Ingress 가 생성되지 않는 상태였던 것도 함께 수정
- breaking_change_check: breaking=false (제거 26건이 전부 미사용 key)
- scripts/deploy-test/deploy-test-argo-cd.sh 신규
같은 클러스터에 두 번째 argo-cd 를 띄우려면 crds.install=false 가 필수다 —
CRD 3종이 클러스터 전역이고 운영 릴리스가 소유해 Helm 이 ownership 충돌로
거부한다. Ingress 도 항상 끈다(운영과 host 충돌).
검증: 워크로드 롤아웃 / health.persist / api 버전 / admin 로그인
- argo-cd/7.8.11/BUILD-README.md 에 `helm repo add argo ...` 추가
chart_version_detector 가 이 한 줄을 정규식으로 뽑아 업스트림 레포를 정하는데,
argo-cd 에는 없어서 신규 버전 자동 감지가 조용히 실패하고 있었다
(repo: null → latest_version: null). CLAUDE.md 의 "변경 금지" 규정도
실제 파싱 계약에 맞게 정정했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
-ingress-unauth 는 kubectl get ingress 목록에서 "인증 없는 입구"를
그대로 광고한다. 리소스가 무엇인지가 아니라 무엇이 없는지로 이름을
지은 것이기도 해서, 경로가 /static 외로 늘어나면 이름이 뜻을 잃는다.
파일명(webserver-ingress-static.yaml)과 일치시키고 용도를 그대로
드러내는 -ingress-static 으로 바꾼다. 값 키 dip.unauthenticatedPaths
는 values 파일 안에만 있고 의도를 정확히 서술하므로 그대로 둔다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
세션이 없는 상태로 접속하면 Airflow UI 한 페이지가 /static 자원을 수십 개
동시에 요청하고, 각 요청이 저마다 APISIX openid-connect 로그인 플로우를
시작한다. 세션은 state를 하나만 보관하므로 콜백이 동시에 돌아오면 마지막
하나를 뺀 전부가 state 검증에 실패해 500이 난다.
templates/webserver/webserver-ingress-static.yaml 은 업스트림 Apache Airflow
차트에 없는 PaaSup 추가 템플릿이다. dip.unauthenticatedPaths 가 있을 때만
애노테이션 없는 Ingress를 하나 더 렌더해 해당 경로를 인증 없이 통과시킨다.
애노테이션을 전부 비우는 것은 의도된 것으로, plugin-config-name 을 빼는 게
목적이고 cert-manager.io/* 까지 빼는 이유는 웹 Ingress와 같은 TLS Secret 을
두고 Certificate 를 중복 생성하지 않게 하기 위해서다.
값을 ingress.web 아래가 아니라 dip 아래에 두는 이유는 values.schema.json 의
ingress.web 이 additionalProperties: false 라 그 아래 새 키를 넣으면 스키마
검증에서 배포가 실패하기 때문이다. qdrant·litellm 의 dip.mainPath 와 같은
자리를 쓴다.
webserver-ingress.yaml 과 동일한 조건으로 렌더하므로 Airflow 3.0
(webserver → api-server) 전환 시 함께 재작업이 필요하다. 업스트림 파일은
수정하지 않았고 fork 델타는 신규 템플릿 1개뿐이다.
이슈 #24 는 dip-console 이 차트 밖에서 생성하는 방안(B안)을 권고했으나,
실제로 증상이 재현되는 서비스가 airflow 하나로 좁혀져 차트 템플릿(A안)으로
갔다. dip-console 로 옮길 때는 dip.unauthenticatedPaths 를 비우면 된다.
redirect_uri 고정은 여전히 dip-console 몫으로 남는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CLAUDE.md 정적 카탈로그 규모를 실측치로 교체(차트 59 / 버전 디렉토리 70).
차트 디렉토리 5종 파일이 전부 갖춰지지 않은 곳이 있다는 사실과 dip-* 계열이
선택적이라는 점을 명시해 "5개 필수"로 오해하지 않게 했다.
- 디렉토리 트리에 scripts/deploy-test/·images/·MEMORY.md·doc/ 하위 문서를 추가.
scripts/build/ 의 "아직 실사용 이미지 없음" 문구는 실제 빌드 이미지가 생겨
더 이상 사실이 아니라 제거했다.
- chart-to-cnpg: 남은 전환 대상에서 flowise 제외(2026-08 완료), infisical-standalone 추가.
- self-build-image: 이미지 3종 → 7종. 목록이 또 어긋나지 않도록 images/ 디렉토리가
단일 출처임을 설명에 박아뒀다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
flowise/6.0.0 의 dip-values.yaml + dip-questions.yaml 스키마를 airflow 에 적용했다.
doc1 은 cnpg-cluster(airflow-db), doc2 는 airflow 본체다.
dip-values.yaml
- bootstrap.initdb 의 database/owner 는 airflow-db-values.yaml 과 맞춘 airflow.
- databases[] 도 airflow/airflow. 차트 기본값인 appdb/appuser 를 쓰면 appuser
롤이 생성되지 않아 Database CR reconcile 이 실패한다.
- bootstrap.initdb 에는 ensure/reclaimPolicy 를 넣지 않았다. cnpg-cluster 의
cluster.yaml 이 읽지 않는 databases[] 전용 키다.
- postgresql.enabled: false. 내장 bitnami 대신 syncWave 0 의 cnpg 를 쓴다.
- metadataConnection.host 는 "{{ .Name }}-airflow-db-rw". dip 배포는 cnpg
릴리스명에 테넌트 접두사를 붙여 나간다(관측: instance=demo01-air-airflow-db).
flowise 의 externalPostgresql.host 와 같은 규칙이다.
dip-questions.yaml
- git-sync 는 GIT_SYNC_*/GITSYNC_* 네 키를 모두 선언한다. 차트가 네 개를 각각
secretKeyRef 로 잡아서 하나라도 없으면 파드가 기동되지 않는다.
- connection 기본값 호스트는 $CATALOG_NAME-airflow-db-rw.$CATALOG_NAME.
차트가 data.metadataSecretName 의 connection 키를
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN 에 그대로 주입하므로 이 값이 유일한 실효 값이다.
두 파일의 토큰 형식 차이는 의도한 것이다 — dip-questions 는 $CATALOG_NAME,
dip-values 는 {{ .Name }} 가 각 파일의 기존 관례다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
LLM·데이터분석 스택(2,3)에 남아있던 P0(litellm, open-webui, langfuse,
strimzi-kafka-operator, kafka-cluster, airflow, lakekeeper, superset)를 P1/P2로
재분류해, P0는 dipup 기본 배포(argocd·harbor·gitea·infisical·keycloakx)와 그
직접 의존 인프라(cert-manager, apisix, etcd, cloudnative-pg, cnpg-cluster,
rancher, dnsup)에만 남도록 정리했다. 데이터분석 스택 차트 수 헤더(16→18)도
실제 개수에 맞춰 수정.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
limit(개수 상한)만으로는 특정 차트를 겨냥해 스캔할 수 없었다(images_final.tsv가
차트 알파벳 순으로 쌓여 앞쪽 무관한 차트까지 같이 스캔됨). chart 입력을 비우면
기존과 동일하게 전체 스캔.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
etcd(bitnamilegacy 동결 미러) → etcd.enabled=false + 카탈로그 자체 etcd 차트를
externalEtcd 기본값으로 연결. adc·apisix-ingress-controller·apisix(paasup/apisix)
세 이미지는 SUSE BCI 자체 빌드로 교체 — 전부 벤더 등급만으로는 안 보이던
벤더 하향 등급 CVE(NVD 재평가 시 드러남)가 원인이었다.
- images/apisix-ingress-controller: 정적 링크 Go 모듈 취약 버전만 강제 업그레이드
- images/apisix: APISIX-Runtime(WASM·dubbo 등 커스텀 모듈 포함) 전체를 SUSE BCI
위에서 소스로 재현, keycloak-authz 플러그인 오버레이
- images/adc: 업스트림 빌더 스테이지는 그대로 두고 distroless 최종 베이스만
SUSE BCI+nodejs24 로 교체
scripts/build/patch-catalog-tag.py 의 TAG_BLOCK 이 점 구분 중첩 경로를 지원하도록
확장(apisix 서브차트 alias 때문에 필요).
세 이미지 모두 게이트 PASS(실효 CRITICAL/HIGH 0/0)와 배포 검증(테스트 클러스터)을
마쳤다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CVE 자체 빌드 이미지가 앱 버전까지 함께 올리며 두 카탈로그 버전이 서로 다른
컴포넌트 버전을 요구하는 복잡도가 생겨, 구버전을 유지하는 대신 최신 버전
하나로 정리한다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
manifests/helm 차트를 DIP/LLM/데이터분석 3개 스택과 우선순위(P0~P2)로 분류한다.
차트별 CVE 트리아지 상세는 issue #19로 별도 관리한다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
## doc/sbom-pipeline.md — 중복·모순 정리 (328 → 286줄)
같은 사실이 여러 절에 흩어져 있었고, 일부는 문서가 아니라 변경 이력이었다.
- `SEVERITY` 를 전 심각도로 덮어써야 하는 이유가 환경변수 절·CI 절·요약 절 3곳에
있었다. 스크립트 절의 blockquote 하나로 합쳤다 — "게이트를 돌릴 거라면 전 심각도로
스캔해야 한다"가 핵심이고 나머지는 그 결과다.
- Job Summary 1MB 제한이 CI 절과 결과 확인 절에 중복됐다. CI 절 하나로 합쳤다.
- `--warn-only` 서술이 mermaid 라벨·CI 절·게이트 절·트리아지 절 4곳에 있었다.
게이트 절 하나로 합치고, `build-image.yml` 쪽은 이미 강제라는 대비를 함께 적었다.
- 자체 빌드 트리거 표가 "PR 은 push 안 함"을 말하는데 바로 아래 불릿이 같은 말을
반복했다. 표는 그대로 두고 불릿은 **왜** 그런지(REGISTRY 미전달 → localhost 태그라
push 를 시도할 수조차 없다)만 남겼다.
- "오해를 주던 단일 '총 소요'는 제거" 같은 변경 이력 서술을 걷어냈다. 문서는 현재
상태를 적는 곳이다.
- "첫 전체 실행 결과(2026-07-08)" 절은 수치를 싣고 바로 아래에서 "현재 수치가
아니다"로 무효화하는 구조였다. 절 자체를 없애고, 거기서 유일하게 쓸모 있던 사실
(SBOM 생성 실패는 대부분 사설/미인증 레지스트리이거나 대용량 timeout)만 스크립트
절로 옮겼다.
- "실행 이력(2026-08-04)" 절은 MEMORY.md 와 중복이라 제거했다. 거기서만 알 수 있던
사실(Actions 시크릿의 push 권한 확인)은 GitHub 설정 표에 반영했다.
- `CVE_API_KEY` 가 본문에만 있고 GitHub 설정 표에 빠져 있어 추가했다.
- 아키텍처 절 불릿이 mermaid 서브그래프 라벨과 같은 말을 하고 있어, "pull 을 ② 한
곳에 몰아둔 것이 핵심"이라는 결론 한 문장으로 줄였다.
## 이미지 목록을 문서에 박아두지 않는다
이미지는 계속 추가되므로 열거하면 추가할 때마다 낡는다. `images/` 디렉토리를 단일
출처로 삼고 CLAUDE.md·image-authoring.md·build-image.yml·sbom-pipeline.md 의 열거를
걷어냈다. keycloak README 의 베이스 OS 결정 근거도 "기존 3종" 대신 "먼저 들어온
이미지들"로 바꿨다 — 근거의 내용은 그대로다.
## 현황 서술 정정
- build-image.yml 주석이 "아직 도입된 자체 빌드 이미지가 없다(images/ 가 비어 있음)"
로 남아 있었다. 이 레포 CI 에서 빌드→검증→게이트→push→카탈로그 브랜치 push 까지
실제로 검증된 상태다.
- MEMORY.md: cve-exceptions.json 첫 예외 등록, 베이스 OS 정책 확정, PR 자동 생성이
조직 정책으로 불가하다는 실측(run 30882785612)을 반영했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI(31148639764)의 trivy 취약점 DB 가 로컬보다 최신이라 로컬 스캔에는 없던
CVE-2026-40983·CVE-2026-40984(io.micrometer:micrometer-core)가 차단으로 잡혔다.
netty·jackson 과 동일한 성격의 번들 jar CVE 라 같은 오버레이 메커니즘으로 처리한다.
micrometer 1.16.3 → 1.16.6. netty 와 같은 이유로 CVE 가 붙은 micrometer-core 만이
아니라 패밀리 전체 4종(commons·core·observation·registry-prometheus-simpleclient)을
함께 올린다 — 아티팩트 간 버전 혼용이 비지원이다.
Dockerfile 의 ARG 선언을 처음에 빠뜨렸는데 overlay-jars.sh 의 `: "${VAR:?}"` 가드가
설계대로 빌드를 세웠다("parameter null or not set"). 조용히 통과하지 않는다.
재빌드 결과(로컬 trivy DB 캐시를 지우고 CI 와 같은 최신 DB 로 재판정):
차단 0건 — 게이트 PASS
docker.io/paasup/keycloak:26.7.1-bci15.7-hardened-20260807 push 완료
태그는 빌드일 기준이라 같은 날 재빌드가 같은 태그를 덮는다(프레임워크 설계대로).
직전에 push 된 것은 micrometer 취약점이 남아 있던 빌드이고 어디에도 소비되지 않았다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기존 3종의 verify.sh 가 전부 100755 인데 100644 로 들어갔다. 둘 다 `bash <파일>`
로 호출되어 동작에는 영향이 없지만 관례를 맞춘다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #18 이 카탈로그에 넣는 quay.io/keycloak/keycloak:26.6.4 가 게이트에서 차단
17건(실효 HIGH 17 / CRITICAL 0)이었다. sbom.yml 이 warn-only 라 PR 은 통과했지만
실제로는 게이트 실패 상태로 카탈로그에 들어간다.
## 상위 태그·베이스 OS 교체를 먼저 검토한 결과
차단 17건 중 12건이 배포본에 함께 실린 jar 다. keycloak 26.6.4 와 최신 26.7.1 의
quarkus.version 이 둘 다 3.33.2.1 이고 그 BOM 이 netty 4.1.135.Final /
jackson-bom 2.21.2 를 고정한다(keycloak pom.xml 두 태그 + quarkus BOM 실측).
필요한 수정 버전은 netty 4.1.136.Final, jackson 2.21.4 라 **상위 태그로도 풀리지
않고**, CVE 가 OS 패키지가 아니라 jar 자체라 **베이스 OS 교체도 통하지 않는다.**
jar 를 직접 교체하는 자체 빌드가 유일한 수단이다 — etcd 이미지의
`go.work replace golang.org/x/text` 와 같은 성격의 의존성 override.
## images/keycloak/
업스트림 quarkus/container/Dockerfile 을 기준으로 하되 셋이 다르다.
1. 런타임 rootfs 가 SUSE BCI. bci-micro 파일시스템을 **씨앗으로 깔고** 그 위에
zypper --installroot 로 설치한다. 업스트림 ubi-null.sh 처럼 별도 installroot 를
micro 위에 덮으면 micro 의 rpmdb 가 가려져 micro 자체 패키지가 SBOM 에서 통째로
사라진다 — CVE 가 주는 게 아니라 스캔 사각지대가 생긴다. 씨앗 방식으로 OS 패키지
65종이 정상적으로 잡히는 것을 SBOM 으로 확인했다.
2. 취약 jar 오버레이(overlay-jars.sh). netty 17종 → 4.1.136.Final, jackson
core/databind → 2.21.4, pgjdbc → 42.7.12. Quarkus fast-jar 의 클래스패스가
파일명을 그대로 참조하므로 **파일명은 유지하고 내용만** 바꾸고 sha1 로 검증한다.
trivy 는 jar 내부 메타데이터를 읽으므로 SBOM 에 새 버전이 정확히 잡힌다.
3. bin/client 제거. keycloak-admin-cli 가 jackson 을 shade 로 품은 uber-jar 라
교체가 불가능하다. 서버 JVM 이 로드하지 않는 독립 CLI 라 제거했다 — 업스트림
대비 유일한 기능적 차이이며 CUSTOM-README 에 대안을 적었다.
버전은 26.7.1 로 올렸다. 26.6.4 는 26.7.1(및 26.6.5)에서만 패치된 keycloak-services
HIGH 5건(CVE-2026-16102/16442/16443/15572/15573)에 취약하다. 차트(keycloakx 7.2.2)는
최신이고 그대로 둔다 — appVersion 26.6.4 는 codecentric 의 릴리스 캐던스 지연이다.
## 베이스 OS 정책 확정 (image-authoring.md 원칙 2 미결 해소)
SUSE BCI 로 통일하되 **버전은 이미지마다 실측해서 고른다.** BCI 16.0 이 나와 있지만
SLE_BCI 의 java-21-openjdk-headless 가 15.7 은 21.0.12, 16.0 은 21.0.11 이라 최신
베이스로 가면 CVE-2026-41254·CVE-2026-47063 이 오히려 남는다. bci-micro 에
sed·grep·find 가 셋 다 없다는 것과 SLE 패키지명 차이(tzdata→timezone 등)도 함께
기록했다.
## 실측 결과
로컬 빌드(linux/amd64) → verify.sh → SBOM → 전 심각도 스캔 → 게이트:
차단 17건 → **0건** (커버리지 자가진단 ok, OS=sles 15.7)
남은 1건 CVE-2025-59250 은 예외 등록했다 — 트리비가 같은 mssql-jdbc jar 하나로
컴포넌트를 둘 만들어(pom.properties 의 13.2.1.jre11 / 파일명의 13.2.1) 접미사가
잘린 쪽이 매칭된 파싱 오탐이다. 설치본은 FixedVersion 목록에 있는 13.2.1.jre11 이다.
dev 클러스터 격리 네임스페이스(kc-test-build)에 cnpg-cluster + keycloakx 로 실배포
검증: Pod Running, jdbc-postgresql 연결, liquibase 스키마 생성, admin 부트스트랩
(KC-SERVICES0077), apisix ingress 경유 OIDC discovery 200 / admin 토큰 발급 /
realm·client 생성(201) 까지 확인. 정리 시 Longhorn Volume 까지 삭제했다.
## custom-values.yaml ingress 수정
path 가 exact "/" 였다. apisix 에서는 루트만 매치되어 /realms/*, /admin/* 이 전부
404 가 난다 — airflow·superset·mlflow·lakekeeper 에서 이미 실측된 문제로 카탈로그가
regex 방식으로 통일돼 있다. path: /.* + k8s.apisix.apache.org/use-regex 로 맞췄고,
배포 검증에서 이 경로들이 실제로 뜨는 것을 확인했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1.0.0 에서 복사한 뒤 안 고친 차트 버전 표기(1.0.0)와 배포 경로를 1.1.0 으로
맞추고, 저장소에 실제로 존재하지 않는 doc/decisions·doc/analysis·doc/charts
경로 인용을 제거했다(리뷰 중 확인 — PR #17).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dev 클러스터 격리 네임스페이스에 실제 배포해 검증하는 과정에서 두 가지
누락을 발견했다:
1. command/args 기본값이 둘 다 빈 배열이라, 지정하지 않으면 컨테이너가
인자 없는 kc.sh(도움말 출력, exit 0)로 끝나 CrashLoopBackOff가 된다.
2. hostname-strict 기본값이 true라 KC_HOSTNAME 을 지정하지 않으면
"hostname is not configured" 로 기동이 실패한다.
두 값 모두 custom-values.yaml에 추가하고, BUILD-README/CUSTOM-README에
실측 근거를 남겼다. 이후 admin 부트스트랩(KC-SERVICES0077), DB 마이그레이션,
admin REST API로 realm/client 생성까지 전부 정상 동작 확인.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
codecentric/keycloak(18.4.0, WildFly 기반, appVersion 17.0.1-legacy)이
bitnami/postgresql 서브차트를 조건부 의존성으로 포함해 bitnami 무료 배포
정책 변경 문제가 그대로 전이됐다. codecentric은 이 WildFly 차트를 더 이상
갱신하지 않고 Quarkus 기반 Keycloak(17+)용 별도 차트 keycloakx를 제공하며,
keycloakx는 서브차트 의존성이 전혀 없어(Chart.yaml에 dependencies 없음)
문제가 근본적으로 해소된다.
실제 소비자가 없어(문서 예시 표 한 줄 외 참조 없음) phased 전환 없이
keycloak/18.4.0을 같은 커밋에서 제거했다.
custom-values.yaml 작성 시 확인한 핵심 사항 — 이 차트의 http.relativePath
기본값이 구버전 WildFly Keycloak 호환용 "/auth"라, 명시적으로 "/"로
오버라이드해야 한다(안 하면 OIDC issuer/admin API 경로가 소비 앱들의
경로 접미사 없음 가정과 어긋난다). database.existingSecret/existingSecretKey
로 kubernetes.io/basic-auth 시크릿을 그대로 참조 가능함도 helm template로
확인했다.
Closes#1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
앱별 부트스트랩 SQL 을 ConfigMap/Secret 참조로 실행할 수 있게 한다. CNPG CRD 에는
이미 있는 필드(operator 0.29.0/CRD 확인됨)인데 차트가 렌더하지 않아 values 로 쓸 수
없었다.
용도: 스키마 덤프처럼 큰 SQL 을 values 에 인라인하지 않고 ConfigMap 으로 넘기는 경우.
postInitApplicationSQL(인라인)과 시점·권한이 동일(클러스터 생성 직후 1회, 앱 DB 안에서
superuser) 하고 SQL 출처만 다르다. 1회성이라 비멱등 SQL(CREATE TABLE 등)을 그대로
넣어도 재실행되지 않는다.
- values.yaml: bootstrap.initdb.postInitApplicationSQLRefs 추가(configMapRefs/secretRefs,
기본 빈 배열)
- templates/cluster.yaml: 값이 있을 때만 렌더(있으면 렌더, 없으면 필드 자체가 안 나옴 —
기존 클러스터에 영향 없음을 렌더 테스트로 확인)
- CUSTOM-README.md: postInitApplicationSQL 과의 차이·참조 처리 순서(Secret 전체 →
ConfigMap 전체) 문서화
카탈로그 관례 파일(BUILD-README·CUSTOM-README 본문 대부분·dip-*.yaml·custom-values.yaml)은
1.0.0 에서 그대로 승계했다(diff 로 확인).
검증: 빈 값일 때 필드 미노출, configMapRefs 지정 시 정상 렌더, 기존 1.0.0
custom-values.yaml 로 1.1.0 렌더해도 문제없음(하위 호환) 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
12.4.0 → 12.6.0 승계 시 BUILD-README/CUSTOM-README/custom-values 3개만 옮기고
카탈로그 관례 파일 5개를 빠뜨렸다. 12.4.0 에서 그대로 승계한다:
- argo-values.yaml
- dip-questions.yaml
- dip-resources-quotas.yaml
- dip-values.yaml
- dip-volumes-quotas.yaml
dip-*.yaml 은 카탈로그 전반의 관례다(25개 이상 차트, 총 100개 파일). 갱신 대상
7개 차트 중 이 파일들을 가진 것은 gitea 뿐이라 다른 차트는 영향이 없다.
내용은 버전 의존적이지 않아(리소스/볼륨 티어, questions, ApplicationSet 용 values)
수정 없이 그대로 옮겼다.
검증: 5개 파일 모두 12.4.0 과 12.6.0 에서 helm 렌더 결과가 동일하다. dip-values.yaml
(`{{ .Name }}`·`{{ .Domain }}` 미치환)과 argo-values.yaml(postgresql/postgresql-ha
동시 활성)은 양쪽 버전에서 똑같이 렌더 실패하는데, ApplicationSet 계층이 먼저
치환·조정하는 것을 전제로 한 파일이라 원래 helm 단독 렌더 대상이 아니다 —
이번 승계로 생긴 회귀가 아님을 12.4.0 대조로 확인했다.
차트 12개 렌더 재검증 12/12 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rancher 2.14.3
- custom-values 의 `preinstallHook: true` 제거. 2.10.1 에 있던
templates/preinstallHook/ (tls-ca secret 생성 Job)이 2.14.3 본문에는 없어
이 값이 아무 동작도 하지 않는다. dipup 은 설치 전 단계에서 직접 만든다
(pkg/kube/secret.go CreateRancherCASecret).
- privateCA: true 는 deployment 가 tls-ca secret 을 non-optional 로 마운트하게
하므로, 카탈로그 차트만으로 배포할 때 secret 이 없으면 파드가
ContainerCreating 에서 멈춘다. 해당 주의를 custom-values·CUSTOM-README 에 명시.
- BUILD-README 상단에 2.14.3 이 dipup tgz 전개본이라 이 문서의 차트 수정 절차가
적용되지 않았음을 명시하고, preinstallHook 단계를 무효 표시.
infisical-standalone 1.9.0
- custom-values 에 `ingress.nginx.enabled: false` 추가. 차트 기본값이 활성이라
스캐너(extract-helm-images.sh 가 custom-values 로 effective image 산출)가
dipup 이 배포하지 않는 k8s.gcr.io/ingress-nginx/controller:v1.1.0 ·
kube-webhook-certgen:v1.1.1 을 잡아 CVE 트리아지 잡음이 됐다.
dipup env/values/infisical-values.yaml 과 값을 맞춘다.
검증: 12/12 차트 helm template --kube-version 1.34.1 렌더 성공.
infisical effective image 가 dipup 배포분 3종으로 축소됨을 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>