Dockerにおける特権とルートの違いとは?
Dockerは、必要に応じてrootユーザーとしてコマンドを実行できますが、Privilegedという似たようなフラグも提供しています。しかし、コンテナの文脈では、これはrootの使用とは非常に異なります。システムを安全に保つために、この違いを理解することが重要です。
"ルート" とは一体何を意味するのか?
コンテナ内のユーザーとコンテナ外のユーザーの違いは、Dockerの内部での動作に起因しています。Dockerの基盤となる技術はLinuxネームスペースであり、これはカーネルレベルでの隔離を実現します。
コアコンセプトは非常にシンプルです。ホストの視点から見ると、Dockerコンテナはそのデータを格納するかもしれません。
/var/lib/docker/container/しかし、コンテナは別の「マウント」ネームスペースにあるため、それは次のように表示されます。
/
コンテナは何も知らないままです。プロセスおよびIPC名前空間、ネットワーク名前空間、ユーザー名前空間など、複数の名前空間タイプが存在します。Dockerは、コンテナを機能させるためにそれらすべてを利用しています。
Dockerデーモンはホストマシン上でrootとして実行されるため、デフォルトではすべてのコンテナもrootとして実行されます。コンテナ内のrootユーザーは、コンテナ外のrootユーザーと同じです。これは通常大きな問題ではありません。なぜなら、他の名前空間と同様に他のコンテナから隔離されているからです。コンテナ内でrootとして実行されるプロセスは、監獄のディレクトリの外にあるファイルにアクセスすることはできません。
これにより理論的な権限昇格攻撃の可能性が残るため、多くの人々はコンテナのrootユーザーを再マッピングすることを選ぶでしょう。
--userホストマシンで権限の低いユーザーとして実行するように設定するフラグで、いかなる種類のルートアクセスも拒否します。任意のユーザーIDを指定すると、Dockerはコンテナ内のroot(ID 0)を指定されたユーザーIDにマッピングします。
docker run -it --user 4000 ubuntu shもちろん、このrootユーザーはコンテナに対して完全なアクセス権を持ち、一般的なLinuxのベストセキュリティプラクティスは依然として適用されます。あなた自身のユーザーを設定し、通常のLinuxシステムのようにアプリケーションを実行するべきです。これにより、潜在的な攻撃面が低く抑えられ、ユーザーのリマッピングと組み合わせることで、コンテナが容易に外に出る可能性はありません。
特権がコンテナの脱出を許可する
特権は異なります。それは、Dockerコンテナが名前空間から抜け出し、システム全体に直接アクセスできるように、実行時に特別に設定できるフラグです。一般的に、これは非常に悪いアイデアです。なぜなら、これによりコンテナからの悪意のあるコードが、ホストの.ssh/authorized_keysを上書きしたり、ディスクパーティションを削除するなどの nasty なことを行うことができるからです。
コンテナの分離の目的をも無意味にするが、いくつかのユースケースはある。特権モードで実行することは、ホストマシン上でプロセスを実行するのと同じであるが、コンテナの中で実行するという組織的な利点を得ることができる。ネットワークデバイスのように、マシン上のハードウェアに直接アクセスする必要があるプロセスや、ルートパーティションに対する読み書きアクセスが必要なプロセスを実行する場合は、特権モードで実行することでこれを可能にする。もう一つの主要なユースケースは Docker in Docker、または DinD であり、これは Jenkins が Jenkins コンテナ内で Docker コンテナをビルドするために使用する。
JenkinsをインストールしてCI/CDパイプラインを構築する方法
しかし、他の何かについては、これはおそらく不要であり、ただリスクを増やすだけです。ただし、作業の内容を理解していて、特権付きでコンテナを実行したい場合は、--privilegedフラグを渡す必要があります。
docker run -it --privileged ubuntu sh同じ機能がKubernetesにも利用可能で、securityContextを使用します:
spec:
containers:
- name: nginx
image: nginx
securityContext:
privileged: true
