LiteLLM の v1.85.1 リリースノートを読んでいたら、Docker イメージの署名検証がちゃんと整備されていることに気づいた。cosign を使った署名で、commit `0112e53` で導入した鍵で全リリースを署名しているらしい。star 数が 47.8k を超えているプロジェクトなので、サプライチェーン攻撃への対策をこのレベルでやっているのは当然といえば当然なんだけど、自分がちゃんとやれていたかと問われると正直微妙だった。
うちのチームでは LiteLLM を社内の LLM プロキシとして使っている。OpenAI と Anthropic とGemini をまとめて扱えるのが便利で、API コストの集計も楽になった。ただ Docker イメージを pull するときに署名を検証するフローは組み込んでいなかった。CI で `docker pull ghcr.io/berriai/litellm:latest` してそのまま使っていたやつだ。「まあ公式リポジトリだし」という雑な信頼で運用していた。これはまずいな、と今更ながら思った。
リリースノートには 2 通りの検証方法が書いてある。タグを使う方法と、commit hash を直接指定する方法だ。タグは tag protection rules に依存するので、より強い保証が欲しいなら commit hash 固定を推奨している。具体的にはこう:
commit hash は cryptographically immutable なので、鍵ファイルが差し替えられるリスクがない、という理屈だ。確かにそうで、タグは force push されたら参照先が変わるけど、commit hash はそれができない。地味だけど重要な区別だと思う。
早速 GitHub Actions に組み込んでみた。cosign の install ステップを入れて、verify してから docker run するようにした。ここでちょっとハマった。cosign のバージョンによって `--key` フラグの挙動が微妙に違って、古いバージョンだと URL を直接渡せないケースがあった。`sigstore/cosign-installer@v3` を明示的に指定したら解決した。バージョン固定大事。
あとは verify の成功時の出力を確認するのに少し時間がかかった。リリースノートには「The cosign claims were validated」と「The signatures were verified against the specified public key」という 2 行が expected output として書いてある。これが出ていれば OK というのが明示されているのは助かった。ドキュメントが雑なツールだと成功なのか失敗なのか出力から判断できないことがあるので。
もう一個ハマったのは、verify するイメージタグと key ファイルのバージョンを合わせること。`v1.85.1` のイメージを検証するなら key も `v1.85.1` のパスから取る、という対応関係が崩れると検証に失敗する。当たり前といえば当たり前なんだけど、renovatebot が自動で image タグを上げてくれる運用にしていたので、key の URL だけ古いままになっていた。CI が落ちてから気づいた。
そもそも LiteLLM を社内で使い始めたのは、OpenAI の API キーをそれぞれのサービスに直接持たせたくなかったからだ。エンジニアが増えると誰がどのキーを持っているかわからなくなる。プロキシ経由にして、キーの管理と使用量の追跡を一元化する構成は良かったと思っている。
ただセキュリティを意識して導入したプロキシのイメージ自体の検証を怠っていたのは間抜けだった。彼女に「セキュリティのためにプロキシ入れた」と言って褒めてもらったのに、その実態はこれだった。まあ知らないだろうけど。
cosign の組み込みは半日もかからなかった。リリースノートに必要な情報が全部書いてあったのが大きい。v1.85.1 は機能追加より changelog の内容としては地味だけど、こういう信頼性の担保を丁寧にドキュメントに落とし込んでくれているのは神だと思う。次のバージョンアップ時も verify ステップが CI で壊れないか確認するのを忘れずにやる。
うちのチームでは LiteLLM を社内の LLM プロキシとして使っている。OpenAI と Anthropic とGemini をまとめて扱えるのが便利で、API コストの集計も楽になった。ただ Docker イメージを pull するときに署名を検証するフローは組み込んでいなかった。CI で `docker pull ghcr.io/berriai/litellm:latest` してそのまま使っていたやつだ。「まあ公式リポジトリだし」という雑な信頼で運用していた。これはまずいな、と今更ながら思った。
pinned commit hash で検証するのが推奨らしい
リリースノートには 2 通りの検証方法が書いてある。タグを使う方法と、commit hash を直接指定する方法だ。タグは tag protection rules に依存するので、より強い保証が欲しいなら commit hash 固定を推奨している。具体的にはこう:
cosign verify \
--key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
ghcr.io/berriai/litellm:v1.85.1commit hash は cryptographically immutable なので、鍵ファイルが差し替えられるリスクがない、という理屈だ。確かにそうで、タグは force push されたら参照先が変わるけど、commit hash はそれができない。地味だけど重要な区別だと思う。
自分の CI に組み込んだらハマったポイント
早速 GitHub Actions に組み込んでみた。cosign の install ステップを入れて、verify してから docker run するようにした。ここでちょっとハマった。cosign のバージョンによって `--key` フラグの挙動が微妙に違って、古いバージョンだと URL を直接渡せないケースがあった。`sigstore/cosign-installer@v3` を明示的に指定したら解決した。バージョン固定大事。
あとは verify の成功時の出力を確認するのに少し時間がかかった。リリースノートには「The cosign claims were validated」と「The signatures were verified against the specified public key」という 2 行が expected output として書いてある。これが出ていれば OK というのが明示されているのは助かった。ドキュメントが雑なツールだと成功なのか失敗なのか出力から判断できないことがあるので。
もう一個ハマったのは、verify するイメージタグと key ファイルのバージョンを合わせること。`v1.85.1` のイメージを検証するなら key も `v1.85.1` のパスから取る、という対応関係が崩れると検証に失敗する。当たり前といえば当たり前なんだけど、renovatebot が自動で image タグを上げてくれる運用にしていたので、key の URL だけ古いままになっていた。CI が落ちてから気づいた。
社内プロキシのセキュリティ、もう少し真面目にやる
そもそも LiteLLM を社内で使い始めたのは、OpenAI の API キーをそれぞれのサービスに直接持たせたくなかったからだ。エンジニアが増えると誰がどのキーを持っているかわからなくなる。プロキシ経由にして、キーの管理と使用量の追跡を一元化する構成は良かったと思っている。
ただセキュリティを意識して導入したプロキシのイメージ自体の検証を怠っていたのは間抜けだった。彼女に「セキュリティのためにプロキシ入れた」と言って褒めてもらったのに、その実態はこれだった。まあ知らないだろうけど。
cosign の組み込みは半日もかからなかった。リリースノートに必要な情報が全部書いてあったのが大きい。v1.85.1 は機能追加より changelog の内容としては地味だけど、こういう信頼性の担保を丁寧にドキュメントに落とし込んでくれているのは神だと思う。次のバージョンアップ時も verify ステップが CI で壊れないか確認するのを忘れずにやる。