Allow chainloading of Inspector ramdisk over UEFI

To send the Inspector ramdisk over HTTP rather than TFTP, we must first
send an iPXE boot image that knows how to speak HTTP, and then instruct
it to "chainload" the inspector ramdisk. Previously, we could only do
this if the machine being introspected had BIOS firmware. However, most
modern servers now use UEFI firmware, which requires a different iPXE
boot image (as described at http://ipxe.org/howto/chainloading).

We must specify the initrd in the iPXE `kernel` line to avoid the
problem described at http://forum.ipxe.org/showthread.php?tid=7589.

We include the iPXE binary images directly in the files/ subdirectory
and serve them from the puppet master. This is because

 - while there is a Debian package that contains both images, there is
   currently no package for Red Hat systems that contains the UEFI
   image;
 - downloading the images from ipxe.org would make our users vulnerable
   to any attack affecting that site.

Change-Id: I1f08578d4005c33feed84d4783a7a7693d13920c
Depends-On: I7dc191a38132db5fc2c68846c036d5b45061b398
This commit is contained in:
Miles Gould 2016-02-04 12:12:44 +00:00
parent dfff2af147
commit 5279179040
6 changed files with 37 additions and 4 deletions

BIN
files/ipxe.efi Normal file

Binary file not shown.

BIN
files/undionly.kpxe Normal file

Binary file not shown.

@ -219,6 +219,24 @@ class ironic::inspector (
content => template('ironic/inspector_ipxe.erb'),
require => Package['ironic-inspector'],
}
# Copy across iPXE boot images for chainloading.
# These can be found in the "ipxe" package on Debian-family operating
# systems, but there is currently (2016-02-24) no RPM that includes the EFI
# image (https://bugzilla.redhat.com/show_bug.cgi?id=1295673 -
# internal-only link).
# TODO(mgould): when ipxe.efi is included in the "bootimgs" RPM, remove our
# copies and replace this code with "install the right OS package and copy
# the files to /tftpboot".
file { '/tftpboot/undionly.kpxe':
ensure => 'present',
source => 'puppet:///modules/ironic/undionly.kpxe',
require => Package['ironic-inspector'],
}
file { '/tftpboot/ipxe.efi':
ensure => 'present',
source => 'puppet:///modules/ironic/ipxe.efi',
require => Package['ironic-inspector'],
}
}
# Configure inspector.conf

@ -175,6 +175,16 @@ describe 'ironic::inspector' do
/kernel http:\/\/192.168.0.1:8088\/agent.kernel ipa-inspection-callback-url=http:\/\/192.168.0.1:5050\/v1\/continue ipa-inspection-collectors=default.* foo=bar/
)
end
it 'should contain iPXE chainload images' do
is_expected.to contain_file('/tftpboot/undionly.kpxe').with(
'ensure' => 'present',
'require' => 'Package[ironic-inspector]',
)
is_expected.to contain_file('/tftpboot/ipxe.efi').with(
'ensure' => 'present',
'require' => 'Package[ironic-inspector]',
)
end
end
end

@ -4,7 +4,12 @@ bind-interfaces
dhcp-range=<%= @dnsmasq_ip_range %>,29
enable-tftp
tftp-root=/tftpboot
dhcp-match=ipxe,175
dhcp-boot=tag:!ipxe,undionly.kpxe,localhost.localdomain,<%= @dnsmasq_local_ip %>
dhcp-boot=tag:ipxe,http://<%= @dnsmasq_local_ip %>:8088/inspector.ipxe
dhcp-sequential-ip
dhcp-match=ipxe,175
dhcp-match=set:efi,option:client-arch,7
# Client is running iPXE; move to next stage of chainloading
dhcp-boot=tag:ipxe,http://<%= @dnsmasq_local_ip %>:8088/inspector.ipxe
# Client is running PXE over EFI; send EFI version of iPXE chainloader
dhcp-boot=tag:efi,ipxe.efi
# Client is running PXE over BIOS; send BIOS version of iPXE chainloader
dhcp-boot=undionly.kpxe,localhost.localdomain,<%= @dnsmasq_local_ip %>

@ -2,6 +2,6 @@
dhcp
kernel http://<%= @dnsmasq_local_ip %>:8088/agent.kernel ipa-inspection-callback-url=http://<%= @dnsmasq_local_ip %>:5050/v1/continue ipa-inspection-collectors=<%= @ramdisk_collectors %> systemd.journald.forward_to_console=yes BOOTIF=${mac} <%= @ramdisk_kernel_args %>
kernel http://<%= @dnsmasq_local_ip %>:8088/agent.kernel ipa-inspection-callback-url=http://<%= @dnsmasq_local_ip %>:5050/v1/continue ipa-inspection-collectors=<%= @ramdisk_collectors %> systemd.journald.forward_to_console=yes BOOTIF=${mac} <%= @ramdisk_kernel_args %> initrd=agent.ramdisk
initrd http://<%= @dnsmasq_local_ip %>:8088/agent.ramdisk
boot