_____ _   _ _    _    ___      _
 / ____| \ | | |  | |  / / |    (_)
| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
 \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\

Uruchamianie LiveCD z dystrybucją Linuksa przez sieć

Już jakiś czas temu na tej stronie powstał artykuł o tym w jaki sposób utworzyć własne LiveCD z dystrybucją GNU/Linux Debian. Na podstawie tego materiału powstały dwa większe projekty jakim był greenOS oraz immudex. Immudex jest dalej rozwijany, a jego charakterystyczną cechą jest to, że musi on być aktualizowany ręcznie przez użytkownika za pomocą dysku USB lub dysku optycznego. W podobny sposób przebiega również instalacja. W zależności od tego jak tworzony jest obraz należy go przegrać na jakiś nośnik, aby uruchomić z niego komputer a następnie z aktualizować lub zainstalować na nim system. Nawet więcej, rozważmy taki przypadek, że chcemy uruchomić więcej niż jeden komputer z LiveCD, a mamy do dyspozycji tylko jeden pendrive. Rozwiązaniem tych, że problemów może być uruchomienie systemu z sieci z wykorzystaniem takich technologii jak DHCP, TFTP, PXE oraz HTTP.

Ze względu na to, że wykorzystujemy tutaj usługę DHCP - powszechną w każdej sieci lokalnej - środowisko PXE (uruchamiania z sieci) możemy skonfigurować w różnych wariantach. Podczas zgłębiania tematu udało mi się wyodrębnić 3 wariacje konfiguracji. Pierwsza z nich - ta najbardziej sprawdzona polega na wyłączniu obecnie używanej dla sieci usługi DHCP i zastąpienie jej tą uruchamianą na serwerze PXE. Z zalet to środowisko PXE na pewno zadziała w naszej sieci, gorzej z faktem, że musimy przenieść całą obecną konfigurację DHCP na nasz serwer i jeśli mamy bardzo dużo rezerwacji to okazuje się to bardzo żmudnym procesem. Dlatego to rozwiązanie może okazać się dobry rozwiązaniem dla wewnętrznej sieci laboratoryjnej. Ta właśnie metodą zostanie tutaj opisana, ponieważ w nalepszy sposób obrazuje zadania konfiguracyjne i stanowi solidną bazę do dalszych eksperymentów ze środowiskiem PXE. Drugą możliwością jest wykorzystanie obecnie działającego serwera DHCP, wówczas serwer PXE zajmuje wyłącznie się hostowanie plików przy użyciu protokołu TFTP. To rozwiązanie będzie dobrze funkcjonować w sieciach gdzie wykorzystywane są routery programowe, oparte na takim oprogramowanie jak na przykład IPFire. Trzecim wariantem jest brak serwera PXE w ogóle, bowiem istnieją routery lub oprogramowanie przygotowane dla routerów takie jak OpenWRT, które jest wstanie uruchomić serwer TFTP. Problemem tutaj jest fakt, że (przynajmniej w przypadku OpenWRT) możemy podać tylko jeden plik bootloadera, a dla komputerów z UEFI potrzebujemy innego pliku bootloadera, niż dla komputerów wykorzystujących klasyczny BIOS. Tutaj będziemy potrzebować wyłącznie plików programu rozruchowego, które możemy przygotować na własnym komputerze. Problematycze może być umieszczenie tych plików w pamięci flash urządzenia.

Jeśli na naszym komputerze posiadamy już zainstalowny system operacyjny w moim przypadku jest GNU/Linux Debian. To naszą konfigurację z racji, że będzie tam zainstalowany serwer DHCP - rozpoczynamy od statycznej konfiguracji interfejsu sieciowego.

# sudo vim /etc/network/interfaces
...
allow-hotplug enp3s0
iface enp3s0 inet static
  address 192.168.1.253
  netmask 255.255.255.0
  gateway 192.168.1.1
  dns-nameservers 192.168.1.1

Po wykonaniu tej konfiguracji, najlepiej jest serwer zrestartować aby zaczął on korzystać z tej konfiguracji. Następną czynnością jest utworzenie odpowiedniej struktury katalogowej dla serwera TFTP.

$ sudo mkdir -vp /pxeboot/{config,firmware}

