今日からFreeBSD Advent Calendar 2020が始まります。
第一日目の今日は、FreeBSD Jailを活用する話を書こうと思います。
背景
UNIX系OSでちょっとした実験・作業用にまっさらな環境を用意したいことは多々あります。
FreeBSDであればJail、LinuxであればDockerでコンテナ環境を作成するかと思いますが、シェルやエディタ、自分がよく使うツールはあらかじめコンテナに含めた状態にしておきたいものです。加えて、コンテナを作成したら ssh
でログインできるような形にもしておきたいものです。
過去に以下の記事でFreeBSD Jailでコンテナを構築する手順を紹介していますが、この記事では手動でコマンドを実行してコンテナを作成するという方法でした。
このコンテナ環境をさらに改良し、FreeBSD Jailでのコンテナ構築とssh設定、シェルの設定ファイルなどの投入等をスクリプトで行う形の運用が実現できたので、今回はその環境の紹介をさせてもらおうと思います。
コンテナで実現したいもの
-
ssh
でコンテナにログインできるようにしたい。 - VNCでGUIを利用できるようにしたい。
- シェルやエディタの設定等をコンテナ構築時に配置しておきたい。
コンテナ環境の構築
ホストOS側の設定
/etc/rc.conf
と /etc/pf.conf
の設定は以前の紹介記事の内容のままでOKです。
- /etc/rc.confの設定
- /etc/pf.confの設定
Jailコンテナ用に以下の手順で配布物を用意します。
ホストOS側でのファイルは一は以下のようになります。ファイル中の create_container.sh
remove_container.sh
が今回紹介するコンテナ作成・削除用の簡易スクリプトになります。また、コンテナに配置したいユーザ用の設定ファイルを JAIL_FAILS
ディレクトリに入れておきます。
.
|-- FBSD12_DIST
| |-- base.txz
| `-- kernel.txz
|-- JAIL_FAILS
| |-- authorized_keys
| |-- create_user.sh
| |-- dot.bashrc
| |-- dot.emacs
| |-- dot.gitconfig
| |-- dot.profile
| |-- dot.screenrc
| |-- sshd_config
| |-- sudoers
| `-- user__ssh_config
|-- create_container.sh
`-- remove_container.sh
コンテナを作成するスクリプト
#!/bin/sh
# 引数には作成したいコンテナ名を指定します。
if [ $# -eq 0 ]; then
echo 'Err: too few argument.'
echo ' ./easy_setup.sh <jail_name>'
exit 1
fi
jail_name=$1
if [ -d ${jail_name} ]; then
echo "Err: Jail already exists. ${jail_name}"
exit 1
fi
# コンテナ名でディレクトリを作成し、必要なファイルを配置します。
mkdir -p ${jail_name}
# FreeBSD配布物を展開します。
echo '-=> Extract FreeBSD files.'
tar Jxfp FBSD12_DIST/base.txz -C ./${jail_name}
tar Jxfp FBSD12_DIST/kernel.txz -C ./${jail_name}
# 必要なファイルをコンテナ用ディレクトリに配置します。
cp /etc/resolv.conf ./${jail_name}/etc/resolv.conf
echo 'sshd_enable="YES"' | sudo tee -a ./${jail_name}/etc/rc.conf
cat JAIL_FAILS/sshd_config | sudo tee -a ./${jail_name}/etc/ssh/sshd_config
cp JAIL_FAILS/sudoers ./${jail_name}/tmp
cp JAIL_FAILS/authorized_keys ./${jail_name}/tmp
cp JAIL_FAILS/create_user.sh ./${jail_name}/tmp
cp JAIL_FAILS/dot.profile ./${jail_name}/tmp
cp JAIL_FAILS/dot.bashrc ./${jail_name}/tmp
cp JAIL_FAILS/dot.emacs ./${jail_name}/tmp
cp JAIL_FAILS/dot.screenrc ./${jail_name}/tmp
# どのコンテナか識別しやすいように、modファイルを設定します。
# (sshログイン時にmodファイルが表示されます)
cat <<_EOF > ./${jail_name}/etc/motd
FreeBSD `freebsd-version`
*** ${jail_name} ***
_EOF
# Jail IDとして使用する値をjail.confから抽出します。
cur_max_ip=`grep 'ip4.addr' /etc/jail.conf | sed -e "s/;.*$//" -e "s/^.*\.//" | sort | tail -n1`
if [ -z "$cur_max_ip" ]; then
new_ip=10
else
new_ip=$((cur_max_ip + 1))
fi
# 作成するコンテナのjail.confエントリを追記します。
cat <<_EOF | tee -a /etc/jail.conf
${jail_name} {
path = /enc/jail/${jail_name};
ip4.addr = 172.16.0.${new_ip};
ip6.addr = fe80::11;
host.hostname = ${jail_name}.furandon.net;
allow.raw_sockets;
exec.start = "/bin/sh /etc/rc";
# exec.stop = "/bin/sh /etc/rc.shutdown";
interface = lo0;
mount.devfs;
persist;
}
_EOF
# jailコマンドの起動例を表示します。
cat <<_EOF
Jail command.
$ sudo service jail onestart ${jail_name}
$ sudo service jail onestop ${jail_name}
_EOF
# にコンテナを起動します。
echo -n "start jail '${jail_name}'..."
sudo service jail onestart ${jail_name}
if [ $? -eq 0 ]; then
# コンテナが起動できたら、初期化用のスクリプトを実行します。
jexec ${jail_name} sh /tmp/create_user.sh
echo 'OK (^_^)'
jls
else
echo 'FAIL (T_T)'
fi
上記のスクリプトでコンテナを起動すると、そのまま初期化用のスクリプトを実行します。
このスクリプトでは、 pkg update
の実行と JAIL_FAILS
ディレクトリからコピーしてきた各種設定ファイルの配置を行います。
#!/bin/sh
pkg update
pkg install sudo bash
cp /tmp/sudoers /usr/local/etc/sudoers
_USER_NAME=fbsd
_FULL_NAME="freebsd_jail_user"
_UID=1001
# ユーザの追加。
pw groupadd -n users -g 1001
pw useradd -n $_USER_NAME -c $_FULL_NAME -g users -G wheel -G wheel -s /usr/local/bin/bash -u $_UID -m
# ssh鍵の配置。
cd /home/$_USER_NAME
sudo -i -u $_USER_NAME mkdir tmp
sudo -i -u $_USER_NAME mkdir -m 700 .ssh
sudo -i -u $_USER_NAME cp /tmp/authorized_keys .ssh/authorized_keys
chown $_USER_NAME:users .ssh/authorized_keys
sudo -i -u $_USER_NAME chmod 600 .ssh/authorized_keys
sudo -i -u $_USER_NAME cp /tmp/user__ssh_config .ssh/config
chown $_USER_NAME:users .ssh/config
sudo -i -u $_USER_NAME chmod 600 .ssh/config
sudo -i -u $_USER_NAME cp /tmp/dot.gitconfig .gitconfig
chown $_USER_NAME:users .gitconfig
sudo -i -u $_USER_NAME chmod 600 .gitconfig
# タイムゾーンの設定。
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
chmod 444 /etc/localtime
echo "Asia/Tokyo" > /var/db/zoneinfo
chmod 644 /var/db/zoneinfo
# ユーザ用の設定ファイルのコピー。
[ -f /tmp/dot.bashrc ] && sudo -i -u $_USER_NAME cp /tmp/dot.bashrc /home/$_USER_NAME/.bashrc
[ -f /tmp/dot.profile ] && sudo -i -u $_USER_NAME cp /tmp/dot.profile /home/$_USER_NAME/.profile
[ -f /tmp/dot.emacs ] && sudo -i -u $_USER_NAME cp /tmp/dot.emacs /home/$_USER_NAME/.emacs
[ -f /tmp/dot.screenrc ] && sudo -i -u $_USER_NAME cp /tmp/dot.screenrc /home/$_USER_NAME/.screenrc
コンテナを削除するスクリプト
コンテナが不要になった場合もスクリプト経由で削除できるようにしておきます。
#!/bin/sh
if [ $# -eq 0 ]; then
echo 'Err: too few argument.'
echo ' remove_container.sh <jail_name>'
exit 1
fi
jail_name=$1
service jail onestop $jail_name \
&& chflags -R noschg $jail_name \
&& rm -rf $jail_name \
&& echo "removed '$jail_name'"
実際にコンテナを作成・削除してみる
以下のような感じで簡単にコンテナの作成・削除が行えます。
$ # コンテナの作成。
$ sudo ./create_container.sh tmp02
...
$ jls
JID IP Address Hostname Path
1 172.16.0.10 tmp01.furandon.net /enc/jail/tmp01
2 172.16.0.11 tmp02.furandon.net /enc/jail/tmp02
$
$ # コンテナの削除。
$ sudo ./remove_container.sh tmp02
まとめ
私の環境で使用しているJailコンテナ管理用スクリプトを紹介してみました。sshで接続できる+自分用の設定が投入された状態のコンテナが簡単に作成できるので、ちょっとした環境を作成したいんだけど...という方はお試しいただければと思います。
また、この環境はJailコンテナを配置するストレージをGEOM/GELIで暗号化して運用しています。明日はこのあたりの話を紹介できればと思います。