chroot + overlayfs + btrfsスナップショット でホスト環境の複製をjailする

いわゆるchroot jailです。このネタもぐぐれば山ほど出てきますので、一捻りしてお送ります。

# chroot jail の基本的な作り方

chroot jail の何たるかについては、ぐぐれば一山いくらってくらいの解説記事がありますので省略。

ここでは chroot jail としてフツーに操作できるLinux環境を作る際に用意しなければならないディレクトリを解説します。

参考文献: [chrootする際には/procと/devだけでなく/sysもmountしよう - Dマイナー志向](http://d.hatena.ne.jp/tmatsuu/20101225/1293262061)

後は、ぐぐったのと実際にやってみたのとで調べた結果、下記手順がよろしかろうという結論です。linuxカーネルとその周辺の話題を英語も厭わずキチッと調べると正確な所がハッキリすると思うのですが、今回はそこまで根性を出す事が出来ませんでした:sweat: 要するに /proc /dev /sys を mount --rbind するのではなくて、ファイルシステムをマウントするようにしてみました、というそれだけの事です。

```
# mkdir proc sys dev
# mount -t proc proc proc
# mount -t devtmpfs dev dev
# mount -t sysfs sys sys
```

（2017.06.09.追記）
更に次のディレクトリも必要なようです。参考文献: [tmpfs - ArchLinux](https://wiki.archlinuxjp.org/index.php/Tmpfs)

```
# mkdir tmp
# mount -t tmpfs tmpfs tmp
# mount -t tmpfs tmpfs dev/shm
```

ちなみにdevptsは使ってはダメとの事。参考文献: [OSの心臓、glibcのコンパイルとchroot (3/3) - LFSで作って学ぶLinuxの仕組み（3）](http://www.atmarkit.co.jp/ait/articles/0302/18/news002_3.html)
devfsとdevtmpfsの関係については[7.3.1. 開発経緯 - 7.3. デバイスとモジュールの扱いについて - 第7章 システム設定とブートスクリプト - Linux From Scratch - Version 7.6](http://lfsbookja.osdn.jp/7.6.ja/chapter07/udev.html)が参考になります。
（2017.06.09.追記ここまで）

そして最後に chroot するワケですが、当然これだけでは /bin/bash が無くてエラーが発生します。

```
# chroot .
chroot: failed to run command '/bin/bash': No such file or directory
```

そこで /bin/bash を始めとした必要なコマンド全てをリンクなり何なりします。その結果の１つが例えば [jailing - chroot jailを構築・運用するためのスクリプトを書いた - Kazuho's Weblog](http://blog.kazuhooku.com/2015/05/jailing-chroot-jail.html) です（と私は理解しました）。

ここでホスト環境全体の複製を作ってしまえばmountの数が減って楽できるだろう、それこそ手作業でも全く問題無い程度まで手間が軽減されるのではないか、と考えたのでした。逆に、ホスト環境の複製という事にして困る事は何かな、と。

# overlayfs

ホスト環境全体を丸々複製するならoverlayfsを利用するのが便利です。しかしxfsを使用していると条件があったりして微妙です。その解説は、例えば[DockerでOverlayFS over XFSするために](http://qiita.com/amatsus/items/aa2a58b0d5800312b6fa)など。

幸いにして私の環境は[ブート環境からすべて丸ごとbtrfs](http://qiita.com/katz_engineer/items/88250ee4ea51edb327f0#パーティションパーティションのフォーマット)です。overlayfsを使うに当たっての問題はありません。

但し、overlayfs自身の問題があるようです。この制約について触れている文章がほとんど無いようなので、最近のoverlayfsでは解消されたのでしょうか？良くわかりません。御存知の方は是非ご教示ください。

[下のファイルシステムへの変更 - overlayfs.txt - Linux カーネル文書](https://sites.google.com/site/kandamotohiro/linux/overlayfs-txt)
 → [英語の原文(?)はこちら](https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt)

> 下のファイルシステムへの変更
>
> オーバレイがマウントされていない時のオフライン変更は、上と下のツリーに対して可能です。
> マウントされたオーバレイファイルシステムの一部となっている時の元となるファイルシステムへの変更は許されません。元となるファイルシステムが変更された場合、オーバレイの振る舞いは未定義です。ただ、クラッシュあるいはデッドロックにはならないでしょう。

なかなか刺激的な話が書かれています:sweat: 本気でoverlayfsを使い倒そうとするなら結構な制限だと思うのですが、そうでもないのでしょうか。まぁDVDとかにかぶせて使うだけなら全く困りませんが… そんな世間様の動向は置いといて、実際に今回私がやりたかったのは下記のような感じです。

```
# mkdir overlayroot upper work
# mount -t overlay overlay -o lowerdir=/,upperdir=upper,workdir=work overlayroot
```

ですが、これはダメだと。なぜならば、このoverlayが生きている間はホスト環境を更新する事が出来ません。pacman とか、ちょっとしたメモ書きとか、chroot jailの追加とか、一切合切ダメです。

それならそれで対策を考えなければなりません。そこで目を付けたのが btrfs のスナップショットでした。

# btrfsスナップショット

スナップショットを撮って、それを下層ディレクトリとしてoverlayします。

```
# btrfs subvolume snapshot / root-snapshot
Create a snapshot of '/' in './root-snapshot'
# mount -t overlay overlay -o lowerdir=root-snapshot,upperdir=upper,workdir=work overlayroot
```

後は、このスナップショット root-snapshot には書き込みや削除等々一切しないという運用ルールを決めれば良い。気を付けなきゃいけないのはスナップショットだけで、現在使用中のルート / 以下は普通に使えます。問題にはならないでしょう。ビバ・スナップショット。

# overlayfsのちょっと便利な機能

書き込み禁止。overlayfsとは関係無く、mountコマンドの普通のオプション -r ですが。

```
# mount -t overlay overlay -o lowerdir=root-snapshot,upperdir=upper,workdir=work overlayroot -r
# echo test >overlayroot/test
-bash: overlayroot/test: Read-only file system
```

下層ディレクトリの複数指定。コロン:で区切ると複数のディレクトリを下層として指定できるようです。これは重要な機能だと思うんですが、触れている記事はほとんど無いようですね。
参考文献: [第18回　Linuxカーネルのコンテナ機能 [7] ─ overlayfs overlayfsの将来 - LXCで学ぶコンテナ入門 －軽量仮想化環境を実現する技術](http://gihyo.jp/admin/serial/01/linux_containers/0018?page=3)

```
# mkdir a b u w m
# echo a >a/a.txt
# echo b >b/b.txt
# mount -t overlay overlay -o lowerdir=a:b,upperdir=u,workdir=w m
# ls m
a.txt  b.txt
```

# セキュリティについての注意

そもそもchroot jailに強固なセキュリティを求めてはいけません。ちょこっとディレクトリ指定を間違った位ではシステムを壊す事はありません、という程度でしょう。だからその程度でシステムクラックは難しい、逆に言うと本気になってそれ以上の方法を試すならヤラれる可能性は高い。実際、例えば[3.13 Chroot Jailの構成および使用（Oracle® Linux セキュリティ・ガイド リリース6）](https://docs.oracle.com/cd/E39368_01/b72804/ol_cj_sec.html)には次のような注意が目立つ場所に書かれていました。

> chrootメカニズムでは、意図的な改ざんや特権ユーザーによるシステム・デバイスへの低レベルのアクセスを防ぐことはできません。たとえば、chroot rootユーザーはデバイス・ノードを作成し、その上にファイル・システムをマウントできます。また、root権限を取得し、chroot()を使用して現在の作業ディレクトリを実際のrootディレクトリに変更できた場合、プログラムはchroot jailから脱出できます。

後者のchroot jailからの脱出は、確か有名な話でしたよね。前者については、例えば上述の overlayroot 以降で:

```
# chroot overlayroot
# mount -t devtmpfs dev /dev
# mount /dev/sda /mnt
# ls /mnt
@
# ls /mnt/@
bin  boot  dev  etc  home  lib  lib64  mnt  opt  proc  root  run  sbin  src  sys  tmp  usr  var
```

という感じで、root権限を持っていてコマンドを自由に実行できる状態であれば、デバイスをマウントできてしまいます。という事は、その中を自由自在に読み書きできてしまうワケで… ホスト環境のファイル全部ダダ漏れです。

世間で言われているほど、chroot jail をセキュリティ的に信頼する事は出来ません。

# chroot jailの価値

それでもchroot jailには価値があります。[システム開発の際に用意すべき環境](http://qiita.com/katz_engineer/items/4a0161459133cf2ec11d)の記事で触れたような、テストやレビューその他の理由で複数の環境を用意しなければならない状況もその１つでしょう。chroot jailならば極めて低コストで沢山の環境を用意する事が出来ます。というか、個人でそういう複数環境を用意したかったのでこれを考えたのでした。

低コストで複数環境と言えばDockerですが、私はDockerを再発明したい:grin: