StableBuild のミラーとキャッシュへのアクセスは、Dockerfile に直接記載された API キーで制限されています。例えば、以下では API キーが FROM と、パッケージレジストリへの認証に使用される sb-apt.sh の ARG の両方で使用されています。
FROM stablebuild-my-secret-api-key.dockermirror.stablebuild.com/ubuntu:focal-20231003
ARG SB_API_KEY=stablebuild-my-secret-api-key
ARG APT_PIN_DATE=2023-11-10T10:40:01Z
COPY ./sb-apt.sh /opt/sb-apt.sh
RUN bash /opt/sb-apt.sh load-apt-sources ubuntu
RUN apt update && apt install -y curl
これらのキーはアカウントのトラフィック請求に使用されるため、非公開にしておくことが重要です。トラフィックの急増が見られる場合は、生トラフィックログを確認してキーが漏洩していないかチェックしてください。キーは ダッシュボード > Keys からローテーションできます。
Docker イメージ内でのキーの確認
Dockerfile にキーを記載する方法は、社内用の Docker コンテナをビルドする場合は問題ありませんが、Docker コンテナを公開(Docker Hub やその他の公開レジストリに)したい場合は問題になります。コンテナをプルした誰もがコンテナを構成するレイヤーを確認でき、API キーがそこに含まれています。さらに、ビルド時に API キーを含むファイルがコンテナに書き込まれる場合があります。例えば、上記の例ではキーはレイヤーを検査したときにも、ファイルシステム上にも残っています。
これを確認するには、まず次のコマンドでコンテナをビルドします:
docker build -t unsecure-demo .
次に dive でレイヤーを検査して、キーが存在することを確認します:
コンテナのレイヤーを通じて漏洩したキー(dive で検査) ファイルシステム上でもキーを見つけることができます。インタラクティブシェルでコンテナを実行します:
次のコマンドでディスクに保存されたキーを見つけられます:
キーを保護しましょう。まず、ベースイメージの FROM 行:
これはレイヤー(dive で確認可能)やファイルシステムには漏洩しませんが、イメージのメタデータには含まれます。これを解決するには、マルチステージ Docker イメージを作成します:
レイヤーを通じたキーの漏洩を防ぐ
次に、レイヤーを通じたキーの漏洩に対処しましょう:
キーをハードコードする代わりに、Docker ビルドシークレットを使用できます。シークレットはビルド時にマウントされ、最終イメージには含まれません。次のように使用します:
次のコマンドでこのコンテナをビルドします:
再び dive でイメージを検査すると:
ハードコードされたキーが消えています:
Docker イメージのレイヤーからキーが漏洩しなくなりました ファイルシステムを通じたキーの漏洩を防ぐ
ファイルシステムを通じたキーの漏洩を防ぐには、キーが保存されているすべてのファイルを、キーを使用する同じステップ内でクリーンアップする必要があります。そうしないと、特定のレイヤーのファイルシステムを検査することでキーを復元される恐れがあります。
先ほどのファイルシステムの検査で、キーが /etc/apt/sources.list(sb-apt.sh によって書き込まれる)に記載されており、/var/lib/apt/lists/ のファイル名(apt キャッシュファイル)にも含まれていることがわかりました。Dockerfile を次のように書き直します:
次のコマンドでこのコンテナをビルドします:
コンテナを実行してファイルシステムを検索すると、結果が出なくなります:
最終確認:エクスポートしたイメージの検査
最終確認として、完全なイメージ(すべてのレイヤーとメタデータを含む)をディスクにエクスポートし、API キーが残っていないか最終スキャンを行います:
🎉 コンテナにキーが含まれなくなり、Docker Hub やその他の公開レジストリに安全にプッシュできます。
上記は Ubuntu パッケージレジストリの場合ですが、他のミラーやキャッシュを使用する場合は、キーが漏洩していないことを確認するためにレイヤーとファイルシステムを手動で検査する作業が必要です。dive やコンテナへのインタラクティブシェルを使えば、比較的簡単に確認できます。
Kaniko でのビルドシークレットの使用
Kaniko を使用してコンテナをビルドする場合、ビルドシークレットは利用できません。しかし、ファイルシステム上の /kaniko フォルダが Kaniko コンテナとビルドプロセス間で共有されているという特性を利用できます。Dockerfile では次のように使用します:
ターゲット /kaniko/sb-api-key.txt は共有ファイルシステム上にあるため、/kaniko/executor を呼び出す前に Kaniko コンテナ内のこの場所にキーを書き込むだけです:
例えば、gcr.io/kaniko-project/executor コンテナのエントリーポイントを sh に設定し、引数を [ "-c", "echo -n 'stablebuild-my-secret-api-key' > /kaniko/sb-api-key.txt && /kaniko/executor --dockerfile=./Dockerfile" ] に設定することでこれを実現できます。