LiteLLM の v1.89.4 のリリースノートを眺めていたら、Docker イメージの署名検証まわりの記述がしっかり書かれていて、思わず手が止まった。
cosign で署名されていること自体は知っていたけど、ピン留めした commit hash でのベリファイが「最も強い方法」だとリリースノートに明記されているのを読んで、自分の CI がタグ指定のゆるい方法しかやっていないことに気づいた。えぐい見落としだった。
commit hash 固定がなぜ強いのか
タグはリポジトリのルール次第で動かせてしまう可能性がある。対して commit hash は内容そのものの暗号学的な識別子なので、同じ hash が別のバイナリを指すことはあり得ない。LiteLLM のリリースノートは「cryptographically immutable」という言い方をしていて、これが全部を説明している。
実際に推奨されているコマンドはこれだ。
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.89.4key の URL 自体に commit hash `0112e53` が入っているのが神ポイントだと思った。公開鍵の取得先まで固定されるので、鍵ごとすり替えられるリスクを潰せる。
自分のプロジェクトでは LiteLLM のコンテナを GitHub Actions のジョブの中で pull して使っている。今まで `ghcr.io/berriai/litellm:v1.89.4` をそのまま pull するだけで、署名を確認するステップをまったく入れていなかった。ハマったことはなかったけど、それは運が良かっただけだった。
CI に cosign verify を差し込んだ
とりあえず動かしてみた感じ、GitHub Actions に組み込むのは 10 行もかからなかった。
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Verify LiteLLM image
run: |
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.89.4`sigstore/cosign-installer` の Action を使えば cosign のバイナリをわざわざ自前でキャッシュしなくていい。verify が通ればそのまま次のステップに進むし、失敗すればジョブが止まる。シンプルすぎて逆に「これだけでいいの?」と思うくらいだった。
ちなみに彼女に「Docker イメージに署名してるかどうか確認するの大事なんだよね」と話したら「そのイメージってアイコンみたいなやつ?」と返ってきて、説明を諦めた。まあ伝わらなくても正しいことはやる。
LiteLLM を使っているなら他のサードパーティイメージも見直したい
そもそも自分が LiteLLM をなぜ使っているかというと、OpenAI と Anthropic の API を同じインターフェースで切り替えながらコストを見比べたいからだ。モデルごとのトークン単価が違うので、用途によって使い分けるためのプロキシとして便利に使っている。
GitHub のスター数は 51.5k を超えていて、フォーク数も 9.2k ある。使っている人が多いということは、供給チェーンを狙う攻撃のターゲットになりやすいということでもある。だからこそ公式が cosign による署名と検証の手順を整備しているわけで、こっちもそれを使わないのはもったいない。
今回 LiteLLM のリリースノートを読んで気づいたのは、自分が pull しているサードパーティの Docker イメージのうち、署名の有無すら把握していないものがいくつかあるということだった。次の週末はそっちのリストを作るところから始めようとしている。
サプライチェーン攻撃の話は昔から「気をつけろ」と言われ続けているけど、こうして具体的な CLI コマンドが目の前に出てくると、やっと実作業として動けるものだ。