【入門編】 コンテナイメージの署名と検証(Cosign/Notary) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

コンテナイメージに「鍵」をかけよう! 〜Cosign/Notaryでサプライチェーン攻撃から我が家を守る〜

皆さん、こんにちは!セキュリティバイブルの著者であり、日夜サイバー攻撃の最前線で奮闘しているホワイトハッカーです。今回は、新人のIT担当者や、これからセキュリティに触れていく開発者の皆さんに向けて、コンテナイメージの署名と検証という、ちょっと専門的に聞こえるけれど、実はとっても身近な「家の鍵」の話を、泥棒の侵入を防ぐ防犯の仕組みに例えながら、分かりやすく解説していきますね。

なぜコンテナイメージに「鍵」が必要なのか? 〜想像してみよう、空き巣の手口〜

最近、コンテナ技術(DockerとかKubernetesとか)を使ってアプリケーションを開発・運用する場面が増えていますよね。便利でスケーラブル、まさに現代のITインフラの主役と言っても過言ではありません。

でも、ちょっと待ってください。そのコンテナイメージ、本当に「信頼できる」ものですか?

ここでお話するのは、「コンテナイメージのサプライチェーンセキュリティ」という、ちょっと耳慣れない言葉かもしれません。でも、これは「信頼できるソースからビルドされたイメージのみが実行されるように、デジタル署名を用いてイメージの真正性を検証する」という、非常に重要な対策なんです。

例えるなら、あなたの家は、安全に守られていますか?

  • あなた自身が作った「オリジナルの設計図」(これがコンテナイメージに相当します)
  • その設計図通りに建てられた「あなたの家」(これがコンテナ上で動くアプリケーション)

もし、悪意のある第三者(泥棒)が、あなたの家の設計図をこっそりすり替えて、「これはあなたの家です」と偽って、何か危険なものを仕掛けたらどうなるでしょう?

例えば、

  • あなたの家の設計図(コンテナイメージ)に、こっそり「盗聴器」や「監視カメラ」が仕掛けられていたら?
  • 「あなたのお友達」と名乗る人が、実は泥棒に指示されて、偽物の設計図(悪意のあるコンテナイメージ)をあなたの家に持ち込もうとしたら?

これが、コンテナの世界で起こりうる「サプライチェーン攻撃」の恐ろしさなんです。

コンテナイメージは、インターネットを通じて様々な場所から取得したり、複数の開発者間で共有したりすることがあります。その過程で、悪意のあるコードが仕込まれたり、脆弱性がそのまま含まれたイメージが紛れ込んだりするリスクがあるのです。

信頼の「証」!デジタル署名とは? 〜家の「特殊な印鑑」〜

そこで登場するのが、今回ご紹介する「コンテナイメージの署名と検証」という仕組みです。これは、あなたの家の設計図に、「これは間違いなくあなた自身が作ったオリジナルの設計図です!」という「特殊な印鑑」を押すようなものだと考えてください。

この「特殊な印鑑」が、セキュリティの世界では「デジタル署名」と呼ばれます。

デジタル署名は、公開鍵暗号方式という、ちょっと賢い暗号技術を使っています。簡単に言うと、

1. 秘密鍵(印鑑の彫刻刀): イメージを作った人だけが持っている、絶対に他人に知られてはいけない「秘密の鍵」。
2. 公開鍵(印鑑の印影): 誰でも見ることができる「印影」。この印影と、秘密鍵で押された「本物の印影」を照合することで、本当にその秘密鍵の持ち主が署名したのかを確認できます。

このデジタル署名がコンテナイメージに付与されていると、「このイメージは、この秘密鍵の持ち主(信頼できる開発者や組織)によって作成され、改ざんされていない」という証明になるのです。

CosignとNotary 〜「鍵」と「署名」の管理番人〜

では、具体的にどうやってこの「デジタル署名」をつけたり、検証したりするのでしょうか?そこで活躍するのが、Cosign(コサイン)やNotary(ノータリー)といったツールです。

これらのツールは、コンテナイメージのサプライチェーンセキュリティを強化するための、いわば「鍵と署名の管理番人」のような存在です。

  • Cosign: 最近注目されているツールで、シンプルで使いやすいのが特徴です。Sigstoreというプロジェクトの一部として開発されており、鍵の管理や署名、検証を簡単に行えます。
  • Notary: Dockerが主導して開発された、より歴史のあるツールです。より詳細な権限管理や、複数の署名者を管理したい場合に強力な機能を発揮します。

どちらのツールを使うかは、プロジェクトの規模や要件によって異なりますが、基本的な考え方は同じです。「イメージを作った人が秘密鍵で署名し、そのイメージを使う人が公開鍵で署名を検証する」という流れです。

泥棒を撃退! 〜署名と検証の具体的なステップ〜

では、実際に泥棒(悪意のあるイメージ)を撃退するために、署名と検証をどのように行うか、具体的なステップを見ていきましょう。まずは、シンプルで使いやすいCosignを使った例で説明しますね。

ステップ1:イメージに「印鑑」を押す(署名)

あなたが信頼できるイメージを作成したら、それを公開する前に「印鑑」を押しましょう。

