Files
service-catalog/images/keycloak/overlay-jars.sh
T
wbsong111 4e12e38293 add-keycloakx: micrometer 오버레이 추가 (CI 에서 새로 잡힌 차단 2건)
CI(31148639764)의 trivy 취약점 DB 가 로컬보다 최신이라 로컬 스캔에는 없던
CVE-2026-40983·CVE-2026-40984(io.micrometer:micrometer-core)가 차단으로 잡혔다.
netty·jackson 과 동일한 성격의 번들 jar CVE 라 같은 오버레이 메커니즘으로 처리한다.

micrometer 1.16.3 → 1.16.6. netty 와 같은 이유로 CVE 가 붙은 micrometer-core 만이
아니라 패밀리 전체 4종(commons·core·observation·registry-prometheus-simpleclient)을
함께 올린다 — 아티팩트 간 버전 혼용이 비지원이다.

Dockerfile 의 ARG 선언을 처음에 빠뜨렸는데 overlay-jars.sh 의 `: "${VAR:?}"` 가드가
설계대로 빌드를 세웠다("parameter null or not set"). 조용히 통과하지 않는다.

재빌드 결과(로컬 trivy DB 캐시를 지우고 CI 와 같은 최신 DB 로 재판정):

  차단 0건 — 게이트 PASS
  docker.io/paasup/keycloak:26.7.1-bci15.7-hardened-20260807 push 완료

태그는 빌드일 기준이라 같은 날 재빌드가 같은 태그를 덮는다(프레임워크 설계대로).
직전에 push 된 것은 micrometer 취약점이 남아 있던 빌드이고 어디에도 소비되지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 14:05:05 +09:00

