# 0002. cloudnative-pg 오퍼레이터를 소스 컴파일 자체 빌드로 대체하고, 자체 빌드 오케스트레이션을 하나로 통일한다 - 날짜: 2026-07-30 (결정) · 2026-08-04 (`docker.io/paasup` 로 재빌드) - 상태: 확정 - 원본: security-catalog ADR 0005 — dip-catalog 맥락으로 다시 썼다([README](README.md) 참고) ## 결정 `manifests/helm/cloudnative-pg/0.29.0` 의 오퍼레이터 이미지를 자체 빌드로 한다. 현재 태그는 [custom-values.yaml](../../manifests/helm/cloudnative-pg/0.29.0/custom-values.yaml) 의 `image.repository`/`image.tag` 가 단일 출처이고, 빌드 정의는 [images/cloudnative-pg/](../../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](../../.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_` **파일 존재**로 판단하는데, 업스트림의 멀티아치 심볼릭 링크를 "부수 장치" 로 오판해 제거했기 때문이다. 같은 바이너리를 `/manager` 와 `/operator/manager_amd64` 양쪽에 COPY 해 해결했다. - **베이스 OS 는 BCI 로 통일한다는 결정([0001](0001-cnpg-postgresql-image.md))이 이 이미지에도 적용된다.** 최초 설계는 "업스트림과 최대한 동일하게" 를 따라 distroless 를 그대로 썼으나 카탈로그 정책과 어긋나 `bci-micro` 로 교체했고, 교체 후에도 게이트·배포 검증 PASS 를 유지하는 것을 확인했다. - **오케스트레이션 통일이 회귀를 만들지 않는 것을 확인했다** — 스크립트를 일반화한 직후 기존 `cnpg-postgresql` 을 다시 빌드해 태그·게이트 결과가 동일함을 확인했다. ## 받아들인 비용 - **업스트림 서명·provenance·SBOM attestation 을 잃는다.** ADR [0001](0001-cnpg-postgresql-image.md) 과 동일한 비용이다. - **`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-micro` 는 `bci-base` 와 달리 nonroot 계정이 없어 직접 만들어야 한다** — BCI micro/minimal 계열을 쓰는 다른 자체 빌드 이미지도 같은 작업이 필요하다. ## 재검토 조건 - **업스트림이 `v1.30.1` 이상을 정식 릴리스하면** — 상위 태그 교체가 다시 가능해지므로 자체 빌드보다 우선한다. - **`release-1.30` 의 기능 커밋 2개가 실제 회귀를 일으키면** — 기능 커밋 이전 시점 등 다른 pinned commit 으로 되돌린다. - **SUSE 가 CNPG 호환 공식 오퍼레이터 이미지를 발행하면** — 자체 빌드가 불필요해진다. - **`bci-micro` 에서 예기치 못한 런타임 문제(CA 신뢰 체인, TLS 등)가 나오면** — `bci-base` 로 승격하거나 다른 BCI 변종을 재검토한다.