> For the complete documentation index, see [llms.txt](https://stablebuild.gitbook.io/ja/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://stablebuild.gitbook.io/ja/chtoriaru/protecting-your-keys-in-public-docker-containers.md).

# 公開 Docker コンテナでのキーの保護

StableBuild のミラーとキャッシュへのアクセスは、Dockerfile に直接記載された API キーで制限されています。例えば、以下では API キーが `FROM` と、パッケージレジストリへの認証に使用される `sb-apt.sh` の `ARG` の両方で使用されています。

```docker
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](https://github.com/wagoodman/dive) でレイヤーを検査して、キーが存在することを確認します：

```
dive unsecure-demo
```

<figure><img src="/files/euvX0oHc8JD9RYMOmpA0" alt=""><figcaption><p>コンテナのレイヤーを通じて漏洩したキー（<code>dive</code> で検査）</p></figcaption></figure>

ファイルシステム上でもキーを見つけることができます。インタラクティブシェルでコンテナを実行します：

```
docker run --rm -it unsecure-demo bash
```

次のコマンドでディスクに保存されたキーを見つけられます：

```
grep -rio --exclude-dir={ece,pytorch,sys,proc} 'stablebuild-my-secret-api-key' /
find / -name "*stablebuild-my-secret-api-key*"
```

<figure><img src="/files/C8zxewxbj6oauCqdz0fO" alt=""><figcaption><p>コンテナ内のファイルを通じて漏洩したキー</p></figcaption></figure>

### キーの保護

キーを保護しましょう。まず、ベースイメージの `FROM` 行：

```docker
FROM stablebuild-my-secret-api-key.dockermirror.stablebuild.com/ubuntu:focal-20231003
```

これはレイヤー（dive で確認可能）やファイルシステムには漏洩しませんが、イメージのメタデータには含まれます。これを解決するには、マルチステージ Docker イメージを作成します：

```docker
FROM stablebuild-my-secret-api-key.dockermirror.stablebuild.com/ubuntu:focal-20231003 AS base
FROM scratch
COPY --from=base / /
```

#### レイヤーを通じたキーの漏洩を防ぐ

次に、レイヤーを通じたキーの漏洩に対処しましょう：

```
ARG SB_API_KEY=stablebuild-my-secret-api-key
```

キーをハードコードする代わりに、[Docker ビルドシークレット](/ja/mirtokyasshu/docker-mirror.md)を使用できます。シークレットはビルド時にマウントされ、最終イメージには含まれません。次のように使用します：

```docker
FROM stablebuild-my-secret-api-key.dockermirror.stablebuild.com/ubuntu:focal-20231003 AS base
FROM scratch
COPY --from=base / /

ARG APT_PIN_DATE=2023-11-10T10:40:01Z

COPY ./sb-apt.sh /opt/sb-apt.sh

# シークレット「sb-api-key」をファイル「/kaniko/sb-api-key.txt」にマウント
# ファイルの内容を環境変数SB_API_KEYに読み込む
RUN --mount=type=secret,id=sb-api-key,target=/kaniko/sb-api-key.txt \
    SB_API_KEY=$(cat /kaniko/sb-api-key.txt) bash /opt/sb-apt.sh load-apt-sources ubuntu

RUN apt update && apt install -y curl
```

次のコマンドでこのコンテナをビルドします：

```
export SB_API_KEY=stablebuild-my-secret-api-key
docker build -t demo-build-secrets --secret id=sb-api-key,env=SB_API_KEY .
```

再び dive でイメージを検査すると：

```
dive demo-build-secrets
```

ハードコードされたキーが消えています：

<figure><img src="/files/fQCDEBcwnj1Z0rvzBzC7" alt=""><figcaption><p>Docker イメージのレイヤーからキーが漏洩しなくなりました</p></figcaption></figure>

#### ファイルシステムを通じたキーの漏洩を防ぐ

ファイルシステムを通じたキーの漏洩を防ぐには、キーが保存されているすべてのファイルを、キーを使用する**同じステップ内**でクリーンアップする必要があります。そうしないと、特定のレイヤーのファイルシステムを検査することでキーを復元される恐れがあります。

先ほどのファイルシステムの検査で、キーが `/etc/apt/sources.list`（`sb-apt.sh` によって書き込まれる）に記載されており、`/var/lib/apt/lists/` のファイル名（apt キャッシュファイル）にも含まれていることがわかりました。Dockerfile を次のように書き直します：

```docker
FROM stablebuild-my-secret-api-key.dockermirror.stablebuild.com/ubuntu:focal-20231003 AS base
FROM scratch
COPY --from=base / /

ARG APT_PIN_DATE=2023-11-10T10:40:01Z

COPY ./sb-apt.sh /opt/sb-apt.sh

# 元の /etc/apt/sources.list をバックアップ（後で復元）
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak

# 1. シークレット「sb-api-key」をファイル「/kaniko/sb-api-key.txt」にマウント
# 2. ファイルの内容を環境変数SB_API_KEYに読み込み、`sb-apt.sh`を実行してソースを読み込む
#    これによりFSにキーを含む'/etc/apt/sources.list'が作成される
# 3. apt update && apt installを1つのrunコマンドで実行（/etc/apt/sources.listがレイヤーに保存されないように）
# 4. 元のsources.listを復元
# 5. /var/lib/apt/lists/内のキーを含むaptキャッシュファイルを削除
RUN --mount=type=secret,id=sb-api-key,target=/kaniko/sb-api-key.txt \
    SB_API_KEY=$(cat /kaniko/sb-api-key.txt) bash /opt/sb-apt.sh load-apt-sources ubuntu && \
    apt update && \
    apt install -y curl && \
    cp /etc/apt/sources.list.bak /etc/apt/sources.list && \
    rm -r /var/lib/apt/lists/
```

次のコマンドでこのコンテナをビルドします：

```
export SB_API_KEY=stablebuild-my-secret-api-key
docker build -t demo-clean-fs --secret id=sb-api-key,env=SB_API_KEY .
```

コンテナを実行してファイルシステムを検索すると、結果が出なくなります：

```bash
$ docker run --rm -it demo-clean-fs bash
root@012e063d3d45:/# grep -rio --exclude-dir={ece,pytorch,sys,proc} 'stablebuild-my-secret-api-key' /
# 結果なし
root@012e063d3d45:/# find / -name "*stablebuild-my-secret-api-key*"
# 結果なし
```

#### 最終確認：エクスポートしたイメージの検査

最終確認として、完全なイメージ（すべてのレイヤーとメタデータを含む）をディスクにエクスポートし、API キーが残っていないか最終スキャンを行います：

```bash
$ mkdir -p out && \
    docker save -o out.tar demo-clean-fs && \
    mkdir -p out && \
    tar -xvf out.tar -C out/

$ cd out
$ grep stablebuild-my-secret-api-key -R .
# 結果なし！
```

🎉 コンテナにキーが含まれなくなり、Docker Hub やその他の公開レジストリに安全にプッシュできます。

上記は Ubuntu パッケージレジストリの場合ですが、他のミラーやキャッシュを使用する場合は、キーが漏洩していないことを確認するためにレイヤーとファイルシステムを手動で検査する作業が必要です。dive やコンテナへのインタラクティブシェルを使えば、比較的簡単に確認できます。

### Kaniko でのビルドシークレットの使用

Kaniko を使用してコンテナをビルドする場合、ビルドシークレットは利用できません。しかし、ファイルシステム上の `/kaniko` フォルダが Kaniko コンテナとビルドプロセス間で共有されているという特性を利用できます。Dockerfile では次のように使用します：

```docker
RUN --mount=type=secret,id=sb-api-key,target=/kaniko/sb-api-key.txt \
    SB_API_KEY=$(cat /kaniko/sb-api-key.txt) bash /opt/sb-apt.sh load-apt-sources ubuntu
```

ターゲット `/kaniko/sb-api-key.txt` は共有ファイルシステム上にあるため、`/kaniko/executor` を呼び出す前に Kaniko コンテナ内のこの場所にキーを書き込むだけです：

```bash
echo -n "stablebuild-my-secret-api-key" > /kaniko/sb-api-key.txt && \
    /kaniko/executor --dockerfile=./Dockerfile ...
```

例えば、`gcr.io/kaniko-project/executor` コンテナのエントリーポイントを `sh` に設定し、引数を `[ "-c", "echo -n 'stablebuild-my-secret-api-key' > /kaniko/sb-api-key.txt && /kaniko/executor --dockerfile=./Dockerfile" ]` に設定することでこれを実現できます。
