MEMORY.md 를 상태 파일로 되돌린다 (264줄 → 64줄)
MEMORY.md 는 3번째 줄에서 "지금 시점의 상태와 다음에 할 일만 담는다" 고 스스로 선언하는데
실제로는 완료 기록이 쌓여 264줄이 됐고, 이슈 참조가 한 건도 없었다. 그 결과:
- SBOM_PIPELINE_IMAGE 재빌드가 파일 안에서 3번 반복된다 (215·234·262줄)
- 게이트 강제력 전환이 2번 반복되고, 그 내용은 이미 이슈 #7 체크리스트와 #19 에 있다
- argo-cd 절 55줄은 커밋 33e91c0 메시지의 요약본이다
- 베이스 OS 정책·"벤더 릴리스 노트 믿지 말 것" 은 본문이 스스로 "이미 image-authoring.md /
skill 에 있다" 고 밝히면서 중복 서술한다
같은 사실이 여러 곳에 있으면 나중에 어느 쪽이 맞는지가 새 문제가 된다.
성격별로 목적지를 정하고 내보냈다
---------------------------------
추적이 필요한 미결 → GitHub 이슈 (#29~#33 발행, MEMORY.md 엔 한 줄 링크)
재발 방지 교훈 → .claude/ 문서·skill
단순 완료 기록 → 삭제 (커밋·PR·images/<image>/README.md 가 권위 있는 기록)
교훈 이관 — 아직 어디에도 없던 것만 옮겼다:
- image-authoring.md: 베이스 OS 를 CVE 수치만으로 고르면 배포에서 죽는다.
cp --update=none(coreutils 9.3+) 실측과, 차트가 실행하는 명령을 verify.sh 에서
재현하라는 규칙. 원칙 2 의 "BCI 버전은 실측해서 정한다" 바로 뒤에 붙였다.
- self-build-image skill: 같은 날 재빌드하면 태그가 겹쳐 노드 캐시가 반영을 막는다.
근본 해결은 #31, 여기엔 우회법만.
- cve-remediation skill: 레버 표를 보기 전에 "이 컴포넌트가 필요하긴 한가" 를 먼저 묻는다.
dex 가 한 줄로 차단 57건(58%)이었다. 가장 값싼 레버인데 표에 없어서 새 단계로 넣었다.
유지 규칙을 명시했다
--------------------
트리거는 시간이 아니라 상태다 — "1달 지났으니 정리" 는 아무도 시작하지 않고, 날짜로 자르면
오래됐지만 유효한 미결까지 잘린다. 항목이 "다음에 할 일" 이 아니게 되는 순간 내보낸다.
다만 놓친 것을 걷어내기 위해 월 1회 점검하고 파일 상단의 점검 날짜를 갱신한다.
규칙은 MEMORY.md 자체와 CLAUDE.md("작업 기록을 어디에 남기는가") 양쪽에 뒀다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,17 @@ docker run --rm registry.suse.com/bci/bci-base:<태그> \
|
||||
새 버전으로 올릴 때는 trivy 의 해당 SLE 버전 커버리지도 다시 확인한다 —
|
||||
`CoverageProbe` 가 `none` 이면 findings 0 이 진짜 0 이 아니다(게이트가 막는다).
|
||||
|
||||
**CVE 수치만 재고 고르면 배포에서 죽는다.** 베이스 OS 는 런타임이 요구하는 도구의 **버전**도
|
||||
같이 바꾼다. 실측(2026-08-19, `argocd`): argo-cd 차트의 repo-server init 컨테이너가
|
||||
`cp --update=none` 을 쓰는데 이 형식은 GNU coreutils 9.3+ 에서만 된다. BCI 15.7 로 빌드한
|
||||
이미지가 **게이트도 `verify.sh` 도 통과하고 배포 시점에** `Init:CrashLoopBackOff` 로 죽었다.
|
||||
스캐너는 "설치된 패키지에 알려진 CVE 가 있는가" 만 보지 "이 이미지를 쓰는 차트가 무엇을
|
||||
요구하는가" 는 전혀 보지 못한다.
|
||||
|
||||
→ **차트가 이 이미지에 대고 실제로 실행하는 명령을 `verify.sh` 에서 그대로 재현한다.**
|
||||
베이스를 바꿀 때 빌드 단계에서 걸린다. `images/argocd/verify.sh` 의 "차트가 실제로 실행하는
|
||||
명령" 절이 예다.
|
||||
|
||||
### `bci-micro` 위에 패키지를 얹을 때 — rootfs 는 반드시 "씨앗" 방식으로
|
||||
|
||||
`bci-micro` 는 패키지 매니저가 없지만 **rpmdb 는 갖고 있다**
|
||||
|
||||
@@ -16,7 +16,12 @@ description: 게이트가 카탈로그 이미지에서 차단 CVE(CRITICAL/HIGH)
|
||||
2. 차단 CVE를 컴포넌트 단위로 나눈다. "N건"이 성격 다른 여러 그룹(OS 패키지 vs 앱이
|
||||
번들/pin한 라이브러리)일 수 있고 그룹마다 레버가 다를 수 있다 — keycloak은 17건이
|
||||
OS rpm 5건 + Quarkus BOM pin jar 12건으로 갈렸다.
|
||||
3. 그룹별로 위부터 먼저 맞는 것을 쓴다:
|
||||
3. **레버를 고르기 전에 "이 컴포넌트가 필요하긴 한가"를 먼저 묻는다.** 차트 기본값으로 켜져
|
||||
있을 뿐 우리가 쓰지 않는 컴포넌트가 차단의 큰 몫을 만들고 있을 수 있다 — argo-cd 는
|
||||
`configs.cm.oidc.config` 로 Keycloak 에 직접 붙는데 차트 기본값 `dex.enabled: true` 때문에
|
||||
쓰이지도 않는 파드가 떠서 혼자 차단 57건(전체의 58%)을 만들고 있었다. 한 줄로 끝났다.
|
||||
가장 값싼 레버이고, 아래 표에는 없다.
|
||||
4. 그룹별로 위부터 먼저 맞는 것을 쓴다:
|
||||
|
||||
| 조건 | 레버 |
|
||||
|---|---|
|
||||
@@ -24,17 +29,17 @@ description: 게이트가 카탈로그 이미지에서 차단 CVE(CRITICAL/HIGH)
|
||||
| 베이스가 distroless/scratch, CVE가 정적 링크 바이너리(Go 모듈 등)에 있다 | 베이스 OS 교체 불가 → 자체 빌드 |
|
||||
| 앱이 번들·직접 pin한 라이브러리(jar 등)에 있다(OS 패키지 아님) | 태그·베이스 OS 둘 다 무효 → 자체 빌드(overlay/재컴파일) |
|
||||
| 다른 배포판이 backport로 이미 고쳤다 | 베이스 OS 교체 |
|
||||
| 컴포넌트가 중복/오탐 의심 | 4번 검증 후 예외, 아니면 자체 빌드 |
|
||||
| 컴포넌트가 중복/오탐 의심 | 5번 검증 후 예외, 아니면 자체 빌드 |
|
||||
|
||||
4. 예외는 검증 후에만 — "위험이 낮아 보인다"는 근거가 아니다. InstalledVersion이
|
||||
5. 예외는 검증 후에만 — "위험이 낮아 보인다"는 근거가 아니다. InstalledVersion이
|
||||
FixedVersion 이상인지, 같은 파일이 SBOM에서 컴포넌트 두 개로 잡히지 않는지(PkgPath
|
||||
비교) 확인한다. 실례: keycloak `CVE-2025-59250`(mssql-jdbc jar 하나가 두 컴포넌트로
|
||||
잡혀 잘린 쪽만 매칭된 오탐). 근거·만료일은 `doc/cve-exceptions.json`.
|
||||
5. 자체 빌드는 `self-build-image` + [image-authoring.md](../../image-authoring.md)로,
|
||||
6. 자체 빌드는 `self-build-image` + [image-authoring.md](../../image-authoring.md)로,
|
||||
태그/베이스 OS 교체는 카탈로그 values만 바꾸고 재게이트한다 — 별도 스크립트 없음.
|
||||
6. 수정 후 반드시 재게이트하고 PASS라도 배포 검증까지 끝나야 종료다 — 1회로 끝난다고
|
||||
7. 수정 후 반드시 재게이트하고 PASS라도 배포 검증까지 끝나야 종료다 — 1회로 끝난다고
|
||||
가정하지 않는다(keycloak은 1차 수정 후 재스캔에서 micrometer 2건이 새로 잡혔다).
|
||||
7. 착지는 브랜치 push까지다 — 조직 정책상 `GITHUB_TOKEN`으로 PR을 못 연다. 사람이 PR을
|
||||
8. 착지는 브랜치 push까지다 — 조직 정책상 `GITHUB_TOKEN`으로 PR을 못 연다. 사람이 PR을
|
||||
열고, 판단 근거는 PR 설명 + `MEMORY.md`에 남긴다.
|
||||
|
||||
## 참고
|
||||
|
||||
@@ -42,6 +42,10 @@ CI는 `build-image.yml`이 `image` 입력으로 이미 파라미터화돼 있다
|
||||
스캐너에 그 배포판 데이터가 없다는 뜻이다(`sbom-cve-gate` skill 참고).
|
||||
- **롤링 태그를 쓰지 않는다.** 같은 앱 버전이라도 베이스 업데이트 결과가 시점마다 달라
|
||||
태그에 빌드일을 포함한다(예: `1.30.0-security-hardened-20260804`).
|
||||
- **단, 같은 날 다시 빌드하면 그 태그가 겹친다.** 노드가 캐시한 옛 digest 가 그대로 쓰여
|
||||
(`imagePullPolicy: IfNotPresent`) 고친 것이 반영되지 않은 채 "안 고쳐졌다" 로 보인다.
|
||||
배포 검증 중이라면 `imagePullPolicy: Always` 로 우회하고, digest 로 확인한다 —
|
||||
`kubectl get pod -o jsonpath='{..imageID}'`. 프레임워크 차원의 미결 사항이다.
|
||||
|
||||
## 마무리
|
||||
|
||||
|
||||
Reference in New Issue
Block a user