Представьте, в ОС или каком-либо компоненте нашли уязвимость, взломали, и одно дело, утекшие данные, а ведь до кучи могут сделать хост частью своего ботнета, например. Вы хватаетесь за голову, что ж теперь, аудит проводить, куда лазили, что делали, или просто переустановить всё, опять же заново настраивать, — сплошной головняк. Восстановление из последнего бэкапа? Как давно он был сделан? Ведь наверняка с тех пор в конфигурацию хоста внесены изменения. Я веду к тому, что всё ещё популярно хранить актуальное состояние ОС в единственном экземпляре в «горячем» виде, так сказать.
А что если, экземпляр вашей ОС хранился бы в «холодном» виде в образе, на сервере, откуда бы загружался на ваш хост при каждом его включении, и подтягивал за собой всю конфигурацию, необходимую для работы. Хост взломали, а вы просто исправили баг в образе который хранится «на холодную» и жмякнули кнопочку reset для перезагрузки, и снова в строю. Это же просто офигенно.
Как раз сейчас я этим и занимаюсь и решил поделиться мыслями. Хочу перевести все свои сервисы на удалённую «бездисковую» загрузку по сети. Чтоб даже домашний ПК-роутер, раздающий интернеты, загружался по сети и подтягивал образ с соответствующей конфигурацией. Для этого нужен только DHCP, tftp-hpa и... grub2, либо syslinux.
Когда компьютер включается, UEFI / BIOS при необнаружении накопителей пытается загрузиться через сеть, это так по-умолчанию, можно тупо принести новый комп из магазина домой, закрытыми глазами его собрать, включить и он загрузится, и станет нодой, частью вашей сети, да... кра-со-та.
UEFI спросит DHCP-сервер, DHCP выдаст IP и скажет, что по такому-то адресу находится загрузчик. UEFI попытается загрузить его по TFTP-протоколу, и в случае успеха, уже сам grub2 покажет красивую менюшку с выбором ОС, — добро пожаловать бездисковую загрузку по сети!
С установкой и запуском tftp-hpa проблем не будет, /usr/sbin/in.tftpd --listen --secure --verbose /var/ftp/tftpboot
Предлагаю всё хранить в /var/ftp/tftpboot, туда же установим загрузчик GRUB2:
# grub-mknetdir --net-directory /var/ftp/tftpboot
Netboot directory for i386-pc created. Configure your DHCP server to point to /var/ftp/tftpboot/boot/grub/i386-pc/core.0
Netboot directory for i386-efi created. Configure your DHCP server to point to /var/ftp/tftpboot/boot/grub/i386-efi/core.efi
Netboot directory for x86_64-efi created. Configure your DHCP server to point to /var/ftp/tftpboot/boot/grub/x86_64-efi/core.efi
Далее DHCP, достаточно настроить чтобы он раздавал IP и говорил по какому адресу находится файл загрузчика, который UEFI будет загружать через TFTP.
# cat /etc/dhcpd.conf
shared-network arpanet {
interface br0;
allow booting;
allow bootp;
next-server 10.0.0.1;
filename "boot/grub/i386-pc/core.0";
subnet 10.0.0.0 netmask 255.0.0.0 {
option domain-name-servers 8.8.8.8, 8.8.4.4;
option subnet-mask 255.0.0.0;
option routers 10.0.0.1;
range 10.0.0.2 10.0.0.254;
}
}
Загрузка будет происходить с tftp://${next-server}/${filename}
. У меня интерфейс br0 — бридж, в который вхожи все виртуальные машины. Именно br0 присвоен 10.0.0.1. У вас это может быть просто сетевая карта enp1s4po3te5ri7ng9.
Алсо, если у вас реально UEFI, можно добавить проверку, какой загрузчик отдавать системе:
option client-system-architecture-type code 93 = unsigned integer 16;
if option client-system-architecture-type = 00:09 {
filename "boot/grub/x86_64-efi/core.efi";
}
else {
filename "boot/grub/i386-pc/core.0";
}
У меня кстати на QEMU с OVMF загрузчик EFI не заработал. Не знаю почему, то ли OVMF кривой, то ли надо тестировать на реальном железе (пока не пробовал).
Ну и вишенкой на торте надо создать обычный grub.cfg vi /var/ftp/tftpboot/boot/grub/grub.cfg
:
set default=0
set timeout=60
menuentry "Boot SLAX" {
linux /boot/os/slax/vmlinuz load_ramdisk=1 prompt_ramdisk=0 rw printk.time=0 from=http://10.0.0.1/slax/slax-64bit-9.9.1.iso
initrd /boot/os/slax/initrfs.img
}
menuentry "Reboot" {
reboot
}
menuentry "Shutdown" {
halt
}
menuentry "Continue" {
exit
}
На этом вся настройка. Для теста я использовал qemu-system-x86_64 -nic tap
, который скриптами /etc/qemu-{ifup,ifdown} входил в бридж br0. BIOS спрашивал DHCP, DHCP выдавал IP и сообщал адрес загрузчика, далее BIOS загружал его с TFTP сервера и удачно грузился grub2, а дальше — дело тривиальное. Напихать кучу образов ОС.
Для примера можно использовать SLAX, для этого скачаем ISO-образ дистрибутива, стырим оттуда файлики /slax/boot/{vmlinuz,initrfs.img}
и положим к себе в /var/ftp/tftpboot/boos/os/slax/.
Расскажу, как это работает, почему загружается SLAX и почему не загружается Debian / Ubuntu / Anything Else по сети.
Мы включили ПК, по TFTP загрузился grub2 и всё управление сейчас находится у него. Далее, выбирая пунктик меню загрузки SLAX, сам grub2 загружает с TFTP-сервера файлы /vmlinuz и /initrfs.img и передаёт управление уже ядру /vmlinuz. А ядро-то про TFTP сервер ничего не знает! И initrd SLAX'а, и любого другого дистрибутива ничего про TFTP не знает. До того момента, как мы грузимся по сети, мы работаем с TFTP-сервером, grub2 может оттуда загружать все свои модули, шрифты, аниме-картинку-с-понями для фона, но после того, как он передаёт управление ядру — забудьте про TFTP, всё.
В данном примере параметром к ядру указан from=http:// iso-образ SLAX, — да, iso-образ будет скачан с этого ресурса и SLAX будет успешно загружен по сети, нооо, важная деталь — это не параметр ядра, from= сохранится в /proc/cmdline, но ядро не знает что с этим делать, с from= будет работать сам /init скрипт находящийся в initrfs.img. Это чисто фича SLAX, и такой фичи нет у других дистрибутивов.
Как же тогда загрузить Ubuntu Live по сети? Да, grub2 может загрузить ISO образ размером 2гб, но оно вам надо? Ядро не знает про http и ftp (поправьте, если ошибаюсь), но ядро знает про NFS (Network File System) и умеет работать с ней. Таким образом, чтобы загрузить Ubuntu Live, вам надо точно так же извлечь vmlinuz и initrd из iso-образа Ubuntu, а параметром к ядру дописать root=/dev/nfs, таким образом ядро Ubuntu (и любого другого дистрибутива, т.к. это уже фича самого ядра Linux), будет знать, что после того как какой-нибудь скрипт в initrd запросит внешний файл, например, Live-образ системы, — ядро знает, что брать его надо с nfs://10.0.0.1/ubuntu-live — так-то!
Если будут вопросы, постараюсь ответить (хотя скоро спать).
За основу дистрибутива для загрузки по сети я беру любимый CRUX. Вся идея в том, чтобы загружался простенький busybox, подключался к сети (udhcpc), а затем через wget ftp://10.0.0.1/boot/pxelinux.cfg/54:52:00:12:34:56/init.sh && sh init.sh
выполнял дальнейшие инструкции для загрузки, которые могут быть вообще любые. Подтягивал любой образ ФС по сети и switch_root в него! Так-то.