Files
service-catalog/images/apisix-ingress-controller/source.Dockerfile
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

99 lines
5.9 KiB
Docker

# apisix-ingress-controller — 업스트림 소스를 pinned commit(v2.1.0 태그)으로 직접
# 컴파일하고, 취약한 전이 의존성만 강제로 올린다(cloudnative-pg/etcd 자체 빌드와 동일한
# 패턴). 업스트림 루트 Dockerfile 은 이미 빌드된 바이너리를 COPY 만 한다 — 컴파일 자체는
# Makefile 의 `build`/`build-multi-arch` 타겟(`CGO_ENABLED=0 go build ...`)이 한다. 그
# 빌드 단계를 Dockerfile 안으로 가져와 재현한다.
#
# 왜 자체 빌드인가 — apache/apisix-ingress-controller:2.1.0(2026-05-29 빌드, 현재 최신
# 태그)이 게이트에서 차단하는 CRITICAL/HIGH 25건 중 21건이 OS 패키지가 아니라 바이너리에
# 정적 링크된 Go 모듈(stdlib, golang.org/x/net, golang.org/x/text, google.golang.org/grpc,
# go.opentelemetry.io/otel[/sdk])이 원인이다(2026-08-11 실측, apisix 카탈로그 CVE 조치).
# 이미 최신 태그라 상위 태그 교체가 불가능하고, 베이스가 distroless(cc-debian12)라
# libc6/libssl3 OS 패키지 4건만 베이스 교체로 잡히고 나머지는 못 잡는다 — 자체 빌드가
# 유일한 대응이다.
#
# 업스트림과 다르게 하는 부분 — 취약 모듈만 강제 업그레이드(go.work 가 없는 단일 모듈
# 프로젝트라 etcd 처럼 워크스페이스 전역 replace 를 못 쓴다. `go get`+`go mod tidy` 로
# 대신한다). 애플리케이션 코드 자체는 v2.1.0 태그 그대로다 — master 는 릴리스 이후 기능
# 커밋이 다수 섞여 있어(2026-08-11 기준 태그 대비 35커밋 앞섬) 최소 diff 원칙에 맞지 않아
# 쓰지 않았다.
# golang.org/x/net v0.47.0 -> v0.56.0 (CVE-2026-25681/27136/39821 등)
# golang.org/x/text v0.31.0 -> v0.39.0 (CVE-2026-56852)
# google.golang.org/grpc v1.71.1 -> v1.82.1 (CVE-2026-33186, GHSA-hrxh-6v49-42gf)
# go.opentelemetry.io/otel v1.40.0 -> v1.43.0 (CVE-2026-29181)
# go.opentelemetry.io/otel/sdk v1.40.0 -> v1.43.0 (CVE-2026-39883, otel 코어와 버전 동기 필요)
# 이 조합은 `go get` 가 알아서 서로 호환되는 최소 버전으로 끌어올린다(go mod tidy 로 확정) —
# 로컬에서 go build 성공 실측 완료(2026-08-11).
#
# gcr.io/distroless/cc-debian12 → SUSE BCI(bci-micro)로 교체. 카탈로그는 SUSE BCI
# 하나만 쓴다(.claude/image-authoring.md 원칙 2) — builder 스테이지는 공식 golang
# 이미지를 그대로 쓴다. CGO_ENABLED=0 정적 바이너리라 cc(glibc 포함) 변형이 애초에
# 필요 없었다 — 업스트림이 왜 cc 를 쓰는지는 불명(안전 마진으로 추정), static 대비
# 이점이 없어 우리는 bci-micro 로 통일한다.
#
# ldflags — 업스트림 Makefile 의 GO_LDFLAGS 를 그대로 재현한다(internal/version 패키지의
# 빌드타임 심볼 4개). GitSHA 자리에는 pinned commit 전체 해시를 심어 verify.sh 가 컨테이너
# 안에서 git 을 실행하지 않고도 버전 문자열로 확인할 수 있게 한다(etcd/cloudnative-pg 와
# 동일한 이유).
# syntax=docker/dockerfile:1
ARG GO_BUILDER_TAG=1.26.5-trixie
# FROM 에서 쓰는 ARG 는 반드시 첫 FROM 이전(전역 스코프)에 선언해야 한다 — .claude/image-authoring.md.
ARG RUNTIME_BASE=registry.suse.com/bci/bci-micro:15.7
FROM --platform=$BUILDPLATFORM golang:${GO_BUILDER_TAG} AS builder
ARG TARGETARCH
ARG SOURCE_COMMIT
ARG APP_VERSION
ARG MIN_K8S_VERSION
ARG XNET_FIX_VERSION
ARG XTEXT_FIX_VERSION
ARG GRPC_FIX_VERSION
ARG OTEL_FIX_VERSION
WORKDIR /src
# BuildKit 의 git context 지원 — tarball+checksum 관리 없이 git 자체가 커밋 무결성을 보장한다.
ADD https://github.com/apache/apisix-ingress-controller.git#${SOURCE_COMMIT} /src
# 취약 전이 의존성만 최소 버전으로 강제 업그레이드한다(위 설명 참고). otel/otel-sdk 는
# 서로 버전이 맞아야 해서 함께 지정한다 — go get 이 나머지 호환 버전을 알아서 정리한다.
RUN --mount=type=cache,target=/root/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go get \
golang.org/x/net@v${XNET_FIX_VERSION} \
golang.org/x/text@v${XTEXT_FIX_VERSION} \
google.golang.org/grpc@v${GRPC_FIX_VERSION} \
go.opentelemetry.io/otel@v${OTEL_FIX_VERSION} \
go.opentelemetry.io/otel/sdk@v${OTEL_FIX_VERSION} \
&& go mod tidy
# 업스트림 Makefile 의 build 타겟을 그대로 재현한다(GOARCH 는 TARGETARCH 로 대체, GitSHA
# 자리에 pinned commit 전체 해시를 심는다 — 위 설명 참고).
RUN --mount=type=cache,target=/root/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
set -eux; \
mkdir -p /out; \
VERSYM="github.com/apache/apisix-ingress-controller/internal/version._buildVersion"; \
GITSHASYM="github.com/apache/apisix-ingress-controller/internal/version._buildGitRevision"; \
BUILDOSSYM="github.com/apache/apisix-ingress-controller/internal/version._buildOS"; \
MINK8SVERSYM="github.com/apache/apisix-ingress-controller/internal/manager._minK8sVersion"; \
LDFLAGS="-X=${VERSYM}=${APP_VERSION} -X=${GITSHASYM}=${SOURCE_COMMIT} -X=${BUILDOSSYM}=linux/${TARGETARCH} -X=${MINK8SVERSYM}=${MIN_K8S_VERSION}"; \
CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -trimpath -ldflags="${LDFLAGS}" -o /out/apisix-ingress-controller cmd/main.go
FROM ${RUNTIME_BASE} AS final
# 업스트림과 동일한 경로 — Helm 차트가 별도 경로를 하드코딩하지 않으므로 필수는 아니지만
# 업스트림 Dockerfile 과의 대응을 그대로 유지한다.
WORKDIR /app
COPY --from=builder /out/apisix-ingress-controller ./apisix-ingress-controller
COPY --from=builder /src/LICENSE /licenses/LICENSE
COPY --from=builder /src/NOTICE /licenses/NOTICE
# 업스트림은 distroless `:nonroot` 태그로 65532:65532 를 기본 사용자로 쓴다 — bci-micro 는
# 그런 태그 변형이 없어 명시적으로 지정한다.
USER 65532:65532
ENTRYPOINT ["/app/apisix-ingress-controller"]
CMD ["-c", "/app/conf/config.yaml"]