を今更ながら勉強しました。
はじめに
本記事は、コンテナ技術のベースとなるLinuxカーネルやそれに付随する機能を紹介するものです。
Namespace
Namespace とは、Linuxカーネルが持つ機能でホストから隔離された空間を作成する機能です。Namespace を作成することでホストからリソースやプロセスが分離されます。
Namespace には以下のような種類があります。これらの Namespace と後述の cgroup、pivot_root、bind mount、OverlayFS ...の機能を連携させることで、コンテナ環境が構成されています。
Namespace Flag Page Isolates
───────────────────────────────────────────────────────────────────
Cgroup CLONE_NEWCGROUP cgroup_namespaces(7) Cgroup root directory
IPC CLONE_NEWIPC ipc_namespaces(7) System VIPC, POSIX message queues
Network CLONE_NEWNET network_namespaces(7) Network devices, stacks, ports, etc.
Mount CLONE_NEWNS mount_namespaces(7) Mount points
PID CLONE_NEWPID pid_namespaces(7) Process IDs
Time CLONE_NEWTIME time_namespaces(7) Boot and monotonic clocks
User CLONE_NEWUSER user_namespaces(7) User and group IDs
UTS CLONE_NEWUTS uts_namespaces(7) Hostname and NIS domain name
cgroup
cgroup とは、OS上で起動したプロセスに物理的なリソースを制限する機能です。Namespaceで隔離したプロセス(=コンテナ)に対しても同様に、リソースの制限をかけることができます。制限可能なリソースにCPU、メモリ、ネットワークI/O、ディスクI/Oがあります。リソース毎にコントローラーが実装されています。また、非特権ユーザでも cgroup を操作できるように権限を委譲する仕組みが用意されています。
chroot
chroot とは、プロセスのルートディレクトリーを変更する機能です。chroot でルートディレクトリを変更すると、変更したディレクトリがルートディレクトリとして認識されます。変更後のルートディレクトリより上位のファイルシステムにはアクセスできなくなります。
特権ユーザーは chroot した環境から更に chroot することでコンテナ(Namespace)から脱出してホストに侵入できるため、主要なコンテナランタイムは chroot ではなく後述の pivot_root を採用しています。
pivot_root
pivot_root とは、ルートファイルシステムを変更する機能です。pivot_root でルートファイルシステムを切り替えると、新しいルートファイルシステムしか参照できなくなります。別のファイルシステムとなるため、元のファイルシステムに脱出することができません。
pivot_root を実行するには条件があるようです。この条件を満たすために、後述の bind mount を利用します。
bind mount
bind mount とは、任意のファイル/ディレクトリを別のファイル/ディレクトリにマウントする機能です。
バインドマウントでホストのディレクトリを自分自身にマウントすることで、システムは自分自身にマウントしたディレクトリを独立したファイルシステムがマウントされた(マウントポイント)かのように扱います。
bind mount でマウントしたディレクトリに pivot_root を実行することで、任意のディレクトリをコンテナのファイルシステムとしてホストから隔離することができます。
ホスト・コンテナ間のUID、GIDマッピング
User Namespaceを作成すると、ホストから隔離された空間にUID、GIDを保持します。ホストと作成したUser Namespace間でUID、GIDを適切にマッピングすることで、セキュアなコンテナ環境を提供できるようになります。具体的に、コンテナの root ユーザをホストの一般ユーザにマッピングすることで、ホストから見ると一般ユーザの権限しか保持していない状態となります。この仕組みを利用すると、一般ユーザ(ルートレスユーザ)がコンテナを起動することが可能となります。
複数のIDをマッピングするケースでは、subuid と subgid を利用します。コンテナ内で複数のユーザを作成するとサブIDの範囲からIPがマッピングされます。
bind mount の項で記載したとおり、コンテナはホストのディレクトリをマウントしています。ホスト・コンテナ間のディレクトリ所有権も同様にマッピングする必要があります。このマッピングする機能がID mapped マウントです。具体的に、mount コマンドの --map-users
, --map-groups
オプションで所有権のマッピングを指定します。
OverlayFS
OverlayFS とは、複数のファイルシステムが持つディレクトリを重ね合わせて、あたかも1つのディレクトリツリーとして構成するユニオンファイルシステムです。コンテナファイルのFROM
キーワードが下層レイヤー、RUN
キーワードが上層レイヤーとなり、OverlayFS の各レイヤーにアーカイブファイルを展開します。
コンテナのネットワーク
コンテナに隔離されたネットワーク機能を提供するために、レイヤー2の仮想ネットワークインターフェースである veth (Virtual Ethernet Device) が利用されています。
veth は常にペアで作成され、それぞれが異なる Network Namespace に配置されます。具体的に、veth ペアの一方はホストのデフォルト Network Namespace に配置され、もう一方はコンテナの Network Namespace 内に移動されます。veth ペアの内のホスト側は、ホストに作成された仮想ブリッジへ接続されます。これにより、仮想ブリッジを介してホストとコンテナ間の通信が可能になります。
レイヤー2はOSI参照モデルのデータリンク層にあたります。veth はMACアドレスを介して同一ネットワーク内(仮装ブリッジ)にパケットを転送し、仮想ブリッジに接続された veth ペアへパケットを転送します。
veth 以外にも、ホストのネットワークスタックを直接共有したり、macvlan でコンテナのネットワークを構成することができます。
capabilities
capabilities とは、root が持つ特権を細分化して、必要な権限のみを一般ユーザに付与する機能です。capabilities の設定で、コンテナに必要な権限のみを付与する運用が可能となります。
seccomp
seccomp (Secure Computing Mode) とは、プロセスから発行されるシステムコールをフィルタリングする機能です。システムコールをフィルタリングするためにBPF(Berkeley Packet Filter)が利用されています。
コンテナはホストのカーネルを共有するため、コンテナ内から自由にシステムコールを使用すると他のコンテナやホストに影響が出てしまいます。コンテナが発行するシステムコールを制限する目的で seccomp が利用されています。
制限する内容は seccomp プロファイルで定義することができます。
SELinux
SELinux (Security-Enhanced Linux) とは、Linuxカーネルに組み込まれたセキュリティ機能で、システムリソースへのアクセスをより詳細に制御するための仕組みです。ホスト上のユーザとプロセス、ファイル、NWなどの各種リソースにLabelを付与し、そのLabelの組み合わせでアクセス可能なリソースを制限するPolicyを定義します。SELinux のルールを適切に設定することにより、権限昇格による被害を軽減できます。
AppArmor
AppArmor とは、Linuxカーネルに統合されたセキュリティモジュールです。プログラムからのファイルやデバイス、ネットワークへのアクセスを制限することができます。任意のファイルパスを対象にセキュリティ制御が可能という特徴があります。
まとめ
この記事では、コンテナ技術を支えるLinuxカーネルの主要な機能について解説しました。
複数のLinuxカーネルの機能が複雑に連携することで、隔離性と効率性、セキュリティを確保したコンテナ環境が構築されています。