Trucchi con PXE

Questi sono brevi appunti per il seminario di Giovanni Mascellani al Linux Day 2014 di Pisa. Si tratta di appunti, non di istruzioni complete. In particolare non forniscono una panoramica completa sui potenziali problemi di sicurezza che nascono in un setup di questo tipo. Chi utilizza questi appunti lo fa sulla propria responsabilità ed è caldamente invitato a consultare la documentazione di supporto dei programmi utilizzati. In altre parole, se fai quello che c’è scritto qui dentro senza capire cosa significa, corri seri rischi di fare qualche disastro. Anche perché poi è probabile che in questi appunti ci siano degli errori. Se capite cosa state facendo potete sistemarli da voi.

Queste istruzioni assumono che si stia lavorando su sistemi Debian/Ubuntu. In linea di principio le stesse cose possono essere fatte su ogni sistema Linux, però alcuni dettagli tecnici potrebbero cambiare.

Questo documento è stato finito il 25 ottobre 2014. Per contattare l’autore: gio@debian.org.

Installazione dei pacchetti

Su Debian installare: atftpd, debootstrap, isc-dhcp-server, nfs-kernel-server, syslinux-common. A partire da Debian jessie bisogna anche installare pxelinux.

Aprire il firewall

È necessario configurare il firewall per ricevere richieste TFTP, DHCP e NFS. TFTP usa la porta UDP numero 69. Per DHCP bisogna utilizzare configurazioni che dipendono dallo specifico motore di firewall utilizzato (consultare la documentazione). Per NFS la situazione è un po’ complicata: vedere le istruzioni sul wiki di Debian.

ACHTUNG!!

Mai tenere un servizio DHCP attivo sul proprio portatile! Si rischia di danneggiare le reti alle quali ci si collega (e di trovarsi davanti amministratori di rete molto arrabbiati)!

Se la rete sulla quale si vuole offrire il servizio di boot con PXE ha già un server DHCP, allora bisogna modificare le impostazioni di quel server (vedere sotto come fare). Due server DHCP sulla stessa rete significano (quasi sempre) grossi guai!

Creazione di un sistema di base

Usare il comando:

# debootstrap --arch=i386 jessie /srv/jessie

Questo installerà un sistema di base in /srv/jessie. Ci vorrà un po’ per scaricare tutti i pacchetti e metterli a posto. Si può scegliere l’architettura amd64 se si è sicuri che il sistema verrà utilizzato solo su processori a 64 bit. Si possono ovviamente anche scegliere altre versioni di Debian e di Ubuntu. Si può opzionalmente anche specificare un mirror da utilizzare per scaricare i pacchetti:

# debootstrap --arch=i386 jessie /srv/jessie http://http.debian.net/debian/

Servire il sistema via NFS

Scrivere qualcosa del genere in /etc/exports

/srv/jessie     *(ro,no_root_squash,async,subtree_check)

E poi ricaricare la configurazione di NFS con

# service nfs-kernel-server reload

Configurare la rete ed il server DHCP

Modificare la riga in /etc/default/isc-dhcp-server:

INTERFACES="eth0"

Configurare un indirizzo statico sull’interfaccia di rete da usare (perché la configurazione diventi permanente bisogna replicarla in /etc/network/interfaces, oppure utilizzare il proprio configuratore di rete di fiducia):

ip addr add dev eth0 192.168.1.1/24

Scrivere la configurazione del demone DHCP in /etc/dhcp/dhcpd.conf:

authoritative;
subnet 192.168.1.0 netmask 255.255.255.0 {
  range 192.168.1.10 192.168.1.100;
  option routers 192.168.1.1;
  option domain-name-servers 8.8.8.8;
  next-server 192.168.1.1;
  filename "pxelinux.0";
}

A seconda dei casi bisogna anche configurare il server per fare IP forwarding e masquerading, in modo da permettere al client DHCP di navigare su Internet.

Installare il kernel nel sistema di base (e configurare altre cose di base)