100 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Keycloak 배포본에 정적으로 들어 있는 취약 jar 를 수정 버전으로 교체한다.
# suse.Dockerfile 의 builder 스테이지에서만 실행된다(호스트에서 직접 쓰지 않는다).
#
# 왜 필요한가
# 차단 CVE 17건 중 12건이 /opt/keycloak/lib/lib/main/ 의 jar 다. 이 버전들은
# Quarkus 3.33.2.1 BOM 이 고정하고 있어 keycloak 상위 태그로도, 베이스 OS 교체로도
# 바뀌지 않는다. etcd 이미지의 `go.work replace` 와 같은 성격의 의존성 override 다.
#
# 왜 파일명을 유지하는가
# Quarkus fast-jar 배포본은 lib/quarkus-run.jar 의 Class-Path 로 jar 파일명을 그대로
# 참조한다. 이름을 바꾸면 클래스패스가 깨진다. 이름을 유지하고 내용만 바꾸면
# - 런타임: 클래스패스 그대로 동작
# - SBOM: trivy 는 jar 내부 META-INF/maven/**/pom.properties 를 읽으므로 새 버전이
# 정확히 잡힌다 (파일명으로 버전을 위장하는 것이 아니다 — 실제 내용이 새 버전이다)
#
# 무결성
# Maven Central 의 .sha1 을 함께 받아 검증한다. 실패하면 즉시 종료한다.
#
# 실패 조건
# OLD 버전 파일을 하나도 못 찾은 spec 이 있으면 실패한다. 업스트림이 의존성 버전을
# 올렸는데 이 스크립트가 조용히 아무것도 안 하는 상태(= CVE 는 그대로인데 빌드는 성공)
# 를 막기 위함이다. patch-catalog-tag.py 가 패턴 불일치 시 크게 실패하는 것과 같은 원칙.
set -euo pipefail
KC_HOME="${1:?사용법: overlay-jars.sh <KEYCLOAK_HOME>}"
LIB="$KC_HOME/lib/lib/main"
M2="${M2_BASE:-https://repo1.maven.org/maven2}"
[ -d "$LIB" ] || { echo "FAIL: $LIB 가 없다 — 배포본 레이아웃이 바뀌었는지 확인"; exit 1; }
: "${NETTY_OLD:?}" "${NETTY_VERSION:?}"
: "${JACKSON_OLD:?}" "${JACKSON_VERSION:?}"
: "${PGJDBC_OLD:?}" "${PGJDBC_VERSION:?}"
: "${MICROMETER_OLD:?}" "${MICROMETER_VERSION:?}"
# groupId(파일명 프리픽스) | groupPath(Maven 경로) | artifact 필터 | OLD | NEW
# artifact 필터가 '*' 이면 해당 groupId + OLD 버전의 모든 jar 가 대상이다.
SPECS=(
"io.netty|io/netty|*|${NETTY_OLD}|${NETTY_VERSION}"
"com.fasterxml.jackson.core|com/fasterxml/jackson/core|jackson-core|${JACKSON_OLD}|${JACKSON_VERSION}"
"com.fasterxml.jackson.core|com/fasterxml/jackson/core|jackson-databind|${JACKSON_OLD}|${JACKSON_VERSION}"
"org.postgresql|org/postgresql|postgresql|${PGJDBC_OLD}|${PGJDBC_VERSION}"
"io.micrometer|io/micrometer|*|${MICROMETER_OLD}|${MICROMETER_VERSION}"
)
fetch() { # $1=url $2=출력경로
local url="$1" out="$2" want got
curl -fsSL --retry 3 --retry-delay 2 -o "$out" "$url"
want="$(curl -fsSL --retry 3 --retry-delay 2 "$url.sha1" | tr -d '[:space:]')"
got="$(sha1sum "$out" | cut -d' ' -f1)"
[ "$want" = "$got" ] || { echo "FAIL: sha1 불일치 $url (기대 $want / 실제 $got)"; exit 1; }
}
total=0
for spec in "${SPECS[@]}"; do
IFS='|' read -r gid gpath filter old new <<<"$spec"
matched=0
for f in "$LIB/$gid."*"-$old"*.jar; do
[ -e "$f" ] || continue
base="$(basename "$f")"
rest="${base#"$gid."}" # netty-codec-http-4.1.135.Final.jar
rest="${rest%.jar}" # netty-codec-http-4.1.135.Final
artifact="${rest%%-"$old"*}" # netty-codec-http
tail="${rest#*-"$old"}" # '' 또는 -linux-x86_64 (classifier)
if [ "$filter" != "*" ] && [ "$artifact" != "$filter" ]; then continue; fi
url="$M2/$gpath/$artifact/$new/$artifact-$new$tail.jar"
fetch "$url" "$f.new"
mv "$f.new" "$f" # 파일명 유지 — 내용만 교체
echo "overlay: $base <= $artifact-$new$tail.jar"
matched=$((matched + 1))
done
if [ "$matched" -eq 0 ]; then
echo "FAIL: spec '$gid/$filter@$old' 에 해당하는 jar 가 없다."
echo " 업스트림이 이미 버전을 올렸을 수 있다 — build.env 의 *_OLD 를 재확인하고,"
echo " 해소됐다면 해당 spec 을 제거한다(그냥 두면 CVE 가 남은 채 빌드가 성공한다)."
exit 1
fi
total=$((total + matched))
done
echo "overlay: 총 ${total}개 jar 교체 완료"
# keycloak-admin-cli 는 jackson 을 shade 로 품은 uber-jar 라 jar 교체로 못 고친다
# (SBOM 실측: jackson-databind@2.21.2 의 FilePath 가 bin/client/keycloak-admin-cli-*.jar).
# 서버 JVM 이 로드하지 않는 독립 CLI(kcadm.sh/kcreg.sh)이므로 하드닝 이미지에서는 제거한다.
# 업스트림 대비 유일한 기능적 차이다 — README.md / CUSTOM-README.md 에 명시.
if [ -d "$KC_HOME/bin/client" ]; then
rm -rf "$KC_HOME/bin/client"
echo "removed: bin/client (kcadm/kcreg — jackson shaded uber-jar, 서버 런타임 미사용)"
else
echo "FAIL: bin/client 가 없다 — 배포본 레이아웃이 바뀌었다. 제거 전제를 재확인할 것"
exit 1
fi