Commit Graph

6 Commits

Author SHA1 Message Date
github-actions[bot] 76a407723f 자체 빌드 이미지 태그 갱신: argocd, cloudnative-pg, cnpg-postgresql, etcd, keycloak
hardened-containers 레포의 published.json(게이트 PASS + push 확인된 발행 기록)을

반영한다. 상세는 이 실행의 Job Summary 참고.

Co-Authored-By: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-26 07:12:08 +00:00
wbsong111 9e5b6633db 자체 빌드 이미지 레포명을 security-images에서 hardened-containers로 정정한다
실제 레포명은 hardened-containers인데 이관 커밋 이후 문서·워크플로·차트 주석에
잘못된 이름 security-images가 남아 있었다. 텍스트 참조 전체를 정정하고
doc/migrations/의 이관 핸드오프 문서도 파일명까지 리네임했다. env var/secret
이름(SECURITY_IMAGES_REPO, SECURITY_IMAGES_DISPATCH_TOKEN)은 GitHub Secret
재등록이 필요한 별도 운영 작업이라 이번 텍스트 정정 범위에서 제외했다.

덧붙여 scripts/build/patch-catalog-tag.py의 docstring이 삭제된 build-image.yml을
호출자로 여전히 가리키고 있던 것도 실제 호출 경로(check-rebuild-needed.py /
apply-published-tags.py → catalog-tag-update.yml)로 고쳤다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 08:16:37 +09:00
wbsong111 7746570ec0 자체 빌드 이미지 프레임워크를 security-images 레포로 이관하고 카탈로그 쪽을 정리한다
images/·scripts/build/build-hardened-image.sh·suggest-go-upgrades.py·
build-image.yml·.claude/image-authoring.md·이미지 ADR(0001·0002·0004)을 삭제했다 —
전부 별도 public 레포 security-images 로 이미 이관됐다.

카탈로그 쪽에는 "무엇을 배포 중인가"를 아는 부분만 남긴다:
- catalog/image-map/<image>.env — 옛 catalog.env 의 카탈로그 레이아웃 정보만 뗀 것
- scripts/build/check-rebuild-needed.py — 드리프트 탐지(A 파트)만 남기고 핀 판단
  (B 파트: pin_changes/apply_changes/parse_module_specs)은 제거
- scripts/build/apply-published-tags.py(신규) — security-images 의 published.json
  을 읽어 카탈로그 values 를 패치
- .github/workflows/{self-build-drift-check,catalog-tag-update}.yml(신규) — 각각
  드리프트 스캔+트리거, 발행 태그 반영

effective_severity 를 cve-gate.py 로 옮겼다 — check-rebuild-needed.py 가 핀 도구를
거치지 않고 게이트를 직접 로드하게 하기 위한 선행 작업이다.

두 레포의 계약은 published.json 스키마 하나뿐이다 — security-images 는 이 카탈로그를
모른다(단방향 의존). 이관 배경·결합점 전체는
doc/migrations/self-build-images-to-security-images.md.

부수 수정: 자체 빌드 이미지를 참조하는 차트 values/README 의 죽은 링크(images/**,
doc/decisions/000{1,2,4}, .claude/image-authoring.md)를 security-images 레포를
가리키는 서술로 교체. deploy-test 스크립트·CUSTOM-README 의 개인 Docker Hub 계정
(docker.io/wbsong111) 을 docker.io/paasup 로 교체.

pitfalls.md 의 "스캐너 결과를 그대로 믿지 말 것" 절은 sbom-cve-gate skill 이 차트
축 설명에 실제로 참조하고 있어 남겼다 — "이미지 태그의 베이스 OS" 절만 제거했다
(다른 참조 없음, security-images 문서로 이관 완료).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 15:21:29 +09:00
wbsong111 33e91c0536 argocd: 자체 빌드 하드닝 이미지 추가, 게이트 차단 0건
업스트림 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>
2026-08-19 15:04:05 +09:00
wbsong111 7957c6a9eb argo-cd: 쓰이지 않는 dex 를 끄고 차단 CVE 57 건 제거
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>
2026-08-19 12:51:58 +09:00
wbsong111 3aa69e5eda argo-cd: 10.4.0 (ArgoCD v3.5.1) 추가 + 배포 테스트 스크립트
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>
2026-08-19 11:28:21 +09:00