Teraz wypełnimy katalog /pxeboot/firmware plikami programu rozruchowego. Do tego będzie potrzebować owych plików oraz pierwszego skryptu ipxe. Skrypt ipxe zawiera listę poleceń wykonywach w środowisku powłoki programu ładującego. Takim programem służącym do rozruchu z sieci jest właśnie projekt iPXE. Pliki wykonywalne tego programu skompilujemy samodzielnie z najnowszego kodu źródłowego projektu dostępnego w serwisie GitHub. Na początek zainstalujemy z repozytorium wymagane do pobrania kodu oraz jego kompilacji pakiety.

$ sudo apt install -y build-essetial liblzma-dev git

Po zainstalowaniu pakietów pobieramy kod źródłowy ze GitHub i przechodzimy do katalogu ipxe/src.

$ git clone https://github.com/ipxe/ipxe
Klonowanie do „ipxe”...
remote: Enumerating objects: 62694, done.
remote: Counting objects: 100% (38/38), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 62694 (delta 15), reused 22 (delta 11), pack-reused 62656 (from 1)
Pobieranie obiektów: 100% (62694/62694), 18.99 MiB | 30.47 MiB/s, gotowe.
Rozwiązywanie delt: 100% (47450/47450), gotowe.
$ cd ipxe/src

W tym katalogu, przed rozpoczęciem kompilacji tworzymy nasz skrypt ipxe. Skrypt ten zostanie umieszczony w kodzie programu rozruchowego, tak aby on uruchamiany zaraz po uruchomieniu samego programu - dążymy do tego aby było to jak najbardziej bezobsługowe.

~/ipxe/src$ vim bootconfig.ipxe
#!ipxe

dhcp
chain tftp://192.168.1.253/config/boot.ipxe

Skrypt ten nakazuje programowi ładującemu, uzyskanie adresu konfiguracji sieciowej z serwera DHCP i następnie przejście do uruchomienia kolejnego skryptu (w tym przypadku) lub innego programu rozruchowego (tzw. chainloading), który zapisany jest na serwerze TFTP. Po utworzeniu pliku przechodzimy do kompliacji plików bootloadera W tym celu wydajemy poniżej odpowiednie polecenie. Flaga EMBED wskazuje na nasz skrypt, bardzo ważne jest prawidłowe zapisanie jej nazwy oraz wskazanie odpowiedniego pliku, bowiem make nie wskaże co do tego błędów.

~/ipxe/src$ make bin/ipxe.pxe bin-x86_64-efi/ipxe.efi EMBED=bootconfig.ipxe
  [PARSEROM]
  [DEPS] core/version.c
  [DEPS] arch/x86/drivers/net/undiisr.S
  [DEPS] arch/x86/transitions/librm.S
  [DEPS] arch/x86/transitions/libpm.S
  [DEPS] arch/x86/transitions/libkir.S
  [DEPS] arch/x86/transitions/liba20.S
  [DEPS] arch/x86/prefix/usbdisk.S
  [DEPS] arch/x86/prefix/unlzma.S
...
  [BUILD] bin/rtl8180.ids.o
  [BUILD] bin/rtl8185.ids.o
  [BUILD] bin/ath5k.ids.o
  [BUILD] bin/ath9k.ids.o
  [AR] bin/blib.a
  [HOSTCC] util/zbin
  [VERSION] bin/version.ipxe.pxe.o
  [LD] bin/ipxe.pxe.tmp
  [BIN] bin/ipxe.pxe.bin
  [ZINFO] bin/ipxe.pxe.zinfo
  [ZBIN] bin/ipxe.pxe.zbin
  [FINISH] bin/ipxe.pxe
rm bin/ipxe.pxe.zinfo bin/ipxe.pxe.bin bin/version.ipxe.pxe.o bin/ipxe.pxe.zbin
  [PARSEROM]
  [DEPS] core/version.c
  [DEPS] arch/x86/transitions/librm.S
  [DEPS] arch/x86/transitions/libpm.S
  [DEPS] arch/x86/transitions/libkir.S
  [DEPS] arch/x86/transitions/liba20.S
  [DEPS] arch/x86/prefix/usbdisk.S
  [DEPS] arch/x86/prefix/unlzma.S
...
  [BUILD] bin-x86_64-efi/hvm.ids.o
  [BUILD] bin-x86_64-efi/rtl8180.ids.o
  [BUILD] bin-x86_64-efi/rtl8185.ids.o
  [BUILD] bin-x86_64-efi/ath5k.ids.o
  [BUILD] bin-x86_64-efi/ath9k.ids.o
  [AR] bin-x86_64-efi/blib.a
  [HOSTCC] util/elf2efi64
  [VERSION] bin-x86_64-efi/version.ipxe.efi.o
  [LD] bin-x86_64-efi/ipxe.efi.tmp
  [FINISH] bin-x86_64-efi/ipxe.efi