Il sistema di base creato per ora è senza kernel, quindi non può essere avviato dai client. Per installare il kernel bisogna prima entrare nel sistema con chroot. Però bisogna anche montare i file system di appoggio come /proc ed altri:

# cd /srv/jessie
# mount -o bind /proc /srv/jessie/proc
# mount -o bind /dev /srv/jessie/dev
# mount -o bind /sys /srv/jessie/sys
# chroot .
[ dentro il sistema nuovo ]
# apt-get update
# apt-get install linux-image-486
[ opzionalmente si possono anche installare e aggiornare altri pacchetti ]
# passwd
[ impostare un password per root ]
# echo "minion" > /etc/hostname
# exit
[ di nuovo nel sistema del server ]
# umount /srv/jessie/proc
# umount /srv/jessie/dev
# umount /srv/jessie/sys

(naturalmente a seconda dei casi bisogna installare la variante del kernel che si intende usare; la -486 è quella più conservativa, che funziona ovunque; in molti casi la -686-pae andrà bene)

C’è un ultima cosa da fare: l’installazione del kernel creerà dei link a kernel e initrd nella directory /srv/tftp. Per qualche strano motivo che non so, il link al kernel va bene, mentre invece quello all’initrd no (perché è assoluto invece che relativo; dall’interno della chroot è la stessa cosa, ma dall’esterno no). Bisogna quindi sistemarlo (e ricordarsi di sistemarlo di nuovo ogni volta che si installa un nuovo kernel):

cd /srv/jessie
rm initrd.img
ln -s boot/initrd.img-3.16-2-486 initrd.img

Installare Pxelinux

Copiare il file pxelinux.0 in /srv/tftp. Il file si può trovare nel pacchetto syslinux-common oppure pxelinux, a seconda della versione di Debian/Ubuntu che si usa. Poi creare il file /srv/tftp/pxelinux.cfg/default nel quale sta la configurazione di Pxelinux. La sintassi della configurazione ed il funzionamento del sistema sono praticamente identici a quella di Syslinux.

Creiamo una configurazione minimale. Copiamo anche il file menu.c32 (dal pacchetto syslinux-common) in /srv/tftp e mettiamo questo contenuto nel file /srv/tftp/pxelinux.cfg/default:

prompt 0
timeout 50

menu title Boot menu

label jessie
    menu label Debian jessie i386
    kernel jessie/vmlinuz
    append rw verbose ip=dhcp initrd=jessie/initrd.img root=/dev/nfs nfsroot=192.168.1.1:/srv/jessie vga=791 init=/lib/systemd/systemd

ui menu.c32

(se non volete usare systemd dovete togliere il parametro init=..., ma dovete anche assicurarvi che qualche altro sistema init sia installato; anche gli altri parametri richiedono di essere adattati alla situazione, in particolare l’indirizzo IP del server NFS; tutti i path che compaiono sono relativi a /srv/tftp)

Bisogna poi creare la cartella /srv/tftp/jessie e copiare (oppure mettere dei link simbolici) kernel e initrd del sistema guest:

cd /srv/tftp
mkdir jessie
cd jessie
ln -s ../../jessie/initrd.img
ln -s ../../jessie/vmlinuz

Configurare aufs

A questo punto è possibile fare il boot del nuovo sistema. Tuttavia se ci provate scoprirete che ci sono un sacco di problemi, perché il file system di root è montato in sola lettura (e NFS è configurato per permettere solo la lettura, non la scrittura). Permettere la lettura a NFS sarebbe una pessima idea, perché diversi computer interferirebbero malamente tra di loro. Bisogna fare in modo che ogni volta che il computer si avvia monti sopra il livello NFS in sola lettura un altro livello che sta interamente in RAM e che è in lettura-scrittura. Tutte le modifiche fatte a questo livello verranno perse ogni volta che il computer viene riavviato. Questo permette di avere un sistema pulito ogni volta che si riavvia il computer!

Creare due file con il seguente contenuto:

/srv/jessie/etc/initramfs-tools/scripts/init-bottom/aufsroot

#!/bin/sh

PREREQ=''

prereqs() {
  echo "$PREREQ"
}

