はじめに
昨今、セキュリティ強化や軽量化の目的で、シェルを含まない distroless などの最小のベースイメージが使われることが増えてきました。一方、コンテナイメージに含まれるファイルをさっと確認したいと思ったときなど、シェルがなくて困ることがあります。この記事では、Docker 単体でシェルを含まないコンテナのファイルにアクセスする方法を紹介します。
シェル (busybox) をボリュームとしてマウントする (コンテナ起動時)
シェル (busybox) のバイナリをボリュームとしてマウントして利用する方法です。
事前に任意のボリュームを作成し、busybox のバイナリをコピーしておきます。この作業は一度だけで大丈夫です。ボリューム名や busybox のバージョンは適宜変更してください。
docker volume create busybox
docker run --rm -v busybox:/bb/ busybox:1.34.1 sh -c "cp /bin/* /bb/"
この busybox のボリュームをマウントして、シェルなしのコンテナイメージを起動します。コンテナ内のファイルと被らないように、別のディレクトリ (/bb
) にマウントして、PATH を通しています。以下の例ではシェルの入っていないイメージ k8s.gcr.io/pause-amd64:3.3
で busybox をのシェルを起動する例です。
docker run --rm -v busybox:/bb/ --entrypoint /bb/sh -e PATH=/bb/ -it \
k8s.gcr.io/pause-amd64:3.3
起動後は busybox のシェルでコンテナのファイルにアクセスできます。
/ # ls /
bb dev etc pause proc sys
ホストから /proc/$PID/root でアクセスする (コンテナ起動中)
起動中のコンテナの場合は、コンテナプロセスの PID を調べて、/proc/$PID/root
からコンテナのファイルシステムにアクセスできます。また、Kubernetes でも、Pod のコンテナ間でプロセス名前空間を共有 (shareProcessNamespace: true
)すれば、この方法でサイドカーからシェルの無いコンテナのファイルにアクセスできます。
コンテナプロセスの PID は、docker ps
でコンテナ ID を調べた後、以下のように docker inspect
で確認できます。
docker inspect -f '{{.State.Pid}}' <CONTAINER_ID>
ここで確認した PID を使って /proc/$PID/root
にアクセスすると、コンテナプロセスのルートファイルシステムにアクセスできます。
$ sudo ls /proc/8032/root
dev etc pause proc sys
おわりに
distroless などの最小のベースイメージを使った場合でも、 前述の方法でコンテナのファイルシステムにアクセスが可能です。攻撃対象領域を小さくするためにも、積極的に最小のベースイメージを使っていきましょう。