Copy shim and grub efi binaries to tftp root

Currently uefi_pxe_bootfile_name defaults to bootx86.efi, but puppet
doesn't copy any file to this location. This change copies the signed
grub shim efi to tftp root bootx86.efi, and also the signed grub
binary to grubx64.efi.

This means UEFI boot with PXE will now work by default by doing a grub
network boot instead of using iPXE. And since all EFI binaries are
signed, it should even be possible to enable Secure Boot for the whole
baremetal provisioning process.

Change-Id: I59850eca971d57464efe85ffea723f19f9855353
Closes-Bug: #1975543
This commit is contained in:
Steve Baker 2022-05-17 17:35:27 +12:00 committed by Takashi Kajinami
parent 8672adf57a
commit 4863a485cd
7 changed files with 146 additions and 6 deletions

View File

@ -71,8 +71,11 @@
# Defaults to $::os_service_default. # Defaults to $::os_service_default.
# #
# [*uefi_pxe_bootfile_name*] # [*uefi_pxe_bootfile_name*]
# (optional) Bootfile DHCP parameter for UEFI boot mode. # (optional) Bootfile DHCP parameter for UEFI boot mode for the
# Defaults to $::os_service_default. # pxe boot interface. No separate configuration template is required
# when using ipxe.
# Defaults to bootx64.efi, which will be the signed shim that loads
# grub for a network boot.
# #
# [*uefi_pxe_config_template*] # [*uefi_pxe_config_template*]
# (optional) Template file for PXE configuration for UEFI boot loader. # (optional) Template file for PXE configuration for UEFI boot loader.
@ -137,7 +140,7 @@ class ironic::drivers::pxe (
$images_path = $::os_service_default, $images_path = $::os_service_default,
$tftp_master_path = $::os_service_default, $tftp_master_path = $::os_service_default,
$instance_master_path = $::os_service_default, $instance_master_path = $::os_service_default,
$uefi_pxe_bootfile_name = $::os_service_default, $uefi_pxe_bootfile_name = 'bootx64.efi',
$uefi_pxe_config_template = $::os_service_default, $uefi_pxe_config_template = $::os_service_default,
$uefi_ipxe_bootfile_name = 'snponly.efi', $uefi_ipxe_bootfile_name = 'snponly.efi',
$ipxe_timeout = $::os_service_default, $ipxe_timeout = $::os_service_default,
@ -156,6 +159,7 @@ class ironic::drivers::pxe (
$tftp_root_real = pick($::ironic::pxe::common::tftp_root, $tftp_root) $tftp_root_real = pick($::ironic::pxe::common::tftp_root, $tftp_root)
$ipxe_timeout_real = pick($::ironic::pxe::common::ipxe_timeout, $ipxe_timeout) $ipxe_timeout_real = pick($::ironic::pxe::common::ipxe_timeout, $ipxe_timeout)
$uefi_ipxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_ipxe_bootfile_name, $uefi_ipxe_bootfile_name) $uefi_ipxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_ipxe_bootfile_name, $uefi_ipxe_bootfile_name)
$uefi_pxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_pxe_bootfile_name, $uefi_pxe_bootfile_name)
if $ip_version != undef { if $ip_version != undef {
warning('The ironic::drivers::pxe:ip_version parameter is deprecated and will be removed in the future.') warning('The ironic::drivers::pxe:ip_version parameter is deprecated and will be removed in the future.')
@ -174,7 +178,7 @@ class ironic::drivers::pxe (
'pxe/images_path': value => $images_path; 'pxe/images_path': value => $images_path;
'pxe/tftp_master_path': value => $tftp_master_path; 'pxe/tftp_master_path': value => $tftp_master_path;
'pxe/instance_master_path': value => $instance_master_path; 'pxe/instance_master_path': value => $instance_master_path;
'pxe/uefi_pxe_bootfile_name': value => $uefi_pxe_bootfile_name; 'pxe/uefi_pxe_bootfile_name': value => $uefi_pxe_bootfile_name_real;
'pxe/uefi_pxe_config_template': value => $uefi_pxe_config_template; 'pxe/uefi_pxe_config_template': value => $uefi_pxe_config_template;
'pxe/uefi_ipxe_bootfile_name': value => $uefi_ipxe_bootfile_name_real; 'pxe/uefi_ipxe_bootfile_name': value => $uefi_ipxe_bootfile_name_real;
'pxe/ipxe_timeout': value => $ipxe_timeout_real; 'pxe/ipxe_timeout': value => $ipxe_timeout_real;

View File

@ -66,6 +66,10 @@ class ironic::params {
$syslinux_package = 'syslinux-tftpboot' $syslinux_package = 'syslinux-tftpboot'
$syslinux_path = '/tftpboot' $syslinux_path = '/tftpboot'
$syslinux_files = ['pxelinux.0', 'chain.c32', 'ldlinux.c32'] $syslinux_files = ['pxelinux.0', 'chain.c32', 'ldlinux.c32']
$grub_efi_package = 'grub2-efi-x64'
$grub_efi_file = '/boot/efi/EFI/centos/grubx64.efi'
$shim_package = 'shim'
$shim_file = '/boot/efi/EFI/centos/shimx64.efi'
} }
'Debian': { 'Debian': {
$common_package_name = 'ironic-common' $common_package_name = 'ironic-common'
@ -98,6 +102,10 @@ class ironic::params {
$syslinux_path = '/var/lib/tftpboot' $syslinux_path = '/var/lib/tftpboot'
} }
$syslinux_files = ['pxelinux.0', 'chain.c32', 'libcom32.c32', 'libutil.c32'] $syslinux_files = ['pxelinux.0', 'chain.c32', 'libcom32.c32', 'libutil.c32']
$grub_efi_package = 'grub-efi-amd64-signed'
$grub_efi_file = '/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed'
$shim_package = 'shim-signed'
$shim_file = '/usr/lib/shim/shimx64.efi.signed'
} }
default: { default: {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, \ fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, \

View File

@ -59,6 +59,12 @@
# driver. # driver.
# Defaults to 'snponly.efi' # Defaults to 'snponly.efi'
# #
# [*uefi_pxe_bootfile_name*]
# (optional) Name of efi file used to boot servers with PXE + UEFI. This
# should be consistent with the uefi_pxe_bootfile_name parameter in pxe
# driver.
# Defaults to 'bootx64.efi'
#
# [*tftp_use_xinetd*] # [*tftp_use_xinetd*]
# (optional) Override wheter to use xinetd instead of dnsmasq as the tftp # (optional) Override wheter to use xinetd instead of dnsmasq as the tftp
# service facilitator. # service facilitator.
@ -78,6 +84,7 @@ class ironic::pxe (
$tftp_bind_host = undef, $tftp_bind_host = undef,
$ipxe_name_base = 'ipxe-snponly', $ipxe_name_base = 'ipxe-snponly',
$uefi_ipxe_bootfile_name = 'snponly.efi', $uefi_ipxe_bootfile_name = 'snponly.efi',
$uefi_pxe_bootfile_name = 'bootx64.efi',
$tftp_use_xinetd = $::ironic::params::xinetd_available, $tftp_use_xinetd = $::ironic::params::xinetd_available,
$dnsmasq_log_facility = undef, $dnsmasq_log_facility = undef,
) inherits ironic::params { ) inherits ironic::params {
@ -89,6 +96,7 @@ class ironic::pxe (
$http_root_real = pick($::ironic::pxe::common::http_root, $http_root) $http_root_real = pick($::ironic::pxe::common::http_root, $http_root)
$http_port_real = pick($::ironic::pxe::common::http_port, $http_port) $http_port_real = pick($::ironic::pxe::common::http_port, $http_port)
$uefi_ipxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_ipxe_bootfile_name, $uefi_ipxe_bootfile_name) $uefi_ipxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_ipxe_bootfile_name, $uefi_ipxe_bootfile_name)
$uefi_pxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_pxe_bootfile_name, $uefi_pxe_bootfile_name)
if $::os['family'] == 'RedHat' { if $::os['family'] == 'RedHat' {
$arch = "-${::os['architecture']}" $arch = "-${::os['architecture']}"
@ -246,6 +254,44 @@ class ironic::pxe (
tag => 'ironic-tftp-file', tag => 'ironic-tftp-file',
} }
ensure_resource( 'package', 'grub-efi', {
ensure => $package_ensure,
name => $::ironic::params::grub_efi_package,
tag => ['openstack', 'ironic-support-package'],
})
file { "${tftp_root_real}/grubx64.efi":
ensure => 'file',
seltype => 'tftpdir_t',
owner => $::ironic::params::user,
group => $::ironic::params::group,
mode => '0744',
source => "${::ironic::params::grub_efi_file}",
backup => false,
show_diff => false,
require => Anchor['ironic-inspector::install::end'],
tag => 'ironic-tftp-file',
}
ensure_resource( 'package', 'shim', {
ensure => $package_ensure,
name => $::ironic::params::shim_package,
tag => ['openstack', 'ironic-support-package'],
})
file { "${tftp_root_real}/${uefi_pxe_bootfile_name_real}":
ensure => 'file',
seltype => 'tftpdir_t',
owner => $::ironic::params::user,
group => $::ironic::params::group,
mode => '0744',
source => "${::ironic::params::shim_file}",
backup => false,
show_diff => false,
require => Anchor['ironic-inspector::install::end'],
tag => 'ironic-tftp-file',
}
File["${tftp_root_real}"] -> File<| tag == 'ironic-tftp-file' |> File["${tftp_root_real}"] -> File<| tag == 'ironic-tftp-file' |>
include apache include apache

View File

@ -41,12 +41,17 @@
# (optional) Name of efi file used to boot servers with iPXE + UEFI. # (optional) Name of efi file used to boot servers with iPXE + UEFI.
# Defaults to undef. # Defaults to undef.
# #
# [*uefi_pxe_bootfile_name*]
# (optional) Name of efi file used to boot servers with PXE + UEFI.
# Defaults to undef.
#
class ironic::pxe::common ( class ironic::pxe::common (
$tftp_root = undef, $tftp_root = undef,
$http_root = undef, $http_root = undef,
$http_port = undef, $http_port = undef,
$ipxe_timeout = undef, $ipxe_timeout = undef,
$uefi_ipxe_bootfile_name = undef, $uefi_ipxe_bootfile_name = undef,
$uefi_pxe_bootfile_name = undef,
) { ) {
include ironic::deps include ironic::deps
} }

View File

@ -0,0 +1,12 @@
---
features:
- |
The pxe parameter `uefi_pxe_bootfile_name` is now managed by puppet, keeping
the ironic default of `bootx64.efi`.
The shim EFI binary is copied to the TFTP root directory, to a file named
the value of `uefi_pxe_bootfile_name`. The grub EFI binary is copied to
the TFTP root directory to a file named `grubx64.efi`.
With these changes, using the pxe boot driver with UEFI boot will result in
a grub network boot which is Secure Boot capable.

View File

@ -24,6 +24,7 @@ describe 'ironic::drivers::pxe' do
let :default_params do let :default_params do
{ :uefi_ipxe_bootfile_name => 'snponly.efi', { :uefi_ipxe_bootfile_name => 'snponly.efi',
:uefi_pxe_bootfile_name => 'bootx64.efi',
} }
end end
@ -47,9 +48,9 @@ describe 'ironic::drivers::pxe' do
is_expected.to contain_ironic_config('pxe/images_path').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/images_path').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/tftp_master_path').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/tftp_master_path').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/instance_master_path').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/instance_master_path').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/uefi_pxe_bootfile_name').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/uefi_pxe_config_template').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/uefi_pxe_config_template').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/uefi_ipxe_bootfile_name').with_value('snponly.efi') is_expected.to contain_ironic_config('pxe/uefi_ipxe_bootfile_name').with_value('snponly.efi')
is_expected.to contain_ironic_config('pxe/uefi_pxe_bootfile_name').with_value('bootx64.efi')
is_expected.to contain_ironic_config('pxe/dir_permission').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/dir_permission').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/file_permission').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/file_permission').with_value('<SERVICE DEFAULT>')
is_expected.to contain_ironic_config('pxe/loader_file_paths').with_value('<SERVICE DEFAULT>') is_expected.to contain_ironic_config('pxe/loader_file_paths').with_value('<SERVICE DEFAULT>')
@ -79,8 +80,8 @@ describe 'ironic::drivers::pxe' do
:images_path => '/mnt/images', :images_path => '/mnt/images',
:tftp_master_path => '/mnt/master_images', :tftp_master_path => '/mnt/master_images',
:instance_master_path => '/mnt/ironic/master_images', :instance_master_path => '/mnt/ironic/master_images',
:uefi_pxe_bootfile_name => 'bootx64.efi',
:uefi_ipxe_bootfile_name => 'ipxe.efi', :uefi_ipxe_bootfile_name => 'ipxe.efi',
:uefi_pxe_bootfile_name => 'shim-x64.efi',
:uefi_pxe_config_template => 'foo-uefi', :uefi_pxe_config_template => 'foo-uefi',
:ipxe_timeout => '60', :ipxe_timeout => '60',
:pxe_bootfile_name => 'bootx64', :pxe_bootfile_name => 'bootx64',