case $1 in
prereqs)
  prereqs
  exit 0
  ;;
esac

# Boot normally when the user selects single user mode.
if grep single /proc/cmdline >/dev/null; then
  exit 0
fi

ro_mount_point="${rootmnt%/}.ro"
rw_mount_point="${rootmnt%/}.rw"

# Create mount points for the read-only and read/write layers:
mkdir "${ro_mount_point}" "${rw_mount_point}"

# Move the already-mounted root filesystem to the ro mount point:
mount --move "${rootmnt}" "${ro_mount_point}"

# Mount the read/write filesystem:
mount -t tmpfs root.rw "${rw_mount_point}"

# Mount the union:
mount -t aufs -o "dirs=${rw_mount_point}=rw:${ro_mount_point}=ro" root.union "${rootmnt}"

# Correct the permissions of /:
chmod 755 "${rootmnt}"

# Make sure the individual ro and rw mounts are accessible from within the root
# once the union is assumed as /.  This makes it possible to access the
# component filesystems individually.
mkdir "${rootmnt}/ro" "${rootmnt}/rw"
mount --move "${ro_mount_point}" "${rootmnt}/ro"
mount --move "${rw_mount_point}" "${rootmnt}/rw"

/srv/jessie/etc/initramfs-tools/hooks/aufsroot

#!/bin/sh

PREREQ=''

prereqs() {
  echo "$PREREQ"
}

case $1 in
prereqs)
  prereqs
  exit 0
  ;;
esac

. /usr/share/initramfs-tools/hook-functions
manual_add_modules aufs
manual_add_modules tmpfs
copy_exec /bin/chmod /bin

Poi renderli entrambi eseguibili:

chmod 755 /srv/jessie/etc/initramfs-tools/scripts/init-bottom/aufsroot
chmod 755 /srv/jessie/etc/initramfs-tools/hooks/aufsroot

Inoltre bisogna ricompilare l’initrd. Serve quindi entrare nel sistema guest come indicato sopra (quando si è installato il kernel) e all’interno del sistema guest dare il comando:

update-initramfs -k all -u

A questo punto il sistema PXE partirà perfettamente!

Altre cose utili da fare nel sistema guest

Il sistema di base è veramente di base! Per avere un po’ di supporto in più si possono fare le seguenti cose (sempre da eseguire dentro il sistema con chroot come indicato sopra).

# apt-get install locales
# dpkg-reconfigure locales
[ configurare opportunamente i locales ]
# dpkg-reconfigure tzdata
[ configurare opportunamente il fuso orario ]
# apt-get install aptitude vim less ntp dbus
# adduser utente
[ configurare opportunamente l'utente ]
# apt-get install xfce4

Montare una cartella home scrivibile dagli utenti

Per ora tutte le modifiche fatte al sistema (per esempio, i file utilizzati dagli utenti nelle loro directory home) vengono perse ad ogni riavvio. Per evitare questo problema bisogna montare le home in lettura-scrittura via NFS. Per fare questo bisogna creare una cartella per le home:

# mkdir /srv/home

ed aggiungere a /etc/export:

/srv/home     192.168.1.0/24(rw,root_squash,async,subtree_check)

Poi bisogna montare il volume all’avvio. Scriviamo in /srv/jessie/etc/fstab:

192.168.1.1:/srv/home    /home    nfs    hard,nointr    0    0

(ovviamente bisogna anche creare le singole home dei vari utenti, con i permessi giusti. Occhio, perché gli UID e GID numerici devono essere quelli del sistema guest, non quelli del sistema host!).


Con il patrocinio di:

Provincia di Pisa

Provincia
di Pisa

Comune di Pisa

Comune
di Pisa

Comune di Calci

Comune
di Calci

Comune di San Giuliano Terme

Comune di
San Giuliano Terme

Comune di Vecchiano

Comune di
Vecchiano

Comune di Vicopisano

Comune di
Vicopisano

Fondazione Toscana G. Monasterio

Fondazione Toscana
G. Monasterio

Università di Pisa

Università
di Pisa

Wikimedia Italia

Wikimedia
Italia