Docker 이미지 보안 — LiteLLM 이미지 서명을 검증하는 법
Docker 이미지 보안 — LiteLLM 이미지 서명을 검증하는 법
컨테이너 이미지를 프로덕션에 올리기 전에 "이 이미지가 정말 공식 것이고, 가는 길에 조작되지 않았나"를 확인하고 싶을 때가 있어요. 공급망 공격이 흔해진 요즘, 이미지 서명 검증은 단순한 방어선이 아니라 필수 관문이 됐습니다. LiteLLM은 v1.83.0부터 GHCR에 게시하는 모든 Docker 이미지를 cosign으로 서명합니다. 이 페이지는 서명을 어떻게 검증하고, CI/CD에서 강제하고, 권장 배포 패턴을 따르는지 다룹니다.
어떤 이미지가 서명되어 있나
ghcr.io/berriai/에 게시되는 모든 이미지 변형이 같은 cosign 키로 서명됩니다.
| 이미지 | 설명 |
|---|---|
ghcr.io/berriai/litellm |
핵심 프록시 |
ghcr.io/berriai/litellm-database |
Postgres 의존성 포함 프록시 |
ghcr.io/berriai/litellm-non_root |
non-root 변형 |
ghcr.io/berriai/litellm-spend_logs |
지출 로그 사이드카 |
서명 키는 커밋 0112e53에서 도입됐고, 공개 키는 저장소의 cosign.pub에 체크인되어 있습니다. 엔터프라이즈 이미지(litellm-ee)도 같은 서명 프로세스를 따르니, 특정 엔터프라이즈 이미지 태그의 적용 범위는 지원팀에 확인하면 됩니다.
서명 검증하기
cosign 설치는 공식 문서를 따라 하면 됩니다. 가장 강력한 검증 방법은 커밋 해시를 쓰는 건데, 커밋 해시는 암호학적으로 불변이라 태그 변조와 무관하게 확실합니다.
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.89.4
이미지 참조를 어떤 서명된 변형으로든 바꿀 수 있습니다 — 예를 들어 litellm-non_root:v1.89.4 같은 식으로요. 태그도 저장소에서 보호되어 같은 키로 확인됩니다. 검증에 성공하면 "The cosign claims were validated" 및 "The signatures were verified against the specified public key"라는 체크 결과가 나옵니다.
Kubernetes에서 강제하기 — Sigstore Policy Controller
Kubernetes 환경이라면 Sigstore Policy Controller가 cosign 검증에 실패한 팟을 거부할 수 있습니다. 세 단계로 구성돼요.
- 컨트롤러 설치:
helm repo add sigstore https://sigstore.github.io/helm-charts
helm install policy-controller sigstore/policy-controller \
-n cosign-system --create-namespace
- LiteLLM 공개 키로
ClusterImagePolicy생성 —ghcr.io/berriai/litellm*이미지에 LiteLLM 공개 키를 권위자로 지정합니다. - 네임스페이스에 라벨을 붙여 강제 활성화:
kubectl label namespace litellm policy.sigstore.dev/include=true
이제 그 네임스페이스에서 서명되지 않은 ghcr.io/berriai/litellm* 이미지를 쓰는 어떤 팟도 admission 단계에서 거부됩니다.
GCP와 AWS에서의 접근
GCP는 Binary Authorization으로 Cloud Run·GKE에서 cosign 서명을 강제할 수 있어요. LiteLLM 공개 키로 cosign 기반 애테스터를 만들고, ghcr.io/berriai/litellm* 이미지에 그 애테스터를 요구하는 정책을 구성하면 됩니다.
AWS는 배포 시점에 cosign 서명을 네이티브로 검증하지 않습니다. 그래서 흔한 접근이 두 가지예요. 하나는 CI/CD 게이트 — 배포 파이프라인에서 ECR로 푸시하거나 ECS 태스크 정의를 갱신하기 전에 cosign verify를 돌려 실패 시 파이프라인을 중단하는 겁니다. 다른 하나는 EKS에서 OPA/Gatekeeper(위의 Sigstore Policy Controller와 동일한 방식)를 쓰는 것이고요.
배포 잡 앞에 검증 스텝을 하나 추가하는 패턴은 대략 이렇게 됩니다.
- name: Verify LiteLLM image signature
run: |
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm-database:${{ env.LITELLM_VERSION }}
다이제스트 고정과 태그 정책
다이제스트 고정은 태그 변조와 무관하게 정확한 이미지 내용을 보장하는 방법입니다.
image: ghcr.io/berriai/litellm-database@sha256:<digest>
다이제스트는 pull 후 얻을 수 있어요.
docker inspect --format='{{index .RepoDigests 0}}' \
ghcr.io/berriai/litellm-database:v1.89.4
cosign 검증도 다이제스트와 함께 동작합니다. 다이제스트 고정이 워크플로우에 너무 빡빡하다면, 불변 릴리스 태그(예: v1.86.2 — semver/PEP 440)를 쓰면 됩니다. 이 태그는 덮어써지지 않는 릴리스 태그예요.
여기서 알아둘 게 있어요. main-stable과 main-latest는 이제 deprecated입니다. LiteLLM이 PEP 440/semver 버전으로 전환하면서 안정 릴리스가 vX.Y.Z 형태의 순수 태그로 게시됩니다. main-stable은 하위 호환을 위해 계속 갱신되지만 deprecated이고, main-latest는 더 이상 갱신되지 않아요. 프로덕션에서 latest는 피하세요. 롤링 태그라 배포 사이에 내용이 바뀔 수 있습니다. 구체적 vX.Y.Z 태그(또는 다이제스트)에 고정하세요.
업그레이드 시 안전한 순서
- 새 이미지 검증 — 새 릴리스 태그 또는 다이제스트에
cosign verify실행 - 스테이징에서 테스트 — 검증된 이미지를 비프로덕션 환경에 배포
- 고정 참조 갱신 — 배포 매니페스트의 다이제스트나 태그 변경
- 프로덕션 배포 — 평소 배포 프로세스로 롤아웃
/health모니터링 — 업그레이드 후 프록시가 정상인지 확인