Files
service-catalog/doc/decisions/0002-cloudnative-pg-operator-self-build.md
T
wbsong111 1a747f61a8 자체 빌드 이미지 문서가 이 레포에 없는 경로를 인용하던 것을 없앤다 (#33) (#34)
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>
2026-08-20 10:20:40 +09:00

5.1 KiB

0002. cloudnative-pg 오퍼레이터를 소스 컴파일 자체 빌드로 대체하고, 자체 빌드 오케스트레이션을 하나로 통일한다

  • 날짜: 2026-07-30 (결정) · 2026-08-04 (docker.io/paasup 로 재빌드)
  • 상태: 확정
  • 원본: security-catalog ADR 0005 — dip-catalog 맥락으로 다시 썼다(README 참고)

결정

manifests/helm/cloudnative-pg/0.29.0 의 오퍼레이터 이미지를 자체 빌드로 한다. 현재 태그는 custom-values.yamlimage.repository/image.tag 가 단일 출처이고, 빌드 정의는 images/cloudnative-pg/다 — 업스트림 release-1.30 브랜치의 pinned commit 을 직접 go build 로 컴파일하고, 최종 런타임 베이스는 SUSE BCI(bci-micro)다.

추가로, 이 작업에서 scripts/build/build-hardened-image.sh 를 일반화해 OS 패키지 재설치형(cnpg-postgresql)과 소스 컴파일형(cloudnative-pg)이 오케스트레이션 스크립트 하나를 공유하게 했다. 자체 빌드 이미지가 늘어날 때마다 방법론이 갈라지지 않게 하기 위함이다. 계약은 .claude/image-authoring.md 가 갖는다.

배경

업스트림 cloudnative-pg:1.30.0 이 게이트에서 실효 HIGH 3건으로 차단됐다 — CVE-2026-39822 (stdlib), CVE-2026-56852(golang.org/x/text), GHSA-hrxh-6v49-42gf(grpc).

셋 다 Go 바이너리에 정적 링크된 모듈 버전이 원인이라 앞선 두 레버가 통하지 않는다.

  • 상위 태그 교체 — 상위 태그가 없다(2026-07-30 확인, 최신 릴리스가 여전히 v1.30.0)
  • 베이스 OS 교체 — 배포 이미지 베이스가 distroless 라 OS 패키지가 사실상 0개다

자체 빌드만 유효한 대응이었다. 세 CVE 모두 업스트림 release-1.30 브랜치에 이미 백포트돼 있어, Go 의존성을 직접 올릴 필요 없이 그 커밋을 그대로 컴파일하면 됐다.

근거

  • release-1.30 HEAD 는 실측으로 확인된 안전한 픽업 지점이다. go.mod 비교로 세 CVE 의 수정 버전이 전부 포함됨을 확인했고(stdlib 1.26.5, x/text 0.39.0, grpc 1.82.1), 재스캔으로 실효 C/H 0/0 을 확인했다.
  • 게이트 통과가 "동작함" 을 증명하지 않는다는 원칙이 실제로 작동했다. 1차 빌드는 게이트를 0/0 으로 통과했지만 배포 검증에서 Cluster 리컨실이 invalid architecture: amd64 로 실패했다. 오퍼레이터가 자신의 가용 아키텍처를 operator/manager_<arch> 파일 존재로 판단하는데, 업스트림의 멀티아치 심볼릭 링크를 "부수 장치" 로 오판해 제거했기 때문이다. 같은 바이너리를 /manager/operator/manager_amd64 양쪽에 COPY 해 해결했다.
  • 베이스 OS 는 BCI 로 통일한다는 결정(0001)이 이 이미지에도 적용된다. 최초 설계는 "업스트림과 최대한 동일하게" 를 따라 distroless 를 그대로 썼으나 카탈로그 정책과 어긋나 bci-micro 로 교체했고, 교체 후에도 게이트·배포 검증 PASS 를 유지하는 것을 확인했다.
  • 오케스트레이션 통일이 회귀를 만들지 않는 것을 확인했다 — 스크립트를 일반화한 직후 기존 cnpg-postgresql 을 다시 빌드해 태그·게이트 결과가 동일함을 확인했다.

받아들인 비용

  • 업스트림 서명·provenance·SBOM attestation 을 잃는다. ADR 0001 과 동일한 비용이다.
  • SOURCE_COMMIT 갱신을 사람이 한다. 자동 추적하지 않는다 — 다음 CVE 발생 시 그 시점의 유지보수 브랜치 최신 커밋을 사람이 골라 source.build.env 를 고쳐 PR 을 여는 것 자체가 트리거다.
  • release-1.30 은 순수 패치 백포트가 아니다. 기능 커밋 2개(feat(pooler) auth_user, feat check_empty_wal_archive)가 섞여 있다. 59 commits 전체를 라인 단위로 감사하지 않았고, 배포 검증 스모크 수준으로만 회귀 여부를 봤다.
  • 업스트림이 테스트하지 않는 구성이다. BCI 기반 오퍼레이터 빌드는 CNPG 의 CI 매트릭스에 없다.
  • bci-microbci-base 와 달리 nonroot 계정이 없어 직접 만들어야 한다 — BCI micro/minimal 계열을 쓰는 다른 자체 빌드 이미지도 같은 작업이 필요하다.

재검토 조건

  • 업스트림이 v1.30.1 이상을 정식 릴리스하면 — 상위 태그 교체가 다시 가능해지므로 자체 빌드보다 우선한다.
  • release-1.30 의 기능 커밋 2개가 실제 회귀를 일으키면 — 기능 커밋 이전 시점 등 다른 pinned commit 으로 되돌린다.
  • SUSE 가 CNPG 호환 공식 오퍼레이터 이미지를 발행하면 — 자체 빌드가 불필요해진다.
  • bci-micro 에서 예기치 못한 런타임 문제(CA 신뢰 체인, TLS 등)가 나오면bci-base 로 승격하거나 다른 BCI 변종을 재검토한다.