コンテナの書き込みと実行の制限
イメージ、動いている実体、ファイルとログの保存場所を対応付けて確認します。
説明
ワークロードの実行時保護では、書き込める場所と、そこから実行できる処理を確認します。設定名だけで保護範囲を判断せず、対象の操作と結果を照合します。
読取り専用のルートと書込み可能なtmpfsを持つコンテナを起動します。公開文字列だけを使い、書込み拒否、ハッシュ、直接実行の拒否とインタープリター経由の違いを確かめます。
イメージ、動いている実体、ファイルとログの保存場所を対応付けて確認します。
1このページの検証用コンテナを起動する
/tmpにはrw,noexec,nosuidを指定します。
docker run -d --name lbox-workload-sample --network none --read-only --tmpfsこのページの検証用コンテナを起動する /tmp:rw,noexec,nosuid,size=1m sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8 sh -c 'echo public-start; sleep 600'ルート領域とは別の条件で/tmpを扱う構成です。これから同じ実体に対して操作します。
2ルート領域への書込みを試す
/lesson-deniedへ公開文字列を書こうとします。
docker exec lbox-workload-sample sh -c 'printf public > /lesson-deniedルート領域への書込みを試す'Read-only file systemで拒否されます。この拒否はファイルシステムの読取り専用設定によるものです。
3一時領域へ同じ文字列を書き込む
/tmp/lesson-publicを作成し、内容を読みます。
docker exec lbox-workload-sample sh -c 'printf public > /tmp/lesson-public一時領域へ同じ文字列を書き込む; cat /tmp/lesson-public; echo'publicが表示されます。ルートへの書込み拒否から、コンテナ内の全書込みが禁止されたとは言えません。
4書き込んだ内容のハッシュを取得する
sha256sumで実際のファイルを読みます。
docker exec lbox-workload-sample sh -c 'sha256sum書き込んだ内容のハッシュを取得する /tmp/lesson-public'これは6バイトのpublicに対応するハッシュです。検知されたパス名だけでなく、内容の同一性を確認する値として使えます。
5一時領域のスクリプトを直接実行する
publicを表示するだけのスクリプトを置き、実行属性を付けて起動します。
docker exec lbox-workload-sample sh -c 'printf "#!/bin/sh\nprintf public\n" > /tmp/hello; chmod 700一時領域のスクリプトを直接実行する /tmp/hello; /tmp/hello'Permission deniedです。実行属性があってもnoexecのマウントから直接実行できません。
6インタープリターがファイルを読む場合を確認する
shへスクリプトのパスを渡します。
docker exec lbox-workload-sample sh -c 'sh /tmp/helloインタープリターがファイルを読む場合を確認する; echo'publicが表示されます。noexecは読み取り自体を禁止する設定ではなく、既存のインタープリターが内容を読む経路まで一律に止めるものではありません。
7拒否したパスと許可したファイルを読み直す
ルート側が作られていないことと、一時ファイルの属性を確認します。
docker exec lbox-workload-sample sh -c 'test ! -e拒否したパスと許可したファイルを読み直す /lesson-denied && printf "root unchanged\n"; stat -c "%A %U %G %s" /tmp/lesson-public'root unchanged、権限-rw-r--r--、所有者root、6バイトです。拒否ログだけでなく、対象の保存状態も確認できました。
まとめ
書込み可能範囲はマウントごとに確認します。
直接実行とインタープリターによる読み取りは異なります。
操作結果をファイルの存在・属性・ハッシュで照合します。
操作履歴と解説を振り返れます。
Docker / Alpine 3.22 / ネットワークなし・読取り専用コンテナ
docker run -d --name lbox-workload-sample --network none --read-only --tmpfs /tmp:rw,noexec,nosuid,size=1m sha256:5291449c3df73caf6ed85e649dec1b9e818b39a5d8c871e97afc13e9cd5e8fa8 sh -c 'echo public-start; sleep 600'baf05bed70748b85f2709f04224577680b01330feb18fed6610cab508219a6d2
docker exec lbox-workload-sample sh -c 'printf public > /lesson-denied'sh: can't create /lesson-denied: Read-only file system
docker exec lbox-workload-sample sh -c 'printf public > /tmp/lesson-public; cat /tmp/lesson-public; echo'public
docker exec lbox-workload-sample sh -c 'sha256sum /tmp/lesson-public'efa1f375d76194fa51a3556a97e641e61685f914d446979da50a551a4333ffd7 /tmp/lesson-public
docker exec lbox-workload-sample sh -c 'printf "#!/bin/sh\nprintf public\n" > /tmp/hello; chmod 700 /tmp/hello; /tmp/hello'sh: /tmp/hello: Permission denied
docker exec lbox-workload-sample sh -c 'sh /tmp/hello; echo'public
docker exec lbox-workload-sample sh -c 'test ! -e /lesson-denied && printf "root unchanged\n"; stat -c "%A %U %G %s" /tmp/lesson-public'root unchanged -rw-r--r-- root root 6
演習完了