apisix의 keycloak-authz 커스텀 태그를 published.json 표준 경로 예외로 반영한다

apisix에 얹는 keycloak-authz 커스텀 플러그인 오버레이는 hardened-containers
표준 파이프라인 밖에서 별도로 빌드돼 같은 리포지토리에 -keycloak-authz 접미사를
붙여 추가로 push된다. published.json에는 이 접미사 태그가 절대 안 잡혀서,
apply-published-tags.py가 무필터로 ref를 그대로 적용하는 지금 방식으로는
카탈로그가 순정(keycloak-authz 없는) 태그를 가리키게 되는 실질적 회귀가 있었다
(manifests/helm/apisix/2.17.0/custom-values.yaml이 실제로 이 상태였다).

scripts/build/resolve-apisix-keycloak-authz-tag.py를 새로 만들어
apply-published-tags.py가 읽기 전에 published.json 사본의 apisix 항목을
제자리에서 고쳐 쓴다 — base 태그에 -keycloak-authz 버전이 실제로 있으면 그걸로
교체하고, 없으면 apisix 항목 자체를 지워 표준 "없다" 분기가 자연히 건너뛰게
한다(순정 태그로 되돌리는 일은 없다). apply-published-tags.py는 한 줄도
안 건드렸다.

catalog-tag-update.yml에 이 전처리를 한 스텝만 끼워 넣고, 즉시 1회 실행해
2.17.0의 회귀를 이 커밋에서 바로 고쳤다(3.18.0-security-hardened-20260826 →
...-keycloak-authz).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wbsong111
2026-08-27 08:41:16 +09:00
parent 7b4405397a
commit 2417655987
5 changed files with 162 additions and 1 deletions
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""resolve-apisix-keycloak-authz-tag.py — apisix의 keycloak-authz 커스텀 플러그인
오버레이 태그를 published.json에 반영한다(제자리 수정).
apisix에 얹는 keycloak-authz 오버레이는 hardened-containers의 표준 파이프라인
밖에서 별도로 빌드돼, 같은 `docker.io/paasup/apisix` 리포지토리에 표준 빌드보다
나중에 `-keycloak-authz` 접미사를 붙여 추가로 push된다. hardened-containers의
`published.json`에는 이 접미사 태그가 절대 안 잡힌다(그 레포가 만드는 게 아니므로).
이 스크립트는 `apply-published-tags.py`가 published.json을 읽기 *전에* 끼어들어
`images.apisix` 항목을 제자리에서 고쳐 쓴다:
1. published.json의 apisix base 태그(`<version>-security-hardened-<date>`)를 읽는다.
2. `<base 태그>-keycloak-authz`가 Docker Hub에 실제로 존재하는지 확인한다.
3. 있으면: `images.apisix`를 그 접미사 태그로 교체한다 — 이후
apply-published-tags.py는 이걸 원래 발행된 태그인 것처럼 그대로 적용한다.
4. 없으면: `images.apisix` 항목 자체를 지운다 — apply-published-tags.py의 기존
"published.json에 없다" 분기가 자연히 타서 apisix를 건너뛴다. **순정(접미사
없는) 태그로 되돌리는 일은 없다** — keycloak-authz가 빠지면 apisix가 실제로
요구하는 커스텀 인증 플러그인 없이 배포되는 회귀이기 때문이다.
apply-published-tags.py·apply_for_image()는 건드리지 않는다 — 이 스크립트가
끝난 뒤의 published.json이 "원래 그런 내용이었던 것"처럼 보이게만 한다.
사용
----
python3 scripts/build/resolve-apisix-keycloak-authz-tag.py --published /tmp/published.json
종료 코드
0 정상(교체·삭제·무변경 무관)
2 실행 오류(published.json 파싱 실패 등 — Docker Hub 조회 실패는 포함 안 함,
아래 참고)
"""
import argparse
import json
import sys
import urllib.error
import urllib.request
from pathlib import Path
def fetch_tags(repo):
"""Docker Hub 공개 API로 <namespace>/<repo>의 태그 전체를 가져온다.
{name: {tag_last_pushed, digest}} 로 반환."""
tags = {}
url = f"https://hub.docker.com/v2/repositories/{repo}/tags?page_size=100"
while url:
req = urllib.request.Request(url, headers={"Accept": "application/json"})
with urllib.request.urlopen(req, timeout=30) as resp:
doc = json.load(resp)
for r in doc.get("results") or []:
name = r.get("name")
if not name:
continue
tags[name] = {
"tag_last_pushed": r.get("tag_last_pushed"),
"digest": r.get("digest"),
}
url = doc.get("next")
return tags
def main():
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--published", required=True, metavar="FILE",
help="hardened-containers의 published.json — 제자리에서 수정한다")
ap.add_argument("--repo", default="paasup/apisix",
help="Docker Hub 리포지토리 (namespace/repo, 기본 paasup/apisix)")
ap.add_argument("--suffix", default="-keycloak-authz",
help="찾을 태그 접미사 (기본 -keycloak-authz)")
ap.add_argument("--registry", default="docker.io",
help="레지스트리 호스트 (기본 docker.io)")
args = ap.parse_args()
published_path = Path(args.published)
try:
doc = json.loads(published_path.read_text())
except Exception as e:
print(f"::error::published.json 을 읽지 못했다: {e}", file=sys.stderr)
return 2
images = doc.get("images") or {}
entry = images.get("apisix")
if entry is None:
print("apisix: published.json 에 없다 — 건너뛴다")
return 0
if entry.get("gate") != "pass":
print(f"apisix: gate={entry.get('gate')!r} — 건너뛴다")
return 0
base_tag = entry.get("tag")
if not base_tag:
print("::warning::apisix: published.json 항목에 tag 가 없다 — 건너뛴다",
file=sys.stderr)
return 0
candidate = f"{base_tag}{args.suffix}"
try:
tags = fetch_tags(args.repo)
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError) as e:
print(f"::warning::apisix: Docker Hub 태그 조회 실패({e}) — "
f"이번 실행에서는 기존 published.json 항목({base_tag})을 그대로 둔다",
file=sys.stderr)
return 0
if candidate in tags:
found = tags[candidate]
images["apisix"] = {
"ref": f"{args.registry}/{args.repo}:{candidate}",
"tag": candidate,
"digest": found.get("digest") or entry.get("digest"),
"gate": "pass",
}
published_path.write_text(json.dumps(doc))
print(f"apisix: keycloak-authz 변형 발견 — {candidate} 로 대체")
else:
del images["apisix"]
published_path.write_text(json.dumps(doc))
print(f"::warning::apisix: {candidate} 가 아직 없다 — "
f"이번 실행에서 apisix 를 건너뛴다(순정 태그로 되돌리지 않는다)",
file=sys.stderr)
return 0
if __name__ == "__main__":
sys.exit(main())