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>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# argocd (자체 빌드)
|
||||
|
||||
`quay.io/argoproj/argocd` 를 대체하는 하드닝 이미지. 업스트림 소스를 pinned commit 으로
|
||||
직접 컴파일하고, 업스트림이 릴리스 바이너리로 내려받던 번들 도구(helm·kustomize·git-lfs)까지
|
||||
같은 Go 툴체인으로 다시 만든다.
|
||||
|
||||
```sh
|
||||
IMAGE=argocd BASE_OS=source bash scripts/build/build-hardened-image.sh /tmp/out
|
||||
```
|
||||
|
||||
## 왜 자체 빌드인가
|
||||
|
||||
이 이미지의 차단 CVE 는 대부분 OS 패키지가 아니라 **바이너리에 정적 링크된 Go 모듈**이다.
|
||||
그래서 앞선 두 레버가 모두 통하지 않는다.
|
||||
|
||||
- **상위 태그 교체 불가** — 이미 최신 릴리스다. 번들 도구도 각각 최신이고, 낡은 Go 는
|
||||
각 업스트림 프로젝트의 선택이라 버전을 올려도 바뀌지 않는다.
|
||||
- **베이스 OS 교체로는 거의 안 잡힌다** — 모듈은 컴파일된 바이너리 안에 있다.
|
||||
|
||||
## 왜 번들 도구까지 다시 만드는가
|
||||
|
||||
업스트림 Dockerfile 은 helm/kustomize/git-lfs 를 `hack/install.sh` 로 **미리 빌드된 릴리스
|
||||
바이너리를 내려받아** 넣는다. 그 바이너리의 Go 버전은 우리가 통제할 수 없다.
|
||||
|
||||
그리고 **부분 조치는 효과가 없다.** 같은 `stdlib`·`x/crypto` 취약점이 다섯 바이너리에 각각
|
||||
들어있어서, 한 바이너리만 고치면 나머지에 그대로 남는다. 고유 CVE 는 소수이고 대부분이
|
||||
공유분이라 전부 다시 만들어야 게이트가 0 이 된다(실측 확인 — argocd 본체만 조치했을 때는
|
||||
거의 줄지 않았다).
|
||||
|
||||
`pebble` 은 우리가 넣은 것이 아니라 ubuntu 베이스에 딸려온 것이다 — 베이스를 SUSE BCI 로
|
||||
바꾸면 함께 사라진다.
|
||||
|
||||
## 다음 CVE 조치 — Dockerfile 은 건드리지 않는다
|
||||
|
||||
버전도 모듈 목록도 Dockerfile 에 박혀 있지 않다. 새 차단 CVE 가 나오면 **`source.build.env`
|
||||
한 곳만** 바뀐다.
|
||||
|
||||
```sh
|
||||
# 1) 게이트 리포트에서 업그레이드 값을 산출한다 (손으로 찾지 않는다)
|
||||
python3 scripts/build/suggest-go-upgrades.py --reports sbom-out/trivy-reports --image argocd
|
||||
|
||||
# 2) 출력된 GO_MODULE_UPGRADES / GO_BUILDER_TAG 를 source.build.env 에 반영
|
||||
|
||||
# 3) 재빌드 — 게이트까지 한 번에 돈다
|
||||
IMAGE=argocd BASE_OS=source bash scripts/build/build-hardened-image.sh /tmp/out
|
||||
```
|
||||
|
||||
| 새 CVE 유형 | 바꾸는 값 |
|
||||
|---|---|
|
||||
| Go `stdlib` | `GO_BUILDER_TAG` |
|
||||
| Go 모듈 | `GO_MODULE_UPGRADES` 에 `<module>@<version>` 추가 |
|
||||
| OS 패키지 | `RUNTIME_BASE` 또는 `RUNTIME_PACKAGES` |
|
||||
| 구성요소 새 릴리스 | 해당 `*_VERSION` |
|
||||
|
||||
`GO_MODULE_UPGRADES` 는 argocd·helm·kustomize·git-lfs **네 프로젝트에 공통 적용**된다.
|
||||
[go-mod-upgrade.sh](go-mod-upgrade.sh) 가 각 프로젝트의 의존성 그래프에 있는 것만 골라
|
||||
적용하므로 목록 하나를 그대로 재사용한다 — `go get` 은 의존성에 없는 모듈도 `go.mod` 에
|
||||
추가해버리기 때문에 필요한 필터다.
|
||||
|
||||
> 제안값은 CVE 요건의 **최소치**다. 모듈 간 제약으로 더 올려야 할 수 있다 — 빌드가
|
||||
> `requires <module>@vX, not @vY` 로 실패하면 그 버전으로 올린다.
|
||||
|
||||
## 업스트림과 다르게 한 부분
|
||||
|
||||
| 항목 | 업스트림 | 이 이미지 | 이유 |
|
||||
|---|---|---|---|
|
||||
| 최종 베이스 | `ubuntu` | `registry.suse.com/bci/bci-base` | 카탈로그는 SUSE BCI 하나만 쓴다(`.claude/image-authoring.md` 원칙 2). `pebble` 도 함께 소멸 |
|
||||
| helm / kustomize / git-lfs | 릴리스 바이너리 다운로드 | 소스 컴파일 | 다운로드 바이너리의 Go 를 통제할 수 없다 |
|
||||
| helm 버전 | 업스트림 pin | 최신 | kustomize·git-lfs 는 pin 이 이미 최신이라 그대로 |
|
||||
| `tini` · `connect-proxy` | apt 패키지 | 소스 빌드 | SLE_BCI 에 둘 다 없다. 기능을 빼지 않기 위해 빌드 |
|
||||
| Go 툴체인 | 업스트림 pin | `GO_BUILDER_TAG` | stdlib CVE 해소 |
|
||||
| 취약 모듈 | 그대로 | `GO_MODULE_UPGRADES` 로 강제 업그레이드 | |
|
||||
| `BUILD_DATE` | 빌드 시각 | 고정값 | 빌드 재현성 |
|
||||
| UI | node 빌드 | **동일** | Go embed 로 바이너리에 들어가 생략 불가 |
|
||||
|
||||
애플리케이션 코드 자체는 pinned 태그 그대로다 — 최소 diff 원칙.
|
||||
|
||||
## SLE 패키지 매핑
|
||||
|
||||
업스트림 apt 목록을 SLE_BCI 이름으로 옮겼다(`.claude/image-authoring.md` 참고).
|
||||
목록 자체는 `source.build.env` 의 `RUNTIME_PACKAGES` 에 있다.
|
||||
|
||||
| ubuntu | SLE_BCI |
|
||||
|---|---|
|
||||
| `git` | `git-core` |
|
||||
| `tzdata` | `timezone` |
|
||||
| `gpg` · `gpg-agent` | `gpg2` |
|
||||
| `openssh-client` | `openssh-clients` |
|
||||
| `ca-certificates` | `ca-certificates` (동일) |
|
||||
| `tini` | **없음** → 소스 빌드 |
|
||||
| `connect-proxy` | **없음** → 소스 빌드 |
|
||||
|
||||
## 검증
|
||||
|
||||
`verify.sh` 가 보는 것 — argocd 버전 문자열, 업스트림 심볼릭 링크 9개, 번들 도구 3개의
|
||||
버전, tini·connect-proxy 실행 가능, git/gpg/ssh 존재, `/etc/gitconfig` 의 LFS 필터,
|
||||
`/app/config` 디렉토리 구조와 래퍼 스크립트.
|
||||
|
||||
**게이트 PASS 는 "동작한다" 를 증명하지 않는다.** 실제 기동은 Kubernetes API 가 필요해
|
||||
스모크 범위 밖이다 — dev 클러스터 배포 검증을 반드시 한다.
|
||||
|
||||
```sh
|
||||
VALUES_FILE=<values> bash scripts/deploy-test/deploy-test-argo-cd.sh /tmp/deploy-test-argocd
|
||||
```
|
||||
@@ -0,0 +1,18 @@
|
||||
# build-image.yml 이 읽는 카탈로그 반영 메타데이터. 빌드 정의(<variant>.build.env)와는
|
||||
# 별개다 — 이건 "이 이미지가 어느 차트의 어느 필드를 가리키는가" 만 담는다.
|
||||
#
|
||||
# argo-cd 카탈로그는 10.4.0(현재 운영)과 7.8.11(직전)을 보관한다. 자체 빌드 이미지는
|
||||
# 운영 버전에만 반영한다 — 7.8.11 은 released 로 동결하고 손대지 않는다
|
||||
# (7.7.0 은 2026-08-19 삭제).
|
||||
CHART_DIRS="manifests/helm/argo-cd/10.4.0"
|
||||
|
||||
# 태그 표기 스타일 — imageName(단일 필드 문자열) | split(registry/repository/tag 분리)
|
||||
TAG_STYLE=split
|
||||
|
||||
# argo-cd 차트는 모든 컴포넌트(server/repo-server/controller/applicationset/notifications)가
|
||||
# global.image.{repository,tag} 하나를 공유한다 — 컴포넌트별 image 블록은 기본이 비어 있고
|
||||
# 비면 global 을 상속한다. 그래서 이 한 곳만 갱신하면 전부 바뀐다.
|
||||
TAG_BLOCK=global.image
|
||||
|
||||
# base_os 입력을 안 주면 쓸 기본 변종 (images/<image>/<DEFAULT_BASE_OS>.build.env)
|
||||
DEFAULT_BASE_OS=source
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env sh
|
||||
# go-mod-upgrade — CVE 대응으로 강제 업그레이드할 Go 모듈 목록을 현재 모듈에 적용한다.
|
||||
# 빌더 스테이지에서 각 Go 프로젝트 디렉토리에 들어간 뒤 인자 없이 호출한다.
|
||||
#
|
||||
# 왜 스크립트로 빼는가
|
||||
# --------------------
|
||||
# 업그레이드 대상을 Dockerfile 에 직접 나열하면, 새 CVE 가 하나 나올 때마다
|
||||
# ① build.env 에 <MOD>_FIX_VERSION 추가 ② Dockerfile 의 ARG 선언 추가(스테이지마다)
|
||||
# ③ go get 목록에 추가(빌드 대상마다) ④ BUILD_ARGS 에 이름 추가
|
||||
# 네 곳을 고쳐야 한다. 목록을 GO_MODULE_UPGRADES 값 하나로 받으면 **build.env 한 줄만**
|
||||
# 바뀌고 Dockerfile 은 그대로다 — 이 이미지는 앞으로도 CVE 조치를 반복해서 받는다.
|
||||
#
|
||||
# 목록에 있으나 이 프로젝트가 쓰지 않는 모듈은 건너뛴다
|
||||
# ----------------------------------------------------
|
||||
# 한 이미지 안에서 여러 Go 프로젝트(argocd·helm·kustomize·git-lfs)를 빌드하는데 각자
|
||||
# 의존성이 다르다. `go get` 은 의존성 그래프에 없는 모듈도 go.mod 에 요구사항으로
|
||||
# **추가**하므로(뒤이은 go mod tidy 가 지우긴 하지만) 애초에 넣지 않는 편이 의도가 분명하고,
|
||||
# 목록 하나를 네 프로젝트에 그대로 재사용할 수 있다.
|
||||
#
|
||||
# 형식: 공백으로 구분한 `<module path>@<version>` 목록.
|
||||
# GO_MODULE_UPGRADES="golang.org/x/net@v0.56.0 google.golang.org/grpc@v1.82.1"
|
||||
set -eu
|
||||
|
||||
if [ -z "${GO_MODULE_UPGRADES:-}" ]; then
|
||||
echo "go-mod-upgrade: GO_MODULE_UPGRADES 가 비어 있다 — 업그레이드 없이 진행"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
targets=""
|
||||
for spec in $GO_MODULE_UPGRADES; do
|
||||
path="${spec%@*}"
|
||||
if [ "$path" = "$spec" ]; then
|
||||
echo "go-mod-upgrade: ::error:: '$spec' 에 @<version> 이 없다"
|
||||
exit 2
|
||||
fi
|
||||
if go list -m "$path" >/dev/null 2>&1; then
|
||||
targets="$targets $spec"
|
||||
echo "go-mod-upgrade: 적용 $spec"
|
||||
else
|
||||
echo "go-mod-upgrade: 건너뜀 $path (이 프로젝트의 의존성 그래프에 없음)"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$targets" ]; then
|
||||
echo "go-mod-upgrade: 적용 대상 없음"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086 # targets 는 공백 구분 목록이라 의도적으로 분리한다
|
||||
go get $targets
|
||||
go mod tidy
|
||||
@@ -0,0 +1,263 @@
|
||||
# argocd — 업스트림 소스를 pinned commit 으로 직접 컴파일하고, 번들되는 Go 도구
|
||||
# (helm/kustomize/git-lfs)까지 같은 툴체인으로 다시 만든다.
|
||||
#
|
||||
# 왜 자체 빌드인가
|
||||
# ----------------
|
||||
# 이 이미지의 차단 CVE 는 대부분 OS 패키지가 아니라 **바이너리에 정적 링크된 Go 모듈**이다.
|
||||
# 상위 태그 교체(이미 최신)로도, 베이스 OS 교체(모듈은 바이너리 안에 있다)로도 잡히지 않아
|
||||
# 자체 빌드만 남는다.
|
||||
#
|
||||
# 왜 번들 도구까지 다시 만드는가
|
||||
# ------------------------------
|
||||
# 업스트림 Dockerfile 은 helm/kustomize/git-lfs 를 hack/install.sh 로 **미리 빌드된 릴리스
|
||||
# 바이너리를 내려받아** 넣는다. 그 바이너리의 Go 버전은 각 프로젝트가 정한 것이라 우리가
|
||||
# 태그를 올려도 바뀌지 않는다.
|
||||
#
|
||||
# 그리고 부분 조치는 효과가 없다 — 같은 stdlib·x/crypto 취약점이 다섯 바이너리에 각각
|
||||
# 들어있어서, 한 바이너리만 고치면 나머지에 그대로 남는다. 고유 CVE 는 소수이고 대부분이
|
||||
# 공유분이다. 전부 다시 만들어야 게이트가 0 이 된다(실측 확인).
|
||||
#
|
||||
# 재사용 설계 — Dockerfile 에 버전을 박지 않는다
|
||||
# ---------------------------------------------
|
||||
# 이 이미지는 앞으로도 CVE 조치를 반복해서 받는다. 다음 조치에서 바뀌는 것은 전부
|
||||
# source.build.env 값이다:
|
||||
#
|
||||
# GO_MODULE_UPGRADES 강제 업그레이드할 Go 모듈 목록 (네 프로젝트에 공통 적용)
|
||||
# GO_BUILDER_TAG Go 툴체인 (stdlib CVE 해소)
|
||||
# *_VERSION 각 구성요소 버전
|
||||
# RUNTIME_PACKAGES 최종 이미지에 설치할 SLE 패키지
|
||||
#
|
||||
# 값은 scripts/build/suggest-go-upgrades.py 가 스캔 리포트에서 산출한다 — 사람이 CVE 를
|
||||
# 훑어 최대값을 고르지 않는다. 모듈 목록은 go-mod-upgrade.sh 가 프로젝트마다 "그 프로젝트가
|
||||
# 실제로 쓰는 것만" 골라 적용하므로 목록 하나를 네 프로젝트에 그대로 재사용한다.
|
||||
#
|
||||
# 업스트림과 다르게 하는 부분
|
||||
# ---------------------------
|
||||
# ubuntu → SUSE BCI(bci-base). 카탈로그는 SUSE BCI 하나만 쓴다
|
||||
# (.claude/image-authoring.md 원칙 2). argocd 는 git/gpg/ssh 런타임이 필요해 패키지
|
||||
# 매니저가 있는 base 를 쓴다(micro 씨앗 방식의 복잡도를 감수할 이점이 없었다).
|
||||
# ubuntu 베이스가 딸려오던 pebble 바이너리도 함께 사라진다.
|
||||
# tini·connect-proxy 는 SLE_BCI 에 패키지가 없어 소스에서 빌드한다.
|
||||
# helm/kustomize/git-lfs 를 릴리스 바이너리 다운로드 → 소스 컴파일로 교체.
|
||||
# UI 는 업스트림과 동일하게 node 로 빌드한다 — Go embed 로 바이너리에 들어가 생략 불가.
|
||||
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# FROM 에서 쓰는 ARG 는 반드시 첫 FROM 이전(전역 스코프)에 선언해야 한다 —
|
||||
# 스테이지 안에 두면 지역 변수가 되어 이후 FROM 의 이미지명이 빈 값이 된다
|
||||
# (.claude/image-authoring.md).
|
||||
ARG GO_BUILDER_TAG=1.26.6-trixie
|
||||
ARG NODE_BUILDER_TAG=24.14.1
|
||||
ARG RUNTIME_BASE=registry.suse.com/bci/bci-base:15.7
|
||||
|
||||
####################################################################################################
|
||||
# UI — 업스트림 argocd-ui 스테이지를 그대로 재현한다. 산출물이 Go embed 로 바이너리에 들어간다.
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/node:${NODE_BUILDER_TAG} AS argocd-ui
|
||||
|
||||
ARG SOURCE_COMMIT
|
||||
ARG APP_VERSION
|
||||
ADD https://github.com/argoproj/argo-cd.git#${SOURCE_COMMIT} /src
|
||||
|
||||
# 업스트림과 동일: corepack 으로 pnpm 을 켜고 lockfile 그대로 설치한다.
|
||||
WORKDIR /src/ui
|
||||
RUN npm install -g corepack@0.34.6 && corepack enable && pnpm install --frozen-lockfile
|
||||
|
||||
# UI 번들은 아키텍처 무관이다 — 업스트림 주석대로 TARGETARCH 를 쓰지 않는다.
|
||||
ENV ARGO_VERSION=$APP_VERSION
|
||||
RUN NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 pnpm build
|
||||
|
||||
####################################################################################################
|
||||
# 번들 Go 도구 — 업스트림이 릴리스 바이너리로 받아오던 것을 소스에서 다시 컴파일한다.
|
||||
#
|
||||
# 새 툴체인으로 다시 컴파일하면 stdlib 은 해소되지만 각 프로젝트가 go.mod 에 pin 한 모듈은
|
||||
# 그대로 낡아 있다 — 도구 쪽 모듈을 빠뜨려 게이트가 실패한 적이 있다(실측). 그래서 argocd
|
||||
# 본체와 같은 GO_MODULE_UPGRADES 를 세 도구에도 적용한다.
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_BUILDER_TAG} AS go-tools
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG HELM_VERSION
|
||||
ARG KUSTOMIZE_VERSION
|
||||
ARG GIT_LFS_VERSION
|
||||
ARG GO_MODULE_UPGRADES
|
||||
ENV CGO_ENABLED=0 GOOS=linux GO_MODULE_UPGRADES=${GO_MODULE_UPGRADES}
|
||||
COPY go-mod-upgrade.sh /usr/local/bin/go-mod-upgrade
|
||||
RUN chmod 0755 /usr/local/bin/go-mod-upgrade
|
||||
WORKDIR /out
|
||||
|
||||
# helm — 업스트림 Makefile 의 ldflags(version/gitTreeState)를 재현한다.
|
||||
ADD https://github.com/helm/helm.git#v${HELM_VERSION} /src/helm
|
||||
RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/helm && go-mod-upgrade && \
|
||||
P=helm.sh/helm/v4/internal/version && \
|
||||
GOARCH=${TARGETARCH} go build -trimpath \
|
||||
-ldflags "-X ${P}.version=v${HELM_VERSION} -X ${P}.gitTreeState=clean" \
|
||||
-o /out/helm ./cmd/helm
|
||||
|
||||
# kustomize — 리포 안의 kustomize/ 서브모듈이 CLI 다.
|
||||
ADD https://github.com/kubernetes-sigs/kustomize.git#kustomize/v${KUSTOMIZE_VERSION} /src/kustomize
|
||||
RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/kustomize/kustomize && go-mod-upgrade && \
|
||||
P=sigs.k8s.io/kustomize/api/provenance && \
|
||||
GOARCH=${TARGETARCH} go build -trimpath \
|
||||
-ldflags "-X ${P}.version=v${KUSTOMIZE_VERSION}" \
|
||||
-o /out/kustomize .
|
||||
|
||||
# git-lfs — Makefile 이 ldflags 로 버전을 심는다.
|
||||
ADD https://github.com/git-lfs/git-lfs.git#v${GIT_LFS_VERSION} /src/git-lfs
|
||||
RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
|
||||
cd /src/git-lfs && go-mod-upgrade && \
|
||||
GOARCH=${TARGETARCH} go build -trimpath \
|
||||
-ldflags "-X github.com/git-lfs/git-lfs/v3/config.GitCommit=v${GIT_LFS_VERSION}" \
|
||||
-o /out/git-lfs .
|
||||
|
||||
####################################################################################################
|
||||
# argocd 본체 — 업스트림 argocd-build 스테이지 + 취약 모듈 강제 업그레이드
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_BUILDER_TAG} AS argocd-build
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG SOURCE_COMMIT
|
||||
ARG APP_VERSION
|
||||
ARG GO_MODULE_UPGRADES
|
||||
ENV GO_MODULE_UPGRADES=${GO_MODULE_UPGRADES}
|
||||
COPY go-mod-upgrade.sh /usr/local/bin/go-mod-upgrade
|
||||
RUN chmod 0755 /usr/local/bin/go-mod-upgrade
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
ADD https://github.com/argoproj/argo-cd.git#${SOURCE_COMMIT} .
|
||||
|
||||
RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
|
||||
go-mod-upgrade
|
||||
|
||||
COPY --from=argocd-ui /src/ui/dist/app ./ui/dist/app
|
||||
|
||||
# 업스트림 Dockerfile 과 동일하게 Makefile 의 argocd-all 타겟을 부른다
|
||||
# (단일 `go build -o dist/argocd ./cmd`). 버전 심볼은 Makefile 이 ldflags 로 심는다.
|
||||
# BUILD_DATE 를 고정해 빌드 재현성을 확보한다(업스트림은 date 를 그때그때 넣는다).
|
||||
RUN --mount=type=cache,target=/root/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \
|
||||
GIT_TAG=v${APP_VERSION} \
|
||||
GIT_COMMIT=${SOURCE_COMMIT} \
|
||||
GIT_TREE_STATE=clean \
|
||||
BUILD_DATE=1970-01-01T00:00:00Z \
|
||||
GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
|
||||
make argocd-all
|
||||
|
||||
####################################################################################################
|
||||
# C 도구 — SLE_BCI 에 패키지가 없어 소스에서 빌드한다(2026-08-19 zypper 실측)
|
||||
####################################################################################################
|
||||
FROM ${RUNTIME_BASE} AS c-builder
|
||||
|
||||
ARG TINI_VERSION
|
||||
ARG SSH_CONNECT_VERSION
|
||||
ARG BUILDER_PACKAGES
|
||||
# SLE_BCI 미러가 간헐적으로 끊긴다(실측: curl error 56 / SSL unexpected eof). 재시도한다.
|
||||
RUN for i in 1 2 3 4 5; do \
|
||||
zypper --non-interactive --gpg-auto-import-keys refresh && break; \
|
||||
echo "zypper refresh 실패 — 재시도 $i"; sleep 10; \
|
||||
done && \
|
||||
zypper --non-interactive install -y --no-recommends ${BUILDER_PACKAGES} && \
|
||||
zypper --non-interactive clean --all
|
||||
|
||||
# tini — 업스트림 argocd 의 ENTRYPOINT(["/usr/bin/tini", "--"]).
|
||||
# 동적 링크로 빌드한다. 이 스테이지와 final 이 같은 BCI 베이스라 glibc ABI 가 동일하고,
|
||||
# 업스트림이 쓰는 apt tini 도 동적 링크다. 정적 링크는 SLE_BCI 에 정적 glibc 가 없어
|
||||
# 애초에 불가능하다(2026-08-19 실측: "cannot find -lc ... static version of the c library").
|
||||
ADD https://github.com/krallin/tini.git#v${TINI_VERSION} /src/tini
|
||||
RUN cd /src/tini && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release . && \
|
||||
make tini && \
|
||||
install -m 0755 tini /out-tini
|
||||
|
||||
# connect-proxy — Debian 의 connect-proxy 패키지 원본(gotoh/ssh-connect 의 connect.c).
|
||||
# SSH-over-proxy 환경에서 git 이 쓴다. 기능을 빼지 않기 위해 빌드한다.
|
||||
ADD https://github.com/gotoh/ssh-connect.git#${SSH_CONNECT_VERSION} /src/connect
|
||||
RUN cd /src/connect && \
|
||||
gcc -O2 -o /out-connect connect.c
|
||||
|
||||
####################################################################################################
|
||||
# 최종 이미지 — 업스트림 argocd-base + final 을 SUSE BCI 위에서 재현한다
|
||||
####################################################################################################
|
||||
FROM ${RUNTIME_BASE} AS final
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/argoproj/argo-cd"
|
||||
|
||||
ARG RUNTIME_PACKAGES
|
||||
ENV ARGOCD_USER_ID=999
|
||||
|
||||
# RUNTIME_PACKAGES 는 업스트림 apt 목록을 SLE 이름으로 옮긴 것이다. 이름이 다른 것들:
|
||||
# git → git-core tzdata → timezone gpg/gpg-agent → gpg2 openssh-client → openssh-clients
|
||||
# tini·connect-proxy 는 SLE_BCI 에 없어 c-builder 에서 빌드해 COPY 한다.
|
||||
# SLE_BCI 미러가 간헐적으로 끊긴다(실측). 재시도한다.
|
||||
RUN for i in 1 2 3 4 5; do \
|
||||
zypper --non-interactive --gpg-auto-import-keys refresh && break; \
|
||||
echo "zypper refresh 실패 — 재시도 $i"; sleep 10; \
|
||||
done && \
|
||||
zypper --non-interactive update -y && \
|
||||
zypper --non-interactive install -y --no-recommends ${RUNTIME_PACKAGES} && \
|
||||
zypper --non-interactive clean --all && \
|
||||
rm -rf /var/log/zypp /usr/share/doc/packages/*
|
||||
|
||||
RUN groupadd -g $ARGOCD_USER_ID argocd && \
|
||||
useradd -r -u $ARGOCD_USER_ID -g argocd argocd && \
|
||||
mkdir -p /home/argocd && \
|
||||
chown argocd:0 /home/argocd && \
|
||||
chmod g=u /home/argocd
|
||||
|
||||
COPY --from=c-builder /out-tini /usr/bin/tini
|
||||
COPY --from=c-builder /out-connect /usr/bin/connect-proxy
|
||||
COPY --from=go-tools /out/helm /usr/local/bin/helm
|
||||
COPY --from=go-tools /out/kustomize /usr/local/bin/kustomize
|
||||
COPY --from=go-tools /out/git-lfs /usr/local/bin/git-lfs
|
||||
|
||||
# 업스트림이 소스에서 넣는 래퍼 스크립트들 — argocd 가 gpg 검증·entrypoint 에 쓴다.
|
||||
COPY --from=argocd-build \
|
||||
/go/src/github.com/argoproj/argo-cd/hack/gpg-wrapper.sh \
|
||||
/go/src/github.com/argoproj/argo-cd/hack/git-verify-wrapper.sh \
|
||||
/go/src/github.com/argoproj/argo-cd/entrypoint.sh \
|
||||
/usr/local/bin/
|
||||
RUN chmod 0755 /usr/local/bin/gpg-wrapper.sh /usr/local/bin/git-verify-wrapper.sh /usr/local/bin/entrypoint.sh
|
||||
|
||||
# git-lfs 시스템 설정(/etc/gitconfig) 을 만들어 LFS 필터를 활성화한다 — 업스트림과 동일.
|
||||
RUN git lfs install --system
|
||||
|
||||
# 하위 호환용 심볼릭 링크 — 업스트림과 동일.
|
||||
RUN ln -s /usr/local/bin/entrypoint.sh /usr/local/bin/uid_entrypoint.sh
|
||||
|
||||
# configmap 마운트 지원 — 업스트림과 동일한 경로/권한.
|
||||
WORKDIR /app/config/ssh
|
||||
RUN touch ssh_known_hosts && \
|
||||
ln -s /app/config/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts
|
||||
|
||||
WORKDIR /app/config
|
||||
RUN mkdir -p tls && \
|
||||
mkdir -p gpg/source && \
|
||||
mkdir -p gpg/keys && \
|
||||
chown argocd gpg/keys && \
|
||||
chmod 0700 gpg/keys
|
||||
|
||||
ENV USER=argocd
|
||||
|
||||
# dual-stack 환경에서 _grpc_config DNS TXT 조회가 타임아웃을 유발하는 문제 회피 — 업스트림과 동일.
|
||||
# argocd-cmd-params-cm 으로 덮어쓸 수 있다.
|
||||
ENV GRPC_ENABLE_TXT_SERVICE_CONFIG=false
|
||||
|
||||
COPY --from=argocd-build /go/src/github.com/argoproj/argo-cd/dist/argocd /usr/local/bin/argocd
|
||||
|
||||
# 업스트림과 동일한 심볼릭 링크 9개 — 차트가 이 이름들로 컨테이너 command 를 지정한다.
|
||||
RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-server && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-repo-server && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-cmp-server && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-application-controller && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-dex && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-notifications && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-applicationset-controller && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-k8s-auth && \
|
||||
ln -s /usr/local/bin/argocd /usr/local/bin/argocd-commit-server
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
|
||||
USER $ARGOCD_USER_ID
|
||||
WORKDIR /home/argocd
|
||||
@@ -0,0 +1,77 @@
|
||||
# argocd — 소스 컴파일형 자체 빌드 (유일한 변종)
|
||||
#
|
||||
# build-hardened-image.sh 가 source 한다. BUILD_ARGS 에 나열한 이름만 --build-arg 로 넘어간다.
|
||||
# 소스를 직접 컴파일하므로 "베이스 OS" 선택지가 없다 — BASE_OS=source 로 호출한다:
|
||||
# IMAGE=argocd BASE_OS=source bash scripts/build/build-hardened-image.sh <OUT_DIR>
|
||||
#
|
||||
# 왜 자체 빌드하는가 → source.Dockerfile 상단 주석 / README.md.
|
||||
# argo-cd 10.4.0 CVE 조치(2026-08-19)로 도입 — 근거·경과는 MEMORY.md.
|
||||
#
|
||||
# ── 다음 CVE 조치에서 바뀌는 것은 이 파일뿐이다 ────────────────────────────────
|
||||
# Dockerfile 에는 버전도 모듈 목록도 박혀 있지 않다. 새 차단 CVE 가 나오면:
|
||||
# Go stdlib CVE → GO_BUILDER_TAG 를 올린다
|
||||
# Go 모듈 CVE → GO_MODULE_UPGRADES 에 `<module>@<version>` 을 추가한다
|
||||
# OS 패키지 CVE → RUNTIME_BASE 를 올리거나 RUNTIME_PACKAGES 를 조정한다
|
||||
# 구성요소 새 릴리스 → 해당 *_VERSION 을 올린다
|
||||
|
||||
DOCKERFILE=source.Dockerfile
|
||||
TARGET=final
|
||||
TAG_SLUG=security
|
||||
|
||||
# build-hardened-image.sh 가 태그·verify.sh 전달용으로 요구하는 범용 필수값.
|
||||
# 스톡 v3.5.1 과는 태그 슬러그(TAG_SLUG=security)로 구분되므로 버전 문자열은 그대로 둔다.
|
||||
APP_VERSION=3.5.1
|
||||
|
||||
# v3.5.1 태그가 가리키는 커밋(lightweight 태그라 태그 객체 없이 커밋 직접 참조), 2026-08-19 확인.
|
||||
SOURCE_COMMIT=109ca7ca71139e514114499d294a492e7910a965
|
||||
|
||||
# stdlib 차단 CVE 를 해소하는 최소 Go 버전. suggest-go-upgrades.py 가 산출한다.
|
||||
# 빌더 스테이지에만 쓰이고 최종 이미지에는 남지 않는다.
|
||||
GO_BUILDER_TAG=1.26.6-trixie
|
||||
|
||||
# UI 빌드용. 업스트림 Dockerfile 의 node pin 과 동일하게 맞춘다 — UI 번들은 스캔에서
|
||||
# 취약점이 잡히지 않으므로 올릴 이유가 없고, lockfile 과의 정합을 지키는 쪽이 안전하다.
|
||||
NODE_BUILDER_TAG=24.14.1
|
||||
|
||||
# 최종 런타임 베이스 — 카탈로그는 SUSE BCI 하나만 쓴다(.claude/image-authoring.md 원칙 2).
|
||||
# argocd 는 git/gpg/ssh 런타임이 필요해 패키지 매니저가 있는 bci-base 를 쓴다.
|
||||
# base 와 micro 를 스캔해 비교했고 차이가 없어, micro 씨앗 방식(.claude/image-authoring.md)의
|
||||
# 복잡도를 감수할 이점이 없었다.
|
||||
#
|
||||
# **16.0 을 쓰는 이유 — coreutils 버전이 차트 요구사항을 가른다.**
|
||||
# argo-cd 차트의 repo-server init 컨테이너(copyutil)가 `cp --update=none` 을 쓴다. 이
|
||||
# 형식은 GNU coreutils 9.3+ 에서만 되는데 15.7 은 그보다 낮아
|
||||
# "option '--update' doesn't allow an argument" 로 죽는다(실측 — 15.7 로 빌드해 배포했다가
|
||||
# repo-server 가 Init:CrashLoopBackOff 로 실패했다). 16.0 은 coreutils 9.6 이라 동작한다.
|
||||
# 16.0 의 패키지 가용성과 trivy 커버리지(CoverageProbe=ok, EOSL 아님)도 확인했다.
|
||||
# verify.sh 가 이 명령을 직접 검사하므로 다음에 베이스를 바꿔도 빌드 단계에서 걸린다.
|
||||
RUNTIME_BASE=registry.suse.com/bci/bci-base:16.0
|
||||
|
||||
# 번들 Go 도구 — 업스트림은 hack/install.sh 로 릴리스 바이너리를 내려받지만, 그 바이너리의
|
||||
# Go 버전이 낡아(git-lfs 1.25.3 · kustomize 1.24.0) CVE 의 주범이었다. 소스에서 다시 만든다.
|
||||
# helm 만 업스트림 pin(4.2.1) 대신 최신을 쓴다 — 나머지 둘은 pin 이 이미 최신이다.
|
||||
HELM_VERSION=4.2.4
|
||||
KUSTOMIZE_VERSION=5.8.1
|
||||
GIT_LFS_VERSION=3.7.1
|
||||
|
||||
# SLE_BCI 에 패키지가 없어 소스 빌드한다(2026-08-19 zypper 실측).
|
||||
# tini 는 업스트림 ENTRYPOINT, connect-proxy 는 SSH-over-proxy 용이다.
|
||||
TINI_VERSION=0.19.0
|
||||
SSH_CONNECT_VERSION=1.106
|
||||
|
||||
# 강제 업그레이드할 Go 모듈 — argocd·helm·kustomize·git-lfs 네 프로젝트에 **공통 적용**된다.
|
||||
# go-mod-upgrade.sh 가 각 프로젝트의 의존성 그래프에 있는 것만 골라 적용하므로 하나의
|
||||
# 목록을 그대로 재사용할 수 있다.
|
||||
#
|
||||
# 값은 suggest-go-upgrades.py 로 산출한다. 단, 제안값은 CVE 요건의 **최소치**라 모듈 간
|
||||
# 제약으로 더 올려야 할 수 있다 — 빌드가 "requires <module>@vX, not @vY" 로 실패하면 그
|
||||
# 버전으로 올린다(x/crypto 가 이 경우였다).
|
||||
GO_MODULE_UPGRADES="golang.org/x/crypto@v0.53.0 golang.org/x/net@v0.56.0 golang.org/x/text@v0.39.0 google.golang.org/grpc@v1.82.1 github.com/go-git/go-git/v5@v5.19.2 oras.land/oras-go/v2@v2.6.2"
|
||||
|
||||
# c-builder 가 tini(cmake)·connect(gcc) 를 컴파일하는 데 필요한 것들.
|
||||
BUILDER_PACKAGES="gcc make cmake git-core tar gzip"
|
||||
|
||||
# 최종 이미지 런타임 패키지 — 업스트림 apt 목록의 SLE 대응(README.md 매핑표 참고).
|
||||
RUNTIME_PACKAGES="git-core ca-certificates gpg2 timezone openssh-clients"
|
||||
|
||||
BUILD_ARGS="SOURCE_COMMIT APP_VERSION GO_BUILDER_TAG NODE_BUILDER_TAG RUNTIME_BASE HELM_VERSION KUSTOMIZE_VERSION GIT_LFS_VERSION TINI_VERSION SSH_CONNECT_VERSION GO_MODULE_UPGRADES BUILDER_PACKAGES RUNTIME_PACKAGES"
|
||||
Executable
+128
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env bash
|
||||
# argocd 이미지 기능 검증 — 호스트에서 bash 로 실행된다
|
||||
# (build-hardened-image.sh 가 `env TAG=... PLATFORM=... <build.env 변수들> bash verify.sh`
|
||||
# 형태로 호출한다).
|
||||
#
|
||||
# 이 이미지의 핵심 위험은 "번들 도구를 릴리스 바이너리 다운로드에서 소스 컴파일로 바꾼 것"과
|
||||
# "ubuntu → SUSE BCI 베이스 교체" 두 가지다. 그래서 argocd 본체뿐 아니라 helm·kustomize·
|
||||
# git-lfs·tini·connect-proxy 가 전부 실제로 실행되는지, 업스트림이 만들던 런타임 구조
|
||||
# (심볼릭 링크 9개, /etc/gitconfig 의 LFS 필터, /app/config 권한)가 그대로인지 확인한다.
|
||||
#
|
||||
# 실제 기동(서버·컨트롤러)은 Kubernetes API 가 필요해 이 스모크 범위 밖이다 —
|
||||
# dev 클러스터 배포 검증(.claude/deploy-test-procedure.md, scripts/deploy-test/deploy-test-argo-cd.sh)이
|
||||
# 담당한다.
|
||||
#
|
||||
# 마지막 줄에 VERIFY-OK 를 출력하면 통과다. build-hardened-image.sh 가 그것으로 판정한다.
|
||||
set -e
|
||||
|
||||
TAG="${TAG:?TAG 환경변수가 필요하다}"
|
||||
PLATFORM="${PLATFORM:-linux/amd64}"
|
||||
APP_VERSION="${APP_VERSION:?APP_VERSION 환경변수가 필요하다 (build.env 에서 전달)}"
|
||||
SOURCE_COMMIT="${SOURCE_COMMIT:?SOURCE_COMMIT 환경변수가 필요하다}"
|
||||
HELM_VERSION="${HELM_VERSION:?HELM_VERSION 환경변수가 필요하다}"
|
||||
KUSTOMIZE_VERSION="${KUSTOMIZE_VERSION:?KUSTOMIZE_VERSION 환경변수가 필요하다}"
|
||||
GIT_LFS_VERSION="${GIT_LFS_VERSION:?GIT_LFS_VERSION 환경변수가 필요하다}"
|
||||
|
||||
echo "== 이미지 메타데이터 =="
|
||||
USER_CFG="$(docker inspect --format '{{.Config.User}}' "$TAG")"
|
||||
[ "$USER_CFG" = "999" ] || { echo "FAIL: Config.User 가 999 가 아니다 (실제: $USER_CFG) — 업스트림 ARGOCD_USER_ID"; exit 1; }
|
||||
ENTRY="$(docker inspect --format '{{json .Config.Entrypoint}}' "$TAG")"
|
||||
case "$ENTRY" in
|
||||
*tini*) ;;
|
||||
*) echo "FAIL: ENTRYPOINT 에 tini 가 없다 (실제: $ENTRY)"; exit 1 ;;
|
||||
esac
|
||||
echo " Config.User=$USER_CFG Entrypoint=$ENTRY"
|
||||
|
||||
docker run --rm -i --platform "$PLATFORM" \
|
||||
-e APP_VERSION="$APP_VERSION" \
|
||||
-e SOURCE_COMMIT="$SOURCE_COMMIT" \
|
||||
-e HELM_VERSION="$HELM_VERSION" \
|
||||
-e KUSTOMIZE_VERSION="$KUSTOMIZE_VERSION" \
|
||||
-e GIT_LFS_VERSION="$GIT_LFS_VERSION" \
|
||||
--entrypoint sh "$TAG" <<'GUEST'
|
||||
set -e
|
||||
|
||||
echo "== argocd 본체 =="
|
||||
OUT="$(argocd version --client --short)"
|
||||
echo " $OUT"
|
||||
case "$OUT" in
|
||||
*"v$APP_VERSION"*) ;;
|
||||
*) echo "FAIL: 버전 출력에 v$APP_VERSION 이 없다 — Makefile ldflags 주입 확인 필요"; exit 1 ;;
|
||||
esac
|
||||
case "$OUT" in
|
||||
*"$SOURCE_COMMIT"*) ;;
|
||||
*) echo "WARN: 버전 출력에 pinned commit 이 안 보인다 (short 출력이라 생략됐을 수 있음)" ;;
|
||||
esac
|
||||
|
||||
echo "== 업스트림 심볼릭 링크 9개 =="
|
||||
for n in argocd-server argocd-repo-server argocd-cmp-server argocd-application-controller \
|
||||
argocd-dex argocd-notifications argocd-applicationset-controller argocd-k8s-auth \
|
||||
argocd-commit-server; do
|
||||
[ -x "/usr/local/bin/$n" ] || { echo "FAIL: /usr/local/bin/$n 없음"; exit 1; }
|
||||
done
|
||||
echo " 9개 모두 존재·실행 가능"
|
||||
|
||||
echo "== 번들 도구 (소스 컴파일로 교체한 것들) =="
|
||||
H="$(helm version --short)"
|
||||
echo " helm $H"
|
||||
case "$H" in *"$HELM_VERSION"*) ;; *) echo "FAIL: helm 버전이 $HELM_VERSION 이 아니다"; exit 1 ;; esac
|
||||
|
||||
K="$(kustomize version)"
|
||||
echo " kustomize $K"
|
||||
case "$K" in *"$KUSTOMIZE_VERSION"*) ;; *) echo "FAIL: kustomize 버전이 $KUSTOMIZE_VERSION 이 아니다"; exit 1 ;; esac
|
||||
|
||||
L="$(git-lfs version)"
|
||||
echo " git-lfs $L"
|
||||
case "$L" in *"$GIT_LFS_VERSION"*) ;; *) echo "FAIL: git-lfs 버전이 $GIT_LFS_VERSION 이 아니다"; exit 1 ;; esac
|
||||
|
||||
echo "== SLE_BCI 에 없어 소스 빌드한 C 도구 =="
|
||||
[ -x /usr/bin/tini ] || { echo "FAIL: /usr/bin/tini 없음"; exit 1; }
|
||||
/usr/bin/tini --version
|
||||
[ -x /usr/bin/connect-proxy ] || { echo "FAIL: /usr/bin/connect-proxy 없음"; exit 1; }
|
||||
# connect 는 인자 없이 부르면 usage 를 내고 비정상 종료한다 — 실행 가능 여부만 본다.
|
||||
/usr/bin/connect-proxy >/dev/null 2>&1 || true
|
||||
echo " tini · connect-proxy 실행 가능"
|
||||
|
||||
echo "== 런타임 필수 도구 (업스트림 apt 목록 대응) =="
|
||||
git --version >/dev/null || { echo "FAIL: git 없음"; exit 1; }
|
||||
gpg --version >/dev/null || { echo "FAIL: gpg 없음"; exit 1; }
|
||||
ssh -V 2>/dev/null || ssh -V || { echo "FAIL: ssh 없음"; exit 1; }
|
||||
echo " git · gpg · ssh 정상"
|
||||
|
||||
echo "== 차트가 실제로 실행하는 명령 =="
|
||||
# argo-cd 차트의 repo-server init 컨테이너(copyutil)가 그대로 쓰는 형식이다.
|
||||
# /bin/cp --update=none /usr/local/bin/argocd /var/run/argocd/argocd
|
||||
# `--update=none` 은 GNU coreutils 9.3+ 에서만 된다. 베이스 OS 의 coreutils 가 낮으면
|
||||
# 이미지는 멀쩡히 빌드·스캔을 통과하고 **배포 시점에** Init:CrashLoopBackOff 로 죽는다
|
||||
# (실측). 그래서 여기서 직접 확인한다 — 베이스를 바꿀 때 이 검사가 걸러준다.
|
||||
: > /tmp/_vsrc
|
||||
if ! /bin/cp --update=none /tmp/_vsrc /tmp/_vdst 2>/dev/null; then
|
||||
echo "FAIL: 'cp --update=none' 이 동작하지 않는다 — 베이스 OS 의 coreutils 가 9.3 미만이다."
|
||||
echo " argo-cd 차트의 repo-server init 컨테이너가 이 형식을 쓰므로 배포가 실패한다."
|
||||
cp --version 2>/dev/null | head -1
|
||||
exit 1
|
||||
fi
|
||||
echo " cp --update=none 동작 ($(cp --version 2>/dev/null | head -1))"
|
||||
|
||||
# argocd 바이너리를 공유 볼륨에 복사하는 흐름 자체를 그대로 재현해 본다.
|
||||
mkdir -p /tmp/_vrun
|
||||
/bin/cp --update=none /usr/local/bin/argocd /tmp/_vrun/argocd || { echo "FAIL: argocd 복사 실패"; exit 1; }
|
||||
/bin/ln -sf /tmp/_vrun/argocd /tmp/_vrun/argocd-cmp-server || { echo "FAIL: cmp-server 심볼릭 링크 실패"; exit 1; }
|
||||
[ -x /tmp/_vrun/argocd-cmp-server ] || { echo "FAIL: 복사된 argocd 가 실행 가능하지 않다"; exit 1; }
|
||||
echo " copyutil 흐름(복사 + cmp-server 링크) 재현 성공"
|
||||
|
||||
echo "== git-lfs 시스템 설정 (업스트림 git lfs install --system) =="
|
||||
git config --system --get filter.lfs.clean >/dev/null || { echo "FAIL: /etc/gitconfig 에 LFS 필터가 없다"; exit 1; }
|
||||
echo " filter.lfs.clean 등록됨"
|
||||
|
||||
echo "== 업스트림 런타임 디렉토리 구조 =="
|
||||
[ -L /etc/ssh/ssh_known_hosts ] || { echo "FAIL: /etc/ssh/ssh_known_hosts 심볼릭 링크 없음"; exit 1; }
|
||||
[ -d /app/config/tls ] || { echo "FAIL: /app/config/tls 없음"; exit 1; }
|
||||
[ -d /app/config/gpg/keys ] || { echo "FAIL: /app/config/gpg/keys 없음"; exit 1; }
|
||||
[ -x /usr/local/bin/entrypoint.sh ] || { echo "FAIL: entrypoint.sh 없음"; exit 1; }
|
||||
[ -x /usr/local/bin/uid_entrypoint.sh ] || { echo "FAIL: uid_entrypoint.sh 없음"; exit 1; }
|
||||
[ -x /usr/local/bin/gpg-wrapper.sh ] || { echo "FAIL: gpg-wrapper.sh 없음"; exit 1; }
|
||||
echo " ssh_known_hosts 링크 · /app/config/{tls,gpg/keys} · 래퍼 스크립트 정상"
|
||||
|
||||
echo "VERIFY-OK"
|
||||
GUEST
|
||||
Reference in New Issue
Block a user