本セッションの登壇者
セッション動画
加藤と申します。SNSでは@ten_forwardとして活動しています。また、gihyo.jpで2014年からコンテナに関する連載LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術を執筆していて、それをもとにした同人本 Linux Container Book (1) Namespace / Network 編も作っていますので、よろしくお願いします。
今日はKubernetesのことをよくご存知の方がたくさんお揃いですが、私は趣味でコンテナを使っていて、とくにカーネル周辺の技術に興味があるので、そのあたりだけ語ります。Kubernetesについてはほぼ知らず、コンテナといえばLXC/LXDをよく使っています。
なお、タイトルでは「最近の」としていますが、Linuxカーネルに新機能が入ってみなさんのお手元で使えるようになるまでにだいたい5 - 6年かかることがあるので、ご紹介する機能がまったく最近のものではないと思われるかもしれませんが、ご了承ください。
本日は、コンテナ関連の新機能として下記の3つを紹介します。
- User Namespace
- seccomp notify
- ID mapped mount
User Namespace
User Namespaceは、一般ユーザーでコンテナを起動できる機能です。コンテナの外から見ると一般ユーザーとして起動していますが、コンテナの中ではroot権限が使えるというマッピングが提供されます。つまり、ホストのroot≠コンテナのrootということになります。これはコンテナでの安全性確保のために役立つ機能です。
この機能自体は新しいものではありませんが、次にご紹介するseccomp notifyとID mapped mountの前提になる機能です。
seccomp / seccomp notify
seccompは「この操作は許可する/しない」というポリシーをあらかじめ定義しておき、実際にそのシステムコールが呼び出されたときにポリシーにしたがって実行される/されないという、フィルタがかけられる機能です。
コンテナラインタイムが特定の操作を許可/禁止したり、危険な操作はできないように設定したり、現在コンテナをお使いの方の多くは知らないうちにこの機能を使っているかと思います。
User Namespaceを使って一般ユーザーで起動したコンテナでは、コンテナ内のrootは外から見ると一般ユーザーなので、ホストのrootと同じ権限は与えられていません。このようなコンテナ内のrootに許可される/禁止される処理はカーネル内で静的に指定されていて、変更することはできません。
ただ、コンテナのホストを管理する立場で考えると、「一般的に危険とされている操作でも、このコンテナには許可しても大丈夫」という場合があります。設定で特定のコンテナに操作を許可できると便利だということで、5.0 カーネルでseccomp notifyという機能が導入されました。
seccomp notifyではコンテナ内でシステムコールが呼び出されたときに下記のような処理をしています。
- seccompがいったんシステムコールの呼び出しを保留し、コンテナランタイムなどのユーザー空間のプログラムに通知する
- 通知を受けたコンテナランタイムなどのプログラムが、どのようなシステムコールを実行しようとしているか、引数なども含めて検査する
- 通知を受けたプログラムが実行を許可していいか(OK/NG)をカーネルに返す
- プログラムが返した結果(OK/NG)に従って、seccompが処理する(OKならシステムコールを実行して結果をコンテナに返す、NGなら実行を拒否してコンテナに返す)
このような仕組みにより、柔軟にシステムコールの実行可否が設定できるようになり、以前は一般ユーザー権限のコンテナでは実行できなかったファイルシステムのマウントや、デバイスファイルの作成などができるようになりました。
seccomp notifyについて深く知りたい方向けには、seccompの勉強会などのリソースがありますのでご参照いただければと思います。
- 第14回 コンテナ技術の情報交換会@オンライン (seccomp 回)
- LXC で学ぶコンテナ入門「第 47 回 非特権コンテナの可能性を広げる seccomp notify
機能」 (gihyo.jp) - Seccomp Notify (brauner's blog)
ID mapped mount
DockerHubなどからダウンロードしたコンテナイメージでは各ファイルにユーザー権限が設定されており、UID/GID:0/0のファイルがほとんどですが、たまにちょっと違う所有権が設定されたファイルがあったりします。たとえばこのコンテナイメージをUID:100000の一般ユーザーで起動する場合、UID:100000でファイルを操作できるようにホスト上のコンテナ用のルートファイルシステムで権限が設定されていないと、コンテナイメージ内のファイルを読み込めません。
これまではコンテナ用ファイルシステム全体にchown
を実行することで、所有権を変更していました。すべてのファイルをUID/GID:0/0にできればいいのですが、たまにroot所有ではないファイルもあるので、chown
の前にファイルの所有権を確認しなければならず、コストがかかります。また、chown
は所有権を永久に変更するため、別のユーザー権限でコンテナを起動しようとすると、再度chown
で所有権を変更することになり、大変です。
そこで5.12カーネルではID mapped mountが導入されました。ID mapped mountは、User Namespaceのマッピングを使ってファイルの読み書き時にUID/GIDを変換することで、ファイルの実際の所有権は変更せずに、コンテナ用のファイルシステムをマウントする機能です。ファイルシステムに所有権を変換するための処理が追加されるイメージで、読み書きのときにコンテナ外部のUID/GID(例: 100000/100000)とコンテナ内のUID/GID(例: 0/0)が相互に変換されます。
ID mapped mountはカーネルに加えてファイルシステム側のサポートも必要ですが、最近OverlayFSでもサポートされるようになり、コンテナでも一般的に使われるようになってきています。
まとめ - コンテナを安全に動かすためのカーネルの機能を理解しよう
コンテナを安全に使うための機能がLinuxカーネルに実装されていますので、数年後にはみなさんが自然に使えるようになっているかと思います。たまには、カーネル側の機能をチェックして、コンテナがどのような仕組みで起動/動作しているのか、思いを馳せてみるのも楽しいのではないでしょうか。
ご清聴ありがとうございました。