View File

@ -76,6 +76,43 @@ describe 'ironic::pxe' do
) )
end end
it 'should contain grub-efi package' do
is_expected.to contain_package('grub-efi').with(
:ensure => 'present',
:name => platform_params[:grub_efi_package],
:tag => ['openstack', 'ironic-support-package'],
)
end
it 'should contain PXE UEFI shim image' do
is_expected.to contain_file('/tftpboot/bootx64.efi').with(
'owner' => 'ironic',
'group' => 'ironic',
'require' => 'Anchor[ironic-inspector::install::end]',
'seltype' => 'tftpdir_t',
'ensure' => 'file',
'show_diff' => false,
'backup' => false,
)
end
it 'should contain shim package' do
is_expected.to contain_package('shim').with(
:ensure => 'present',
:name => platform_params[:shim_package],
:tag => ['openstack', 'ironic-support-package'],
)
end
it 'should contain PXE UEFI grub image' do
is_expected.to contain_file('/tftpboot/grubx64.efi').with(
'owner' => 'ironic',
'group' => 'ironic',
'require' => 'Anchor[ironic-inspector::install::end]',
'seltype' => 'tftpdir_t',
'ensure' => 'file',
'show_diff' => false,
'backup' => false,
)
end
context 'when overriding parameters' do context 'when overriding parameters' do
before :each do before :each do
params.merge!( params.merge!(
@ -128,6 +165,29 @@ describe 'ironic::pxe' do
'backup' => false, 'backup' => false,
) )
end end
it 'should contain PXE UEFI shim image' do
is_expected.to contain_file('/var/lib/tftpboot/bootx64.efi').with(
'owner' => 'ironic',
'group' => 'ironic',
'require' => 'Anchor[ironic-inspector::install::end]',
'seltype' => 'tftpdir_t',
'ensure' => 'file',
'show_diff' => false,
'backup' => false,
)
end
it 'should contain PXE UEFI grub image' do
is_expected.to contain_file('/var/lib/tftpboot/grubx64.efi').with(
'owner' => 'ironic',
'group' => 'ironic',
'require' => 'Anchor[ironic-inspector::install::end]',
'seltype' => 'tftpdir_t',
'ensure' => 'file',
'show_diff' => false,
'backup' => false,
)
end
end end
context 'when excluding syslinux' do context 'when excluding syslinux' do
@ -252,14 +312,18 @@ describe 'ironic::pxe' do
case facts[:osfamily] case facts[:osfamily]
when 'Debian' when 'Debian'
{ {
:grub_efi_package => 'grub-efi-amd64-signed',
:ipxe_package => 'ipxe', :ipxe_package => 'ipxe',
:shim_package => 'shim-signed',
:syslinux_package => 'syslinux-common', :syslinux_package => 'syslinux-common',
} }
when 'RedHat' when 'RedHat'
{ {
:dnsmasq_tftp_package => 'openstack-ironic-dnsmasq-tftp-server', :dnsmasq_tftp_package => 'openstack-ironic-dnsmasq-tftp-server',
:dnsmasq_tftp_service => 'openstack-ironic-dnsmasq-tftp-server', :dnsmasq_tftp_service => 'openstack-ironic-dnsmasq-tftp-server',
:grub_efi_package => 'grub2-efi-x64',
:ipxe_package => 'ipxe-bootimgs', :ipxe_package => 'ipxe-bootimgs',
:shim_package => 'shim',
:syslinux_package => 'syslinux-tftpboot', :syslinux_package => 'syslinux-tftpboot',
} }
end end