ifconfig_lo0_alias0="inet 127.0.0.115/32"
這行是設定 jail 要用的 IP。一般是用 alias 的方式。 再加上這幾行:
jail_enable="YES"
jail_list="conair"
jail_conair_hostname="conair"
jail_conair_ip="127.0.0.115"
jail_conair_rootdir="/usr/jails/conair"
jail_conair_exec="/bin/sh /etc/rc"
jail_conair_devfs_enable="YES"
jail_conair_devfs_ruleset="devfsrules_jail"
上面這幾行是 FreeBSD 5.3 之後才有的設定。jail_list 是設定系統裡面 有那些 jail(s)。jail_xyz_hostname, jail_xyz_ip, jail_xyz_rootdir 是每個 jail (上述範例的 xyz 以 conair 代入) 單獨的相關設定, 依實際 情況而有所不同。jail_xyz_exec, jail_xyz_devfs_enable, 以及 jail_xyz_devfs_ruleset, 基本上是固定的, 不用更動。
Jail 設定
多使用者模式 jail, 就當一般的 FreeBSD 系統來設定吧! 照上述的方法進 入 jail 單人模式, 把以下幾個檔案設定好: /etc/hosts第 13 和 14 行, 該 jail 的 IP 和 hostname 要設好。 /etc/resolv.conf至少放 DNS server。 /etc/master.passwd這就是系統帳號存放的地方了。重點就是, 要新增一個可以遠端登入的 帳號。最簡單的方法是用 adduser 或者 sysinstall 開好就行了。 root 的密碼也要設好。 /etc/group別忘了把自己的帳號加進 wheel。 /etc/rc.confsshd_enable="YES"開啟 sshd 才能遠端登入, 因為 jail 是沒有 console 的。 /etc/ssh/ssh_host_*key自 5.3 起, 第一次啟動 sshd 的時候, 會要求使用者打一些資料進去, 幫助系統產生 ssh key。不過呢, jail 啟動的時候是沒有 terminal 的, 這會導致第一次啟動 jail 的時候有 5 分鐘的停頓。有以下兩個 方法, 可以避開這 5 分鐘的延遲:1. 手動執行 /etc/rc.d/sshd start, 亂打一些東西進去。2. 手動執行下列三行指令:/usr/bin/ssh-keygen -t rsa1 -b 1024 -f /etc/ssh/ssh_host_key -N ''/usr/bin/ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ''/usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''/etc/crontab在 jail 裡面 adjkerntz 要特別關掉。至於其它的 periodic jobs, 依各人需要自行調整。 以上是基本的設定, 接下來看 jail 裡其它的設定檔: /etc/periodic.confperidoc daily 有些事 jail 裡面不用做:
daily_status_security_chksetuid_enable="NO"
daily_status_security_chkmounts_enable="NO"
daily_status_disks_enable="NO"
daily_status_security_kernelmsg_enable="NO"
daily_status_network_enable="NO"
關於 mail, 因為 jail 沒有 127.0.0.1, 所以它無法像一般的 sendmail只聽 127.0.0.1, 反而會直接聽某某 IP。因此 sendmail 要整個關掉。/etc/rc.confsendmail_enable="NONE" 這時候在 /etc/periodic.conf 也要做相對應的修改, 叫它不要寄信出來:/etc/periodic.confdaily_output="/var/log/daily.output"daily_status_security_output="/var/log/security.output"weekly_output="/var/log/weekly.output"monthly_output="/var/log/monthly.output"沒有閱讀 periodic output 習慣的人, 可以將它們都改成 /dev/null。
啟動 jail
到此在 host 上以及 jail 內, 該設定的都差不多了。自 5.3 起, FreeBSD 提供了非常方便的 jail 管理機制, 可以任意的啟動, 關閉任一個 jail。 現在來試一試。 在主系統上# /etc/rc.d/jail start conair 接著 ssh 127.0.0.115, 用剛剛的新加的帳號登入。到目前都沒問題的話, 恭禧你, 已經成功的安裝好一個 jail 了! 接下來就依一般使用 FreeBSD 的方式來使用該 jail 吧。
/etc/rc.d/jail 用法
# /etc/rc.d/jail stop 停止列在 /etc/rc.conf jail_list 中的所有 jails # /etc/rc.d/jail start啟動列在 /etc/rc.conf jail_list 中的所有 jails # /etc/rc.d/jail stop jail1停止列在 /etc/rc.conf jail_list 中的特定 jail # /etc/rc.d/jail start jail1啟動列在 /etc/rc.conf jail_list 中的特定 jail
進階議題
網路連通問題 Host 上若同時設有對內及對外的 IP, 且設給 jail 內部的 private IP, 那麼 jail 設定好後, 還需在 host 上設定 NAT, jail 才能對外連線。在 其它場合, 例如 jail 是對 public IP, 或 jail 及 host 同為 private IP, 已外有執行 NAT 的主機, 則無此限制。
Share ports tree among jails 幾乎所有人使用 jail 的第一個疑問就是, 要怎麼共享 ports tree? 有很 多方法, 例如 nullfs, unionfs, hardlink, NFS 等。mount_nullfs(8) 和 mount_unionfs(8) 看起來很嚇人 (see BUGS), hardlink 也不是好主意。 比較通用的方式是用 nfs。 如何設定 NFS server 和 NFS client 不在本文的討論範圍內, 故將焦點集 中在如何在 jail 內正常使用 NFS mount 進來的 ports tree。 首先, 為了效率, 以及 jails 之間不互相干擾 make ports 程序, 要將 work 目錄調開。設定的方法是把 WRKDIRPREFIX 設定到一個不在 ports tree 裡面的地方。設定的地方是 jail 的 /etc/make.conf, 例如: WRKDIRPREFIX=/tmp 另外還有一個常用的工具程式, portupgrade, 也會寫東西進 /usr/ports, 這也要調開。可以設定的地方之一是 jail 的/etc/login.conf, 裡面多設 一個環境變數, 把 PORTS_DBDIR 改到 /var/db/pkg。除此之外, jail 內的 /etc/csh.login, /etc/profile 也都可以設定這個環境變數。
在 jail 中跑 DNS server FreeBSD 5.3 內建的 bind 已經昇級到 bind 9, 而且預設是以 chroot (不 是 jail!) 方式執行。於 jail 中再 chroot 是沒有問題的, 不過由於 5.3 還有 devfs, 而預設 bind 9 在執行的時候還會再 mount devfs, 這在 jail 內會造成問題。因此要對這點要做點特別調整。把 mount devfs 以及 停止 devfs 相關動作的方式, 是在 jail 內的 /etc/rc.conf 中, 加入 named_chroot_autoupdate="NO" 不過目前為止 named 尚不能正確啟動。接下來解析由 /etc/rc.d/named 啟 動 bind 時需要那些元素:
配置完成的 named_chrootdir (預設是 /var/named)
需要 /dev/null 和 /dev/random
/etc/namedb symbolic link 到 /var/named/etc/namedb 目前欠的就是第 2 點提到的兩個 device nodes。建立它的方式是由 host 中去建立: cd /usr/jails/conair/var/named/devmknod random c 245 0; mknod null c 2 2這樣就可以了。 好了, 接下來一切照舊。:) 在新裝好的 jail 中啟動 bind 的話, 建議先 跑一下 make-localhost, 還有調整一下 named.conf。在 FreeBSD 5.3 裡 面, bind 預設也只有聽 localhost, 不對外服務。而 jail 裡面是沒有 127.0.0.1 的, 所以要把 listen-on { 127.0.0.1; }; 這裡的 127.0.0.1 換成配給 jail 的 IP。
Jail 管理基本知識及工具
以下以列舉在 FreeBSD 5.3 上, 系統提供的 jail 相關訊息以及工具, 及實際應用。 ps利用 ps 指令可以得知某 process 是在 host 或是某一 jail 內運行。在 jail 內的 process, 於 ps 顯示時, 會在 STAT 欄位顯示 J # ps ax grep J這個指令可以列出目前處於 jail 內的 process。但儘止於此, 要得知是屬於那一個 jail 則要用到 procfs。 /proc 在 host 上, 要得知某 process 是屬於何 jail, 可以利用 /proc。但是 5.3 預設並沒有把 /proc 掛上系統, 所以得在 /etc/fstab 加上這一行:
/proc /proc procfs rw 0 0
把 /proc 掛上系統
# mount /proc
把 /proc mount 上來後, 以如下方式觀看該 process 的 status:# cat /proc/
security.jail.set_hostname_allowed 可於 host 環境中設定, 為 1 的時候在 jail 中可以更改該 jail 的 hostname。預設為 1。
security.jail.socket_unixiproute_only 可於 host 環境中設定, 為 1 的時候表示 host 只幫 jail 把 IP 封包往外送(FreeBSD 還支援 Netware, Appletalk 等等通訊協定)。 預設為 1。
security.jail.sysvipc_allowed 可於 host 環境中設定, 為 1 的時候表示可以在 jail 中使用 shared memory, message queues, 還有 semaphores。預設為 0。 要在 jail 中提供用到上述三者的服務, 如 BBS, 或者 PostgreSQL 時, 要將它設為 1。
security.jail.getfsstatroot_only 可於 host 環境中設定, 為 1 的時候表示在 jail 裡面可以看到 其它 mount point, 反之則只能看到 jail 所在的 mount point。 預設為 1。
security.jail.allow_raw_sockets 可於 host 環境中設定, 為 1 的時候表示在 jail 裡面可以產生 raw sockets。最大的用處是允許在 jail 中使用 ping 指令。預 設為 0。
security.jail.jailed 在 host 和 jail 環境中都是唯讀的, 用途在於幫助 /etc/rc.d 的 shell scripts 判斷是不是身處 jail 之中。 可以直接使用 sysctl 指令, 亦可在 /etc/sysctl.conf 或 /boot/loader.conf 中, 設定上述的 kernel state。
Jail 昇級
Jail 內的 FreeBSD 系統, 和一般的 FreeBSD 系統一樣, 也是要昇級的。 不過手續稍微不一樣。其一, 要先在 host 上 buildworld 好。其二, 在 installworld 的時候要指定 DESTDIR。其三, mergemaster 時要多接一個 -D 的參數。以 conair 為例, 在 host 上執行下列指令:
# cd /usr/src
# make installworld DESTDIR=/usr/jails/conair
# mergemaster -D /usr/jails/conair
這些過程比較複雜且煩瑣, 處理的時候要花點耐心。
結語
自 FreeBSD 4.0 起, jail 為 FreeBSD 提供了良好的資訊安全機制, 更佳 的硬體資源利用方式, 以及更方便的系統管理模式。圍繞著 jail 所衍生的 資安機制, 系統工具, 及管理技巧, 也一直持續的在發展。除了 FreeBSD 5.3 本身之外, 於 ports 中還有許多本文尚未提及的 jail 管理工具, 有 興趣的人可以嘗試看看。如今 jail 已是被廣泛應用, 以及持續發展的技術, 如果您尚未使用過 jail, 何不從現在開始?
延伸閱讀
ps(1), killall(1), jail(2), login.conf(5), sysctl.conf(5), loader.conf(5), jail(8), jexec(8), jls(8), sysctl(8)