まず、Cosignをインストールします。お使いのOSに合わせてインストールしてください。

# Linux/macOS の場合 (curl が使える環境)
curl -s "https://raw.githubusercontent.com/sigstore/cosign/main/install.sh" | bash

次に、秘密鍵と公開鍵のペアを生成します。

# 秘密鍵と公開鍵のペアを生成します
cosign generate-keypair

このコマンドを実行すると、cosign.key (秘密鍵) と cosign.pub (公開鍵) というファイルが生成されます。cosign.key は絶対に他人に知られないように、厳重に管理してください!

いよいよ、イメージに署名します。ここでは例として、my-app:latest というイメージに署名してみましょう。

# コンテナレジストリにプッシュ済みのイメージに署名します
# 例: docker.io/your-username/my-app:latest
cosign sign --key cosign.key my-app:latest
# もしくは、ローカルのイメージに署名する場合
# docker save my-app:latest -o my-app.tar
# cosign sign --key cosign.key --UNSIGNED my-app.tar

これで、my-app:latest というイメージに、あなたの秘密鍵で生成されたデジタル署名が付与されました。この署名は、コンテナレジストリ(Docker HubやAWS ECRなど)にイメージと一緒に保存されるか、別途管理されます。

ステップ2:「印影」を渡して、家の「設計図」をチェックしてもらう(検証)

次に、あなたの作ったイメージを他の人が使う場面を想像してみましょう。例えば、開発チームのメンバーが、あなたが提供したイメージを使ってアプリケーションをデプロイするとします。

その際、彼らは、あなたから受け取った「公開鍵」を使って、イメージが本当にあなたのものか、そして改ざんされていないかを確認します。

# 署名を検証します
# 環境変数で公開鍵のパスを指定するか、直接指定します
# export COSIGN_PUBKEY="$(cat cosign.pub)"
cosign verify --key cosign.pub my-app:latest

もし、署名が正しく、イメージが改ざんされていなければ、上記のような出力が表示されます。

The following digests are trusted:
sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

もし、署名が不正だったり、イメージが改ざんされていたりすると、Cosignはエラーを返します。これにより、悪意のある第三者がすり替えた偽物のイメージを実行してしまうことを防ぐことができるのです。

Kubernetesでの利用例 〜自動で「鍵のチェック」〜

Kubernetesのようなオーケストレーションツールを使っている場合、さらに強力な仕組みを導入できます。例えば、Kubernetes Admission Controllerという仕組みを使うと、「署名されていないイメージや、信頼できない署名のイメージは、そもそもクラスター内にデプロイできない」ように設定できるのです。

これは、あなたが家に帰ったときに、「鍵がかかっていないドアや、怪しい鍵で開けようとする人からは、家の中に入れないように自動でロックがかかる」ようなイメージです。

Cosignは、Kubernetesと連携するための機能も提供しています。これを利用することで、デプロイされるコンテナイメージの信頼性を、自動的にチェックさせることが可能になります。

# Kubernetes Admission Controller の設定例 (抜粋)
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: ConstraintTemplate
metadata:
  name: k8srequiredcosign
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredCosign
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredcosign

        # ... (Cosign署名検証のロジック) ...

        violation[{"msg": msg, "details": {"missing_signature": missing_signature}}] {
          image := input.request.object.spec.containers[_].image
          not is_signed(image)
          msg := sprintf("image '%v' is not signed", [image])
          missing_signature := true
        }

この設定例のように、is_signed という関数でイメージが署名されているかを確認し、署名されていなければデプロイを拒否する、といった制御が可能になります。

まとめ:小さな「鍵」が、大きな「安心」を生む

コンテナイメージの署名と検証は、一見すると複雑に感じるかもしれませんが、その本質は「信頼できるものだけを実行する」という、非常にシンプルで強力な考え方です。

  • イメージ作成者: 秘密鍵で「これは私の作ったものだ!」と証明する。
  • イメージ利用者: 公開鍵でその証明を検証し、信頼できるイメージだけを実行する。

この「鍵」と「検証」のプロセスを導入することで、

  • 悪意のあるコードが仕込まれたコンテナイメージの実行を防ぐ
  • 意図しない脆弱性を持ったイメージの利用を未然に防ぐ
  • コンテナイメージのサプライチェーン全体における信頼性を向上させる

といった、非常に大きなセキュリティ効果が期待できます。

「でも、どこから手をつけていいか分からない…」という方も、大丈夫です!まずは、あなたの開発環境で、簡単なイメージにCosignで署名してみることから始めてみてください。そして、その署名を検証するプロセスを試してみましょう。

今回お話しした内容は、まるであなたの家の鍵をしっかりと管理し、怪しい人にはドアを開けないようにする、日々の防犯活動と同じです。小さな対策の積み重ねが、サイバー攻撃という大きな脅威から、あなたのシステムを、そしてあなた自身を守ることにつながります。

一歩ずつ、一緒にセキュリティ対策を学んでいきましょう!これからも、現場で役立つリアルな情報をお届けしていきますので、お楽しみに!

コメント

タイトルとURLをコピーしました