RootlessモードでDockerをより安全にする [DockerCon発表レポート]
NTTの須田です.Moby (≒Docker),BuildKit,containerdなど,コンテナ関連のオープンソースソフトウェアのメンテナ (開発委員.コミッタとも.)を務めています.また,Docker Meetup Tokyoの企画・運営も行っています.
2019年4月29日~5月2日にかけて, Docker公式のカンファレンスである DockerCon が サンフランシスコにて開催されました.
Dockerをより安全に使うための技術「Rootlessモード」に関して発表してきましたので,紹介します.
Rootlessモードとは
Rootlessモードは,Dockerデーモン及びコンテナを,非rootユーザで実行する技術です.Rootlessモードを用いることにより,万一Dockerに脆弱性や設定ミスがあっても,攻撃者にホストのroot権限を奪取されることを防ぐことが出来ます.
須田は,2017年末ころから,Dockerを非rootユーザで実行できるようにするための取り組みを進め,Docker及び下位コンポーネントであるrunc・containerdへのパッチ提供を実施したり,ユーザモードTCP/IPスタックである slirp4netns を考案したりしてきました.須田の提案が,Dockerに公式に採用されるまでにはやや時間がかかりましたが,2019年5月リリース予定の Docker v19.03にて,ようやく実験的に採用されました.
須田のruncやslirp4netnsへの取り組みは,Red Hat社が開発するDocker互換コンテナエンジンであるPodmanにも,Dockerより一足早く2018年夏ころから採用されています. (参考: Red Hatが開発するDocker互換の新コンテナエンジン「Podman」、バージョン1.0に到達, 2019年1月22日 Publickey)
なお,単に docker
コマンドを非rootユーザで実行すること自体は,従来でも可能でした. usermod -aG docker ユーザ名
コマンドを実行し,ユーザを docker
グループに追加すれば,ユーザは /var/run/docker.sock
を通じてDockerデーモンに接続できるようになるため, docker
コマンドを実行できるようになります.ただし,Dockerデーモンは依然としてrootユーザとして動作しており,かつ,ユーザは docker run --privileged
も含め,Dockerデーモンに対して任意のAPIを呼び出すことが可能です.
従って,usermod -aG docker ユーザ名
は,ユーザにパスワード無しでの sudo
を許可することと実質的に同義であり,セキュリティ上の利点は全くありません.
何故Rootlessモードを使うべきか
Dockerには,ホスト上の権限の奪取を防ぐための仕組みが多数備わっています(下記スライド参照).しかし,脆弱性のないソフトウェアを開発することは極めて困難であり,Dockerにも実際に過去に複数の脆弱性が見つかっています.2019年2月には,コンテナの中から容易にホスト上の権限を奪取することが出来る脆弱性 CVE-2019–5736 が発表され,話題となりました.また,Dockerの実装に脆弱性がないとしても,ユーザの設定ミスによってコンテナが脆弱となることも考えられます.
Rootlessモードは,脆弱性や設定ミスそのものを修正する技術ではありませんが,それらによる被害を軽減します.攻撃者が,Rootlessモードのコンテナから抜け出すことに成功しても,アクセス可能なファイルは限定されます.また,ホストのネットワークでのARP spoofingなども実行できません.
Rootlessモードは,HPCなどの共有計算機のユーザにとっても有用です.RootlessモードのDockerは,共有計算機のシステム管理者に作業を依頼しなくても,ユーザ自身でホームディレクトリ内にインストール出来ます.GPUも利用可能です.
Rootlessモードの仕組み
Rootlessモードは,Linuxカーネルが備えているUser Namespaces機能を用いて実装されています. User Namespacesを用いて,非rootユーザをrootユーザに見せかけることで,Dockerデーモンの実行が可能となります.
また, subuid・subgidを用いることで,User Namespaces内で複数のUID・GIDを用いることが可能となります.Dockerデーモンを実行するUIDと,コンテナを実行するUIDを分けることができるので,更にセキュリティを強化出来ます.
User Namespacesは,非rootユーザに見かけのroot権限を与えますが,真のroot権限を与えるわけではないので,多くの制約があります.
例えば,非rootユーザはUser Namespacesを用いることで,Network Namespacesの作成が可能となりますが,ホストとNetwork Namespaceをつなぐ veth を作成することは出来ません.従って,Network Namespace内のプロセスがホストのNATを通じてインターネットに接続することが出来ない問題が生じます.
Rootlessモードでは,ユーザモードで動作するネットワークスタックであるVPNKitを用いることで,この問題を解決しています.
また,須田が考案した類似のネットワークスタックであるslirp4netnsを用いることも可能です.slirp4netnsはパケットのコピーを減らしたり,MTUを大きくしたりすることで,高速化を図っています.
RootlessモードのDockerをインストールする
RootlessモードのDockerは, curl -fsSL https://get.docker.com/rootless | sh
コマンド1行で,ユーザのホームディレクトリ内に簡単にインストールすることが出来ます.sudo
は不要です.ただし, /etc/subuid
および /etc/subgid
が事前に設定されている必要がありますが,最近のLinuxディストリビューションではユーザ作成時に自動的に設定されることが多いので,たいていは考慮不要です.
また,Katacoda (https://www.katacoda.com/courses/docker/rootless) を用いると,Webブラウザ内で簡単にインストールを体験出来ます.キーボードからコマンドを入力しなくても,画面左側に表示されるコマンドをクリックしていくだけで作業を進めることが出来ます.
もしRootlessモードにバグがあれば, https://github.com/moby/moby/issues (Dockerデーモン)または https://github.com/docker/docker-install/issues (インストーラ) にて報告いただければと思います.
おわりに
私たちNTTはオープンソースコミュニティで共に活動する仲間を募集しています.ぜひ弊社 ソフトウェアイノベーションセンタ紹介ページや,採用情報ページをご覧ください.