Ubuntu Weekly Recipe

第686回 Bubblewrap/bwrapを使って管理者権限なしで非特権コンテナーを作る

この記事を読むのに必要な時間:およそ 4.5 分

ルートファイルシステムごとコンテナー化する

最後にbwrapコマンドを使って,ユーザー権限だけで特定のUbuntuの隔離環境を作ってみましょう。これと前述の--bindを組み合わせれば,管理者権限がない環境でもユーザー権限だけで動作確認用のルートファイルシステムを作り,その中でコマンドを動かしてみるといった手順が可能になります※2⁠。

※2
サーバーだとbubblewrapパッケージはインストールされていない可能性が高いため,この部分で管理者権限が必要になります。もしくはインストールされている可能性が高いunshareコマンドを使うというのも手です。考え方としてはbwrapと大差ありません。ただし,そもそもkernel.unprivileged_userns_cloneが0になっている可能性も排除できません。

まずはベースとなるルートファイルシステムをダウンロードしておきます。wgetにしろcurlにしろ方法はなんでもかまいません。LTS向けならUbuntu Baseを使うとサイズを最小にできます。ただし実際のUbuntu環境に合わせるためにはそれなりの追加パッケージが必要です。たとえばvimやnanoはおろか,edもインストールされていないため,パッケージのインストールをせずにファイルを編集するにはsedとawkを駆使する必要があります。

その点,Ubuntu Cloud Imagesにあるクラウドイメージなら,各種クラウドサービスの最大公約数的なパッケージ構成になっているため,ほぼサーバー版のUbuntuと同じです。いろいろなイメージが用意されていますが(リリース名⁠⁠-server-cloudimg-⁠アーキテクチャー⁠⁠-root.tar.xzを選んでください。しかしながらUbuntu Baseが27MiB程度なのに対して,Cloud Imagesは327MiBぐらいとサイズは10倍以上異なります。

ここではUbuntu Baseをダウンロードしてbwrapで切り替えてみましょう。

$ wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.3-base-amd64.tar.gz
$ mkdir rootfs
$ tar xvf ubuntu-base-20.04.3-base-amd64.tar.gz -C rootfs
$ echo 'APT::Sandbox::User "root";' > rootfs/etc/apt/apt.conf.d/90run-as-root

最後のコマンドだけ説明が必要です。最近のAptはパッケージのインターネットからのダウンロードや署名の検証などを,管理者権限ではなく_aptユーザーで行うようになっています。つまりaptコマンドの中で,このユーザーに変わらなくてはなりません。しかしながら,今回はできるだけシンプルにbwrapを使うようにする都合上,単に「コンテナーの中のrootを,ホストの非特権ユーザー」にのみマッピングしています。よってここでは_aptユーザーへのマッピングを用意したり,ダウンロードしたルートファイルシステムのパーミッションを正しく設定することは諦めて,Apt側の設定で「常に管理者権限で実行する」ように設定しました。

これでルートファイルシステムの作成は完了です。最後にそのルートファイルシステムにbwrapで「ログイン」してしまいましょう。

$ bwrap --bind rootfs/ / --ro-bind /etc/resolv.conf /etc/resolv.conf \
    --dev /dev --chdir / --uid 0 --gid 0 --unshare-pid --unshare-user /bin/bash

root@nuc:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

root@nuc:/# apt update
Hit:1 http://security.ubuntu.com/ubuntu focal-security InRelease
(以下略)

今回,ネットワークについてはホストのそれをそのまま相乗りするため,--unshare-netは指定していません。ただしDNSによる名前解決は必要になるため--ro-bind /etc/resolv.conf /etc/resolv.confでホストのresolv設定をそのままコンテナーからも見えるようにしました。

これで管理者権限を取得することなく,コンテナーの中でパッケージのインストール等が使えるようになります。どの操作も基本的にホストから見ると,非特権ユーザーとして動いています。もちろん任意のデバイスファイルのアクセスやカーネルモジュールのロードなど,ホストの特権が必要になる処理は実行できません。もしろんsystemdも動いていないため,サービスの起動も一苦労です。このようにできることは限られてはしまいますが,できるだけ余計なパッケージをインストールせずに環境を整えるという意味では役に立つことでしょう。

ちなみに今回のコンテナーは隔離度が低く「セキュア」ではありません。一般的に非特権コンテナーと言うときはAppArmorなどの矯正アクセス制御やseccomp等を駆使して,コンテナーからできることを限定しています。まともにコンテナーとして運用したいなら,既存のシステムを使うようにしましょう。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。