Создание jail во FreeBsd

Иногда бывает полезно иметь в работающей системе еще одну или несколько виртуальных систем.
Во FreeBsd средством виртуализации является jail. Примеров применения множество: вы можете создавать jailы на своем сервере для знакомых или клиентов, и это обезопасит вашу систему от их проделок, вы можете поместить (это даже рекомендуется) разные сервисы в отдельные jail, например, mysql в одной системе, apache в другой. Таким образом, взлом mysql сервера ничем не грозит веб серверу.

Управлять jailами я буду при помощи ezjail, конечно, труъ-админы могут катать километры шелл скриптов и управлять всем вручную, но уж извольте..
Для начала установим ezjail
cd /usr/ports/sysutils/ezjail
make install clean
rehash


Теперь проинсталируемся
ezjail-admin install


Если вы еще не собирали мир в вашей системе, то придется это сделать.
Процедура длительная, может занять несколько часов, и потребуется ребут.
cd /usr/scr
make buildworld
make buildkernel
make installkernel
reboot


На сообщения mergemaster можно нажимать enter, конфликтов быть не должно.
mergemaster -p
cd /usr/src
make installworld
mergemaster
reboot


Теперь после сборки мира и 2 ребутов можно проапргейдить наш jail (тоже не быстрое дело)
ejzail-admin update -p -i


Для успешной работы jail ему необходим ip адрес. Внешний ip адрес каждому jail это довольно жирно, поэтому давайте выделим ему локальный ip, например, 192.168.0.11
Давайте добавим этот адрес в нашу сетевую карту em0, а также не забудем разместить запись в /etc/rc.conf чтобы при перезагрузке ничего не потерялось
ifconfig em0 alias 192.168.0.11 netmask 0xffffffff
echo 'ifconfig_em0_alias1="inet 192.168.0.11  netmask 255.255.255.0"' >> /etc/rc.conf


Важным условием выбора адреса является то, чтобы этот ип адрес не использовал ниодин сервис в вашей системе.
Пробуем создать jail
ezjail-admin create -r /usr/home/jails/test test 192.168.0.11


Скорее всего вы получите предупреждения, что ip 192.168.0.11 слушается другими сервисами, типа такого
  This may cause some confusion, here they are:
mysql    mysqld     6923  11 tcp4 6 *:3306                *:*
www      proftpd    1400  0  tcp4 6 *:21                  *:*
root     syslogd    1060  9  udp4   *:514                 *:*

Вам нужно вырубить прослушивание всех ip адресов у этих сервисов (это логично даже с точки зрения безопасности). Как это сделать можете почитать в других статьях на этом сайте.

Когда вы отключите прослушивание ip адреса везде, тогда можно запускать jail.
Но перед запуском сначала добавим его в автозагрузку
echo 'ezjail_enable="YES"' >> /etc/rc.conf


Давайте теперь запустим созданный jail
ezjail-admin start test

Проверим запущенные jails в системе
jls

Если все нормально, то должно выдать нечто такое
# jls
   JID  IP Address      Hostname                      Path
     1  192.168.0.11    test                      /usr/jails/test

Отлично, теперь у нас есть работающий jail!
Прежде чем лезть в него, нужно сразу скопировать файл /etc/resolv.conf чтобы разрешались днс адреса
cp /etc/resolv.conf /usr/jails/test/etc


Также, чтобы пинговаться внутри jail надо добавить пару строк в /etc/sysctl.conf
echo 'security.jail.allow_raw_sockets=1' >> /etc/sysctl.conf
echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf

Перезапустим сервис
service sysctl restart


Все, теперь можно зайти в клетку
jexec 1 csh

*некоторое пояснение: 1 это тот самый JID который показывался командой jls, csh это версия шелла

Первым делом в клетке необходимо создать файл /etc/fstab
touch /etc/fstab
ee /etc/rc.conf

Открываем редактором /etc/rc.conf и пишем туда
network_interfaces=""
rpcbind_enable="NO"
cron_flags="$cron_flags -J 15"
syslogd_flags="-ss"

sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"

sshd_enable="YES"

Проверяем локальный ping
test# ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.010 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.014 ms

Отлично, пинг работает.

Теперь на счет внешних соединений: Если вы тестируете это на локалке, то внешние соединения из клетки заработают, если же вы делаете это на сервере, то скорее всего пакеты изнутри клетки во внешнюю сеть будут резаться уровнем выше. Для того, чтобы сеть в клетке работала нужно прибегнуть к помощи файрвола.
В качестве файрвола я буду использовать pf. Нужно выйти из клетки перед тем, как настраивать файрвол
test# exit


Оказавшись в основной системе нужно подгрузить pf как модуль ядра
kldload pf
kldstat
echo 'pf_enable="YES"' >> /etc/rc.conf


Создадим файл /etc/pf.conf (xxx.xxx.xxx.xxx это внешний ип адрес вашего сервера), em0 это сетевой интерфейс
В pf.conf пишем
pub="xxx.xxx.xxx.xxx" 

jail_net="192.168.0.11/32"
jail="192.168.0.11"

if="em0"
 
set block-policy return
set skip on lo
scrub in

nat on $if from $jail to !$jail_net -> $pub 
#создали nat

В конце правила не забудьте пустую строку! Теперь наша клетка находится за натом, и для хостера пакеты из нее не будут отличаться от пакетов из основной системы, и он не будет их срезать.

Теперь запустим файрвол и применим эти правила
pfctl -e
pfctl -f /etc/pf.conf


Зайдем еще раз в клетку и пинганем яндекс
jexec 1 csh
test# ping ya.ru
PING ya.ru (87.250.250.3): 56 data bytes
64 bytes from 87.250.250.3: icmp_seq=0 ttl=57 time=65.462 ms
64 bytes from 87.250.250.3: icmp_seq=1 ttl=57 time=76.410 ms

Отлично, теперь сеть работает и у нас есть отдельная виртуальная система.