看守してみたかった
せっかく FreeBSD なので、用途ごとに環境を Jail で分けてすっきりさせたかった。
まっさらにしたのを機に Jail はじめました。
環境
どういう構成にするか?
ホストとなる環境では極力デーモンを走らせず、各 Jail 内に収めるようにする。 こちらの記事を大いに参考にさせていただきました。
これと同じように、外からの SSH は pf によるポートフォワードでポートごとに Jail を振り分けています。
再インストール前は pf ではなく ipfw を使っていたのですが、ipfw で NAT しつつ Jail でサービスを公開するという方法がよく分からず頓挫していたんですよね…pf だと楽ちんでした。
HTTP(S) に関しては、玄関口となる Jail を1つ立てて、nginx でホスト名を見て振り分けする予定。
Jail つくるぞ
id:dankogai さんのこちらの記事を参考に。とりあえずやることがさらっと書いてあって分かりやすかった。
まずはホスト環境で、Jail 毎に IP アドレスを用意します。 弾さんの記事にもあるように、別にホスト環境の IP アドレスをそのまま使ってもいいようですが、分けたほうがよりスッキリするかなあと思いました。
/etc/rc.conf
(前略) # lo0 に IP アドレスを振る ifconfig_lo0="inet 127.0.0.1" ifconfig_lo0_alias0="inet 10.0.0.254 10.0.0.255 netmask 255.255.255.0" ifconfig_lo0_alias1="inet 10.0.0.11" ifconfig_lo0_alias2="inet 10.0.0.12" : : # pf 関係 pf_enable="YES" pf_rules="/etc/pf.conf" pf_flags="" pflog_enable="YES" pflog_logfile="/var/log/pflog" pflog_flags="" # Jail jail_enable="YES" (以下略)
こんな感じで、必要なだけ IP アドレスを列挙。 pf と Jail を有効にしておきます。
/etc/pf.conf
rc.conf で出てきた pf.conf を用意します。pf のルールを指定するファイルです。
(最初の記事の例のほとんどそのままです)
(前略) # external interface ext_if="vtnet0" # internal interface int_if="lo0" # NW setting for internal NW table <private> const { 10.0.0.0/24 } # IP mascarade nat on $ext_if inet from ($int_if) to ! <private> -> ($ext_if) ## ssh rdr pass on $ext_if proto tcp from any to ($ext_if) port 2211 -> 10.0.0.11 port 22 rdr pass on $ext_if proto tcp from any to ($ext_if) port 2212 -> 10.0.0.12 port 22 : : ## httpd rdr pass on $ext_if proto tcp from any to ($ext_if) port http -> 10.0.0.12 port http rdr pass on $ext_if proto tcp from any to ($ext_if) port https -> 10.0.0.12 port https # packet filter block in log all pass in proto tcp to any port ssh pass out all keep state
ここで、10.0.0.12 を HTTP(S) の窓口に割り振るため、SSH 以外に HTTP(S) のポートをそちらにパスさせる設定を追加しています。 また、ホスト環境にも SSH したいのでそれも追加。
/etc/jail.conf
# common exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.clean; mount.devfs; interface = lo0; path = "/jails/$name"; host.hostname = $name; allow.chflags; allow.raw_sockets; # each jail base { ip4.addr = 10.0.0.11; } httpd { ip4.addr = 10.0.0.12; }
"# each jail" の下のように書いておくと起動時にいちいち IP アドレスとか指定しなくて良くて楽なんですが、ここに書かれた Jail はホストの起動時に自動的に start されてしまうようです。何か書けば止められるのかな…
rc.conf、pf.conf、jail.conf が整ったら一旦再起動しましょう。
Jail 環境の雛形を作る
FreeBSD の再インストール時に、ルートファイルシステムを ZFS にしておきました。Jail 毎に ZFS の dataset を割り当てるととても楽そうだからです。
まずは、base という名前で、Jail 環境の雛形を作ってみます。
# zfs create -o mountpoint=/jails zroot/jails # zfs create zroot/jails/base # bsdinstall jail /jails/base
見慣れたインストーラーでインストールが始まります。base と lib32 があればとりあえず動きます。
Jail 起動
# service jail start base
として起動します。うまく起動できれば、
# jls JID IP Address Hostname Path 1 10.0.0.11 base.example.com /jails/base
みたいな感じでリストに表示されます。
次に、Jail 環境のコンソールに入ってみます。
# jexec base root@base:/ #
こうなればとりあえず Jail の起動成功です。
できたら、この段階で freebsd-update もやっておきましょう(作業は省略)。
ひと通り眺めたら、Jail のシェルを抜けてから
# service jail stop base
で止めておきます。
雛形環境の複製
ZFS の本領発揮です。
# zfs snapshot zroot/jails/base@12.0p11
これで dataset のスナップショットが取れます。@ の後ろはスナップショットの分かりやすい名前を付けます(ここではリリース番号+パッチ番号)。
そしてこれを複製します。
# zfs clone zroot/jails/base@12.0p11 zroot/jails/httpd
これで、base が httpd にそっくりクローンされました。
名前を変えて繰り返せば、雛形からいくらでも複製できます。
ちなみに、不要になった環境は
# zfs destroy zroot/jails/httpd
とすれば消え去ります。スナップショットも destroy で消せますが、クローン元となっているファイルシステムやスナップショットは、クローンした dataset があるうちは消せません。-R スイッチを付ければクローンもろとも消すことはできます。*1
あとは、# jexec httpd
して、普通の FreeBSD 環境と同じように必要なユーザーを adduser したり、パッケージを pkg add したりして環境を作っていきましょう。