Files
service-catalog/images/adc/README.md
T
wbsong111 18044210f6 apisix 카탈로그 CVE 게이트 완전 해소 (차단 165건 → 0건)
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>
2026-08-12 11:37:32 +09:00

6.9 KiB

adc — 자체 빌드

adc(APISIX/API7 관리 CLI, apisix-ingress-controller 의 사이드카) 를 업스트림 소스에서 SUSE BCI 위에 직접 빌드한다. manifests/helm/apisix/2.16.0/custom-values.yamlingress-controller.deployment.adcContainer.image.repository/tag가 이 산출물을 가리킨다.

자체 빌드는 대응 우선순위 3번이다. 상위 태그 교체·베이스 OS 교체로 목표를 만족할 수 있으면 그 쪽을 쓴다. 자체 빌드는 업스트림 서명·provenance·SBOM attestation 을 잃고 재빌드 책임을 지는 선택이다.

왜 자체 빌드하나 — "태그 교체로 끝난 줄 알았는데 아니었다"

apisix 카탈로그 CVE 조치 중 ghcr.io/api7/adc를 0.27.1 → 0.29.0(확인 시점 최신 태그) 으로 올렸다. 업스트림 0.29.0 릴리스 노트: "distroless 이미지로 전환해 베이스 이미지 취약점을 0으로 줄였다" — 실제로 trivy image 원시 스캔은 CRITICAL/HIGH 0/0 이 맞다.

하지만 이건 벤더 등급만 본 결과다. 카탈로그 게이트(scripts/pipeline/cve-gate.py) 는 max(벤더, NVD)로 재평가하는데, 이걸로 다시 돌리면 아래 4건이 실효 CRITICAL/HIGH 로 여전히 차단한다(2026-08-12 실측):

CVE 실효 등급 벤더 NVD 패키지 status
CVE-2019-1010022 CRITICAL LOW CRITICAL (9.8) libc6 affected, 수정 없음
CVE-2019-1010023 HIGH LOW HIGH (8.8) libc6 affected, 수정 없음
CVE-2018-20796 HIGH LOW HIGH (7.5) libc6 affected, 수정 없음
CVE-2019-9192 HIGH LOW HIGH (7.5) libc6 affected, 수정 없음

전부 2018~2019년 glibc regex/collating 스택오버플로 버그다. Debian 이 "affected, 수정 버전 없음"으로 영구 고정해뒀다 — cnpg-postgresql 자체 빌드 때 겪은 것과 완전히 같은 패턴("Debian 은 unimportant/no-dsa 로 판단해 안 고치는데 다른 배포판은 이미 백포트했음"). 이미 최신 태그(0.29.0)라 상위 태그 교체 레버는 소진됐고, 남은 건 베이스 OS 교체뿐이다.

SUSE 로 바꾸면 실제로 해소되는지 사전 검증

registry.suse.com/bci/bci-base:15.7 + zypper install nodejs24만으로 최소 이미지를 만들어 SBOM·스캔해봤다 — 위 4건이 전혀 안 잡힌다(2026-08-12 실측). SUSE 글리브C 에는 이미 고쳐져 있다는 뜻이다.

업스트림과 다르게 하는 부분 — 딱 한 줄

업스트림 Dockerfile(libs/tools/src/docker/Dockerfile, 태그 v0.29.0)은 2단계다:

FROM node:lts-bookworm-slim AS builder      # pnpm+nx 로 main.cjs 하나로 번들
...
FROM gcr.io/distroless/nodejs24-debian13:nonroot
COPY --from=builder /build/dist/apps/cli/main.cjs .
ENTRYPOINT [ "/nodejs/bin/node", "main.cjs" ]

빌더 스테이지(pnpm/nx 빌드)는 정책 대상이 아니라(.claude/image-authoring.md 원칙 2) 업스트림 그대로 재사용한다. 바뀌는 건 최종 스테이지 베이스 한 줄뿐이다:

  • gcr.io/distroless/nodejs24-debian13:nonrootregistry.suse.com/bci/bci-base:15.7
    • zypper install nodejs24(같은 Node 24 메이저 유지 — SUSE 표준 패키지라 cnpg-postgresql 때 겪은 openresty 전용 -devel 문제도 없다)
  • 엔트리포인트 경로 /nodejs/bin/node/usr/bin/node(zypper 설치 경로, 실측)
  • non-root 사용자: distroless :nonroot 태그 대신 명시적으로 adc 시스템 계정 생성

애플리케이션 코드(main.cjs 번들)는 업스트림과 100% 동일하다 — apisix/ apisix-ingress-controller 자체 빌드보다 훨씬 단순한 유형(cnpg-postgresql 과 같은 "OS 패키지 재설치형"에 가깝다 — 소스를 여러 모듈 컴파일하는 게 아니라 빌더 스테이지를 그대로 두고 런타임 베이스만 바꾼다). 실측 빌드 시간도 2분 이내(대부분 pnpm install+nx build 시간).

소스·버전 관리

항목
소스 https://github.com/api7/adc.git
pinned commit source.build.envSOURCE_COMMITv0.29.0 태그(lightweight, peeled 커밋 없음)가 가리키는 실제 커밋
빌더 업스트림과 동일한 node:lts-bookworm-slim — 정책 대상 아님(빌더 스테이지)
최종 베이스 registry.suse.com/bci/bci-base:15.7 + nodejs24

SOURCE_COMMIT자동 추적하지 않는다. 다른 자체 빌드 이미지와 동일하게, 사람이 업스트림 새 릴리스(또는 위 4건을 이미 해소한 버전)를 보고 source.build.env를 고쳐 PR을 여는 것 자체가 갱신 트리거다.

권장 점검 주기: 카탈로그 게이트가 이 이미지의 차단 CVE를 다시 보고할 때, 또는 api7/adc가 다음 릴리스를 내놓았을 때 — 릴리스가 나오면 그쪽으로 갈아타는 것(대응 우선순위 a)이 이 자체 빌드를 유지하는 것보다 항상 우선이다.

빌드

# 로컬 빌드 (push 없음)
IMAGE=adc BASE_OS=source bash scripts/build/build-hardened-image.sh /tmp/out

# 레지스트리에 push 까지
IMAGE=adc BASE_OS=source REGISTRY=docker.io/paasup \
  bash scripts/build/build-hardened-image.sh /tmp/out

수행 순서: 빌드 → 기능 검증(verify.sh) → SBOM → 전 심각도 스캔 → 게이트 판정. verify.sh는 non-root 실행 여부, --version 출력, --help의 커맨드 목록(dump/diff/ sync)을 확인한다 — adc 는 실제 APISIX/API7 백엔드 접속이 필요한 명령이 대부분이라 그 연동 자체는 이 스모크 범위 밖이다. dev 클러스터 배포 검증 (.claude/deploy-test-procedure.md)이 담당한다.

결과(2026-08-12 실측): 게이트 PASS, 커버리지 ok, 실효 CRITICAL/HIGH 0/0 (원본 4건에서 완전 해소). docker.io/paasup/adc:0.29.0-security-hardened-20260812 로 push 완료.

파일 구성

파일 역할
source.Dockerfile 빌드 정의 — 빌더 스테이지(업스트림 그대로) + SUSE BCI 최종 스테이지
source.build.env pinned commit·버전(BUILD_ARGS에 나열한 이름만 --build-arg 로 전달됨)
verify.sh 기능 검증 — non-root·버전·--help 커맨드 확인

베이스 변종이 하나뿐이라 파일명이 source.* 로 고정돼 있다.

태그

docker.io/paasup/adc:0.29.0-security-hardened-20260812
                      └ app ┘└ 슬러그 ┘└ 하드닝 ┘└ 빌드일 ┘

아직 안 한 것 — 배포 검증

게이트 PASS·기능 스모크테스트(버전+help)까지만 확인했다. apisix-ingress-controller 와 함께 실제 APISIX/API7 백엔드에 접속해 dump/diff/sync 가 정상 동작하는지는 아직 확인하지 않았다.claude/deploy-test-procedure.md 절차로 카탈로그 반영 전 반드시 수행할 것(apisix-ingress-controller 자체 빌드는 이미 이 절차로 배포 검증 완료됨 — 같은 방식으로 진행).