On my previous post about Using Powershell and OSDCloud to automate Windows workstation deployment, I mentionned a second part on :
Setting up a PXE infrastructure to deploy Windows workstations with OSDCloud.
So there we are…
At the time, I naively believed I could deploy a functional iPXE infrastructure for BIOS, UEFI, and especially UEFI with secure boot. What a mistake that was…
Quick explaination : Secure Boot ensures that the boot chain is signed by a PC manufacturer. Therefor, it gets very difficult to boot from a custom made PXE/iPXE infrastructure. There are ways, one of which would be to pay a lot of money to get your boot chain to be signed. Another way would be to pay less money for an already signed PXE server. I’m not going to cover these 2 options here, but keep in mind that they do exist.
I want to have it ALL : BIOS, UEFI and UEFI with Secure Boot
Sadly (or not), the simplest and cheapest (it’s free) option is to use a Windows server with WDS (Windows Deployment Services). Honestly, it works pretty well and can be configured quickly.
I know my previous post aimed at convincing you to abandon Microsoft Deployment Toolkit and I still stand by it. Using OSDCloud as a replacement for building a boot image and then using WDS to deploy it is optimal in my opinion.
I don’t care about Secure Boot, give me the quickest and smallest PXE server (BIOS and UEFI compatible)
We are going to setup an alpine server with :
- DHCP server
- TFTP server
- HTTP server
- iPXE
Install Alpine server
- Boot up a server with alpine standard iso and login with
root
. - Run the wonderful
setup-alpine
installer and follow the instructions :- Select keyboard.
- Select hostname, in my case it’s
rhea
. - Configure your network interfaces, in my case
eth0
andeth1
. One of them is on a network open to the Internet, the other on an isolated network dedicated to workstation deployment.- For
eth0
: I assume you have basic network knowledge. You will probably have to set this up manually according to your own network specifications. - For
eth1
: You are free to select your prefered subnet as it will be NATed later on. I’ll go with10.0.0.1
for the ip address and gateway,255.255.255.0
as netmask (253 free addresses is enough in my case).
- For
- Configure the password, timezone, apk mirror.
- No new user appart from
root
in my case. - Configure
openssh
for remote access. - Configure disks ( I use
sys
mode). - Ensure DNS resolution is working with a simple
ping google.com
. Usesetup-dns
to fix any issue if needed. poweroff
the machine and remove the installation media.
You should probably do the good ol’ ssh-copy-id
followed by PermitRootLogin prohibit-password
(/etc/ssh/sshd_config
) shenanigans 👀.
Run rc-service sshd restart
afterwards.
You may now ssh into rhea
🧙♂️.
Setup NAT
# Enable IP forwarding (necessary for routing between networks)
echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf
sysctl -p
# Enable NAT
apk add iptables
rc-update add iptables
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # eth0 is the net card of my open network
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT # eth1 is the net card of my isolated network
/etc/init.d/iptables save
I am using
MASQUERADE
as I don’t have a fixed external IP address on eth0. If you do (and you probably will), consider using SNAT instead for better performance (it wouldn’t really change much in our use case).
Setup DHCP server
Install the DHCP server:
apk add dhcp
Edit /etc/dhcp/dhcpd.conf
:
subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.100 10.0.0.200; # Use your own subnet
option routers 10.0.0.1; # In my case, IP of eth1 interface
option domain-name-servers 8.8.8.8; # Use your prefered DNS server
next-server 10.0.0.1; # TFTP server IP
option bootfile-name "ipxe.efi";
}
Configure the DHCP server to start at boot and manually start it now:
rc-update add dhcpd
rc-service dhcpd start
💡Tip: Check IP address leases in
/var/log/messages
Setup TFTP Server
apk add tftp-hpa
rc-update add in.tftpd
rc-service in.tftpd start
Our PXE files will be copied in
/var/tftpboot/
later
Setup HTTP Server
apk add lighttpd
rc-update add lighttpd default
rc-service lighttpd restart
Our boot image files will be copied in
/var/www/localhost/htdocs/
later.
Setup iPXE
We now have a functional server with all the services we need. We are, however, missing a vital part:
- A bootable image
- A PXE for the machine to boot on
Let’s handle that second part first.
apk add git make binutils mtools perl xz-dev libc-dev gcc
cd /srv
git clone https://github.com/ipxe/ipxe.git
cd ipxe/src
We will now create netboot.ipxe
:
#!ipxe
# Automatically configure interfaces
dhcp
# Network info
echo next-server is ${next-server}
echo bootfile is ${filename}
echo MAC address is ${net0/mac}
echo IP address is ${ip}
# Set HTTP server address
set server http://${next-server}
echo server is ${server}
# Set architecture
cpuid --ext 29 && set arch x86_64 || set arch i386
echo arch is ${arch}
# Load boot loader for Windows
echo Loading Wimboot
kernel ${server}/wimboot
initrd ${server}/BCD BCD
initrd ${server}/boot.sdi boot.sdi
initrd ${server}/boot.wim boot.wim
boot
We now need to compile our iPXE with our netboot configuration. Lets create build.sh
and chmod +x build.sh
it:
make bin-x86_64-efi/ipxe.efi EMBED=netboot.ipxe
make bin-x86_64-efi/snponly.efi EMBED=netboot.ipxe
cp bin-x86_64-efi/ipxe.efi /var/tftpboot/
cp bin-x86_64-efi/snponly.efi /var/tftpboot/
ipxe.efi
is the main artifact that contains all UEFI drivers, and is the most commonly used.snponly.efi
can also be used for chainloading boot, if ipxe.efi is not working, which is the case for when I ran tests in VirtualBox for instance. It uses SNP (Simple Network Protocol) or NII (Network Interface Identifier Protocol) instead of UEFI.- You could also build
snp.efi
orundionly.kpxe
(BIOS) if needed.
Download wimboot
from iPXE’s github with:
wget https://github.com/ipxe/wimboot/releases/latest/download/wimboot -P /var/www/localhost/htdocs/
Now we will need BCD
, boot.sdi
and boot.wim
. For that we will use our OSDCloud ISO from my previous post (remember this is part 2 👀).
From my host, I mounted my OSDCloud ISO and ran in Powershell:
scp D:\Boot\BCD rhea:/var/www/localhost/htdocs/BCD
scp D:\Boot\boot.sdi rhea:/var/www/localhost/htdocs/boot.sdi
scp D:\sources\boot.wim rhea:/var/www/localhost/htdocs/boot.wim
Conclusion
Setting up a PXE server yourself is very educational and a great way to understand the workings of this technology.
However, given that all new PCs are now delivered with Secure Boot enabled, it’s probably simpler and more enjoyable to use WDS in combination with OSDCloud for deployment.