From de3f91f979abb88288b6509c77cf07a4ee556c37 Mon Sep 17 00:00:00 2001 From: wbsong111 Date: Fri, 21 Aug 2026 09:26:28 +0900 Subject: [PATCH 1/3] =?UTF-8?q?MEMORY.md=20=EB=A5=BC=20=ED=98=84=EC=9E=AC?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EB=A1=9C=20=EB=A7=9E=EC=B6=98=EB=8B=A4=20?= =?UTF-8?q?(#29=20=C2=B7=20#30=20=C2=B7=20#31=20=EC=A2=85=EA=B2=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 닫힌 이슈 3건(#29 · #30 · #31)이 "열린 이슈" 표에 남아 있었고, 머지된 PR #28 이 "진행 중" 에 있었다. 대신 아직 열려 있는 #42 · #38 · #37 이 표에 없었다. 닫으면서 사라질 뻔한 것을 "아직 이슈로 만들지 않은 것" 으로 옮긴다 — `imagePullPolicy: Always` 는 #31 에 결정만 기록하고 닫았고 values 반영은 안 됐다. 레포 분리 시점 작업 2건(카탈로그 반영 워크플로 · 게이트 composite action)과 워크플로 결함 3건도 어디에도 없어 같이 적는다. Co-Authored-By: Claude Opus 5 (1M context) --- MEMORY.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index 2116a24..8b21278 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -32,9 +32,9 @@ | # | 내용 | 상태 | |---|---|---| -| [#29](https://github.com/paasup/dip-catalog/issues/29) | airflow 반복 재배포 — 비결정적 webserver secret key + migrations job TTL 루프 | 조치안 확정, **로컬 미커밋** | -| [#31](https://github.com/paasup/dip-catalog/issues/31) | 자체 빌드: 같은 날 재빌드 시 태그 충돌로 노드 캐시가 반영을 막는다 | 선택지 3안, 미결정 | -| [#30](https://github.com/paasup/dip-catalog/issues/30) | `SBOM_PIPELINE_IMAGE` 를 `docker.io/paasup` 으로 이전할지 | 수동 작업 3종, 미결정 | +| [#42](https://github.com/paasup/dip-catalog/issues/42) | `applicationset` 참조 values 의 이미지 태그가 차단 CVE 태그(`20260803`)에 멈춰 있다 | dip-console 이 이 값을 어떻게 쓰는지 확인이 선행 | +| [#38](https://github.com/paasup/dip-catalog/issues/38) | airflow fernet key 비결정 — #29 와 같은 구조, 체크섬에 없어 시한폭탄 | sync 반복 시 값이 바뀌는지 **실측 미완** | +| [#37](https://github.com/paasup/dip-catalog/issues/37) | 게이트는 판정만 하고 제안하지 않는다 — 대응 레버 1번에 도구 지원 0 | 실증 완료, 구현 미착수 | | [#32](https://github.com/paasup/dip-catalog/issues/32) | adc 이미지 배포 검증 미완료 (게이트만 PASS) | apisix-ingress-controller 와 함께 배포 필요 | | [#19](https://github.com/paasup/dip-catalog/issues/19) | 카탈로그 CVE 트리아지 기준선 | 게이트 강제 전환의 선행 조건 | | [#7](https://github.com/paasup/dip-catalog/issues/7) | CVE 조치 파이프라인 (상위 추적 이슈) | 게이트 강제력 전환 결정이 여기 있다 | @@ -42,15 +42,24 @@ ## 진행 중 -- **PR [#28](https://github.com/paasup/dip-catalog/pull/28)** — argo-cd CVE 조치(7.7.0 제거 · - dex 비활성 · 자체 빌드). 리뷰 대기. +없다. 열린 PR 0건. ## 아직 이슈로 만들지 않은 것 +- **`imagePullPolicy: Always` 를 values 에 적용하지 않았다** — 결정은 + [#31](https://github.com/paasup/dip-catalog/issues/31) 에 남기고 닫았지만 반영은 안 됐다. + 대상 7곳, `apisix/2.16.0` 은 명시적 `IfNotPresent` 라 뒤집어야 한다. - **`argo-cd/7.8.11` 삭제 여부** — 카탈로그 차단 CVE 239건이 전부 이 동결 버전 몫이고, 지우면 게이트가 PASS 로 떨어진다. 직전 버전을 없애는 결정이라 PR #28 에서 보류했다. - **자체 빌드 이미지의 정식 반영 경로** — argocd 는 로컬에서 빌드·push 했다. CI `build-image.yml`(`workflow_dispatch`)로 다시 태울지, 로컬 push 로 끝낼지. +- **레포 분리 시점의 두 작업** — ① `catalog.env` 의 카탈로그 매핑(`CHART_DIRS`·`TAG_STYLE`· + `TAG_BLOCK`)을 카탈로그 자산으로 떼어내고 `catalog-tag-update.yml` 로 반영, + ② 게이트를 composite action 으로(`workflow_call` 아님 — 스캔과 같은 job 에서 `$OUT_DIR` + 공유가 필요하다). 결합점 전체는 `.claude/image-authoring.md` "레포 분리 후 무엇이 끊기는가". +- **워크플로 결함 3건** — `cve-edge-post.yml` 이 게이트를 안 부른다(판정기 두 벌) · + 인증 스텝이 `sbom.yml` 과 diff 0 으로 복붙 · `scripts/pipeline/Dockerfile` 을 빌드하는 + 워크플로가 없다(손으로 push). - **`doc/define-chart-resources.md` 에 cloudnative-pg·cnpg-cluster·etcd 전용 절이 없다** — 리소스 프로파일 자체는 각 차트의 `dip-resources-quotas.yaml` 에 있으므로 누락은 아니다. 이 문서만 보는 사람이 세 차트를 못 찾는 것뿐이라 급하지 않다. From c3283bf7a9226b4144b04de62f526a25c5df94af Mon Sep 17 00:00:00 2001 From: wbsong111 Date: Fri, 21 Aug 2026 09:30:41 +0900 Subject: [PATCH 2/3] =?UTF-8?q?imagePullPolicy:=20Always=20=EB=8A=94=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=8B=9C=EC=A0=90=20=EC=88=98=EB=8F=99=20?= =?UTF-8?q?=EC=A1=B0=EC=B9=98=EB=8B=A4=20=E2=80=94=20=EC=B9=B4=ED=83=88?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20values=20=EA=B0=80=20=EC=95=84=EB=8B=88?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #31 코멘트에 "자체 빌드 이미지를 쓰는 차트 7곳을 Always 로 바꿔야 한다" 고 적었는데 잘못됐다. Always 를 카탈로그 기본값으로 넣으면 파드 시작마다 kubelet 이 레지스트리에서 digest 를 해석하고, 레지스트리 장애·Docker Hub rate limit 이 파드 기동을 막는 경로가 생긴다. 태그 겹침은 같은 날 재빌드한 검증 시점에만 생기는 문제인데 그 대가를 운영 내내 지불하는 셈이다. 절차는 deploy-test-procedure.md 로 옮긴다 — 검증 대상 워크로드에만 patch 로 걸고 digest(imageID)로 확인한다. 태그가 같으므로 태그를 보는 것은 아무것도 증명하지 않는다. self-build-image SKILL 의 함정 항목은 이 문서를 가리키게 하고 "프레임워크 차원의 미결" 을 지운다 — 미결이 아니라 결정됐다. MEMORY.md 의 "values 반영 안 됨" 항목은 반영할 것이 없으므로 지운다. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/deploy-test-procedure.md | 27 ++++++++++++++++++++++++ .claude/skills/self-build-image/SKILL.md | 5 +++-- MEMORY.md | 3 --- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.claude/deploy-test-procedure.md b/.claude/deploy-test-procedure.md index 373d5de..6e68573 100644 --- a/.claude/deploy-test-procedure.md +++ b/.claude/deploy-test-procedure.md @@ -90,3 +90,30 @@ APP_POD_SELECTOR="" \ dip-catalog 에 아직 없다). 통과 항목만 쓰지 말고 발견된 문제와 미검증 항목을 반드시 남긴다. 6. 정리한다. 정리 명령은 문서에 함께 기록한다. + +## 같은 날 재빌드했다면 — `imagePullPolicy` 를 수동으로 건다 + +자체 빌드 태그에는 빌드일이 들어간다(`1.30.0-security-hardened-20260820`). **같은 날 두 번 +빌드하면 태그가 겹치고**, 노드가 캐시한 옛 digest 가 그대로 쓰여(`IfNotPresent`) 고친 것이 +반영되지 않은 채 "안 고쳐졌다" 로 보인다. 검증에서 이것을 실제로 밟았다. + +검증 대상 워크로드에만 걸고, digest 로 실제 이미지를 확인한다. + +``` sh +kubectl set image ... # 태그가 같으므로 이미지 교체로는 아무 일도 일어나지 않는다 +kubectl patch deployment -n --type=strategic -p \ + '{"spec":{"template":{"spec":{"containers":[{"name":"","imagePullPolicy":"Always"}]}}}}' +kubectl rollout restart deployment/ -n + +# 태그가 아니라 digest 를 본다 — 태그는 같으므로 아무것도 증명하지 못한다 +kubectl get pod -n -o jsonpath='{range .items[*]}{.status.containerStatuses[*].imageID}{"\n"}{end}' +``` + +**카탈로그 values 에는 넣지 않는다.** `Always` 면 파드 시작마다 kubelet 이 레지스트리에서 +digest 를 해석하므로, 레지스트리 장애·Docker Hub rate limit 이 파드 기동을 막는 경로가 +생긴다(rate limit 은 이 레포에서 실측된 문제다 — `DOCKERHUB_USER`/`TOKEN` 을 쓰는 이유). +태그 겹침은 **검증 시점에만** 생기는 문제이므로 그 대가를 운영 내내 지불할 이유가 없다. + +이것이 [#31](https://github.com/paasup/dip-catalog/issues/31) 의 결정이다 — 태그에 해시를 +붙이거나 digest 로 참조하는 방안은 채택하지 않았다. 태그가 "무엇을 검증했는지의 기록" 이라는 +성격을 유지한다. diff --git a/.claude/skills/self-build-image/SKILL.md b/.claude/skills/self-build-image/SKILL.md index 5efea32..ea73731 100644 --- a/.claude/skills/self-build-image/SKILL.md +++ b/.claude/skills/self-build-image/SKILL.md @@ -97,8 +97,9 @@ python3 scripts/build/check-rebuild-needed.py --reports [--apply `python3 scripts/build/check-rebuild-needed.py --reports [--image ] [--apply]` - **단, 같은 날 다시 빌드하면 그 태그가 겹친다.** 노드가 캐시한 옛 digest 가 그대로 쓰여 (`imagePullPolicy: IfNotPresent`) 고친 것이 반영되지 않은 채 "안 고쳐졌다" 로 보인다. - 배포 검증 중이라면 `imagePullPolicy: Always` 로 우회하고, digest 로 확인한다 — - `kubectl get pod -o jsonpath='{..imageID}'`. 프레임워크 차원의 미결 사항이다. + **검증 대상 워크로드에 `imagePullPolicy: Always` 를 수동으로 걸고 digest 로 확인한다** — + 절차는 [deploy-test-procedure.md](../../deploy-test-procedure.md) "같은 날 재빌드했다면" + 이 단일 출처다. **카탈로그 values 에는 넣지 않는다**(같은 문서에 이유). ## 마무리 diff --git a/MEMORY.md b/MEMORY.md index 8b21278..7d2ab49 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -46,9 +46,6 @@ ## 아직 이슈로 만들지 않은 것 -- **`imagePullPolicy: Always` 를 values 에 적용하지 않았다** — 결정은 - [#31](https://github.com/paasup/dip-catalog/issues/31) 에 남기고 닫았지만 반영은 안 됐다. - 대상 7곳, `apisix/2.16.0` 은 명시적 `IfNotPresent` 라 뒤집어야 한다. - **`argo-cd/7.8.11` 삭제 여부** — 카탈로그 차단 CVE 239건이 전부 이 동결 버전 몫이고, 지우면 게이트가 PASS 로 떨어진다. 직전 버전을 없애는 결정이라 PR #28 에서 보류했다. - **자체 빌드 이미지의 정식 반영 경로** — argocd 는 로컬에서 빌드·push 했다. CI From 57cb2c7bd36a5ef7067f5dafb74462b3c58dafb5 Mon Sep 17 00:00:00 2001 From: wbsong111 Date: Fri, 21 Aug 2026 09:38:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?#32=20=EC=A2=85=EA=B2=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20+=20=EC=B9=B4=ED=83=88=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=EA=B0=80=20=ED=81=B4=EB=9F=AC=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=B3=B4=EB=8B=A4=20=EC=95=9E=EC=84=A0=EB=8B=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B2=83=EC=9D=84=20=EA=B8=B0=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adc 배포 검증(#32)은 완료로 닫았다 — 클러스터에 8일 이상 떠 있고, adc 가 컨트롤러가 APISIX 에 쓰는 유일한 경로인데 admin API 에 라우트 15건·SSL 9건이 전부 컨트롤러가 쓴 것으로 들어가 있다. 이슈 본문의 CLI 체크리스트(dump/diff/sync)는 배포 형태(사이드카 + 유닉스 소켓)와 맞지 않아 실측 항목으로 다시 매핑했다. 닫으면서 드러난 것을 미결로 남긴다 — 게이트 PASS 만으로 patch-catalog-tag.py 가 태그를 올리므로 카탈로그가 클러스터보다 앞서 있고(adc 0812 vs 0813, ingress-controller 0811 vs 0820), 그 격차를 재검증하는 경로가 없다. Co-Authored-By: Claude Opus 5 (1M context) --- MEMORY.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MEMORY.md b/MEMORY.md index 7d2ab49..f667828 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -35,7 +35,6 @@ | [#42](https://github.com/paasup/dip-catalog/issues/42) | `applicationset` 참조 values 의 이미지 태그가 차단 CVE 태그(`20260803`)에 멈춰 있다 | dip-console 이 이 값을 어떻게 쓰는지 확인이 선행 | | [#38](https://github.com/paasup/dip-catalog/issues/38) | airflow fernet key 비결정 — #29 와 같은 구조, 체크섬에 없어 시한폭탄 | sync 반복 시 값이 바뀌는지 **실측 미완** | | [#37](https://github.com/paasup/dip-catalog/issues/37) | 게이트는 판정만 하고 제안하지 않는다 — 대응 레버 1번에 도구 지원 0 | 실증 완료, 구현 미착수 | -| [#32](https://github.com/paasup/dip-catalog/issues/32) | adc 이미지 배포 검증 미완료 (게이트만 PASS) | apisix-ingress-controller 와 함께 배포 필요 | | [#19](https://github.com/paasup/dip-catalog/issues/19) | 카탈로그 CVE 트리아지 기준선 | 게이트 강제 전환의 선행 조건 | | [#7](https://github.com/paasup/dip-catalog/issues/7) | CVE 조치 파이프라인 (상위 추적 이슈) | 게이트 강제력 전환 결정이 여기 있다 | | [#3](https://github.com/paasup/dip-catalog/issues/3) · [#9](https://github.com/paasup/dip-catalog/issues/9) | SBOM 파이프라인 도입 · postgresql-ha 대체 | 본문상 완결로 보인다 — **닫을지 확인 필요** | @@ -54,6 +53,12 @@ `TAG_BLOCK`)을 카탈로그 자산으로 떼어내고 `catalog-tag-update.yml` 로 반영, ② 게이트를 composite action 으로(`workflow_call` 아님 — 스캔과 같은 job 에서 `$OUT_DIR` 공유가 필요하다). 결합점 전체는 `.claude/image-authoring.md` "레포 분리 후 무엇이 끊기는가". +- **카탈로그 태그가 클러스터보다 앞서 있고 재검증 경로가 없다** — 게이트 PASS 만으로 + `patch-catalog-tag.py` 가 태그를 올린다. 2026-08-21 실측: 클러스터의 adc `20260812` · + apisix-ingress-controller `20260811` 이 검증된 것인데 카탈로그는 `20260813` · `20260820` + 이다. 소스 안 바뀐 재빌드라 위험은 낮지만 **게이트 PASS 는 동작을 증명하지 않는다** + (argocd `cp --update=none` 사례). [#32](https://github.com/paasup/dip-catalog/issues/32) + 코멘트에 실측을 남겼다. - **워크플로 결함 3건** — `cve-edge-post.yml` 이 게이트를 안 부른다(판정기 두 벌) · 인증 스텝이 `sbom.yml` 과 diff 0 으로 복붙 · `scripts/pipeline/Dockerfile` 을 빌드하는 워크플로가 없다(손으로 push).