rm bin-x86_64-efi/version.ipxe.efi.o

Skompliowane pliki wykonywalne programu rozruchowego kopiujemy do wcześniej utworzonego katalogu /pxeboot/firmware.

~/ipxe/src$ sudo cp -v bin/ipxe.pxe bin-x86_64-efi/ipxe.efi /pxeboot/firmware
'bin/ipxe.pxe' -> '/pxeboot/firmware/ipxe.pxe'
'bin-x86_64-efi/ipxe.efi' -> '/pxeboot/firmware/ipxe.efi'

Po skopiowaniu plików bootloadera, możemy zainstalować program, który będzie służył nam za serwer DHCP oraz za serwer TFTP. Dodatkowo domyślnie przekazuje on zapytania DNS, dalej do serwerów skonfigurowanych w systemie.

$ sudo apt install -y dnsmasq

Po zainstalowaniu pakietu możemy przjeść do jego konfiguracji. Rozpoczynamy ją od zabezpieczenia konfiguracji dostarczanej wraz z pakietem. W ten sposób będziemy rozpoczynać konfiguracje od zera, w tym przypadku jest to wskazane.

$ sudo mv /etc/dnsmasq.conf /etc/dnsmmasq.conf.bak

Teraz możemy zapisać poniższą konfigurację w /etc/dnsmasq.con.

interface=enp3s0
bind-interfaces
domain=morketsmerke.org

dhcp-range=enp3s0,192.168.1.100,192.168.1.200,255.255.255.0,12h
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,192.168.1.1
dhcp-option=option:dns-server,8.8.8.8

enable-tftp
tftp-root=/pxeboot

dhcp-match=set:bios-x86,option:client-arch,0
dhcp-boot=tag:bios-x86,firmware/ipxe.pxe

dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-match=set:efi-x86_64,option:client-arch,9
dhcp-boot=tag:efi-x86_64,firmware/ipxe.efi

Na początku konfiguracji, dodajemy opcje związane z ogólnymi ustawieniami serwera, takie jak interfejs, na którym ma nasłuchiwać oraz wymusić na dnsmasq nasłuchiwanie na wyłącznie podanych interfejsach. Opcjonalnie możemy dodać nazwę domeny. W drugiej częsci konfiguracji ustawiamy parametry DHCP, takie jak zakres adresów, czas dzierżawy oraz adres bramy czy adresy serwerów DNS. Następnie włączamy usługę TFTP oraz wskazujemy jej katalog główny, w którym będą znajdować pliki udostępniane przez tę usługę. W ostaniej sekcji konfiguracji ustalamy z jakim oprogramowaniem układowym komputer skomunikował się z naszym serwerem DHCP i na podstawie tak uzyskanych informacji dnsmasq będzie określać jaki plik programu rozruchowego mu przekazać do uruchomienia.

Po skonfigurowaniu dnsmasq, nadszedł czas aby napisać już właściwy skrypt ipxe, które go zadaniem bedzie pobranie, załadowanie jądra naszej dystrybucji wraz plikiem initrd oraz uruchomienie jądra wraz z odpowiednimi parametrami. Plik nazwany boot.ipxe - nazwa ta musi być zgodna z nazwą podaną w skrypcie bootconfig.ipxe - ten umiesczamy w /pxeboot/config

#!ipxe

set host ftp.morketsmerke.org
set root_path immudex/pxe

kernel http://${host}/${root_path}/vmlinuz
initrd http://${host}/${root_path}/initrd
imgargs vmlinuz initrd=initrd boot=live fetch=http://${host}/${root_path}/filesystem.squashfs
boot

W tym skrypcie możemy spokojnie używać nazwy domenowej serwera jeśli nie pamiętamy adresu IP. Ostatnia linia przekazuje argumenty uruchomieniowe jądra. Parametr fetch, jest opcją programu live-boot, który jest odpowiedzialny za uruchomienie i utrzymanie środowiska LiveCD. W tej linii możemy umieścić więcej opcji konfigurujących to środowisko. Po zapisaniu konfiguracji pozostało nam, uruchomienie ponowne usługi dnsmasq i spróbowanie uruchomienia.

Źródła:

  1. Configuring PXE Network Boot Server on Ubuntu 22.04 LTS [ang.]
  2. Installing Debian Bullseye ISO over PXE with [ang.]
  3. live-boot GNU/Linux Debian man page [ang.]

~xf0r3m