小さなサイトのサーバーの欠陥
だれかが、通販サイトのページを返すプログラムの欠陥を見つけました。そのプログラムに、好きなことをさせられます。
その先で何に届くかは、プログラムがだれとして動くかで決まります。イメージに何が入っているか、何が書かれているかでも決まります。
このレッスンのゴール
メモ
イメージを安全に出す条件を言い、危ない Dockerfile を直すことができる。
大事な言葉
| ことば | いみ | れい |
|---|---|---|
| root | システムの何でも変えられるユーザー | uid=0 |
| 非 root ユーザー | 権限が限られた、ふつうのユーザー | |
| 固定したタグ | 正確に1つの版を指すイメージのタグ | nginx:1.27-alpine |
| 秘密 | プログラムだけが知るべきパスワードや鍵 | |
| 攻撃面 | 攻撃者が使えるかもしれない、イメージの中のすべて |
学生が入力するセルは、このプレビューでは空白です。
できることの少ないユーザーで動かす
何も指定しないと、コンテナのプログラムは root で動きます。root は、コンテナが書き込めるファイルなら、マウントしたボリュームも含めて何でも変えられます。
非 root ユーザーにはできません。プログラムが攻撃されても、被害は小さくなります。ラボの2つの主なサービスを比べましょう。
web はだれとして動く?
docker exec web idここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
cache はだれとして動く?
docker exec cache idここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
cache に /etc へ書かせてみる
docker exec cache touch /etc/probeここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
web に同じことをさせてみる
docker exec web touch /etc/probeここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Dockerfile でユーザーを作る
FROM python:3.12-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
RUN adduser -D -u 10001 shop
USER shop
CMD ["python", "app.py"]
よくある間違い
注意
コンテナは隔離されているから、中の root は気にしなくてよい、と考える人がいます。壁にも欠陥はあり、マウントしたボリュームは本物のデータです。ユーザーを作って USER で切り替えます。ラボの cache もそうしています。
中身が少ないほど、攻撃されにくい
イメージの中のプログラムは、欠陥がありうるものがもう1つ増えることです。道具は、攻撃者が使えるものがもう1つ増えることです。
Alpine のような軽いベースは、ずっと少ししか持ちません。どの版を受け取るかはタグが決めます。latest のようなタグは動きます。来月のビルドは別のイメージかもしれません。
例: 1つのイメージの2つのタグ
| タグ | 試験用マシンでの大きさ | 意味 |
|---|---|---|
| nginx:1.27 | 284 MB | 下に完全なシステム |
| nginx:1.27-alpine | 76.8 MB | 下に小さなシステム |
| nginx:latest | 測っていません | ビルド時にいちばん新しいもの |
学生が入力するセルは、このプレビューでは空白です。
cache はどのタグに固定している?
docker inspect --format '{{.Config.Image}}' cacheここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
イメージに書いた秘密は残る
イメージは共有されます。レジストリに送られ、サーバーにコピーされ、同僚に渡されます。レイヤーの中にあるものは、一緒に行きます。
Dockerfile に書いたパスワードは、あとの手順でファイルを消しても、レイヤーに残り続けます。秘密はイメージの外に置き、コンテナの起動時に渡します。
秘密を書いた Dockerfile(まねしない)
FROM alpine:3.20
ENV API_KEY=abc123-not-real
RUN echo hello
例: 秘密が見えた場所
| 設定のしかた | 読み戻した場所 | 出たもの |
|---|---|---|
| Dockerfile の ENV | docker history --no-trunc | ENV API_KEY=abc123-not-real の行 |
| コンテナ起動時の -e | docker inspect の Config.Env | 一覧の中に DB_PASSWORD=hunter2 |
| どちらでもない | イメージにも設定にもなし | 実行時に渡した秘密 |
学生が入力するセルは、このプレビューでは空白です。
cache に渡されたものをすべて読む
docker inspect --format '{{json .Config.Env}}' cacheここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
もう一歩先へ
秘密を書いた Dockerfile を取り上げます。タグを固定し、ユーザーとして動き、秘密を持たないように書き直しましょう。
そのあと、課題の3つの関数を古い版と自分の版に実行します。新しい版は、何も指摘されないはずです。