From 4863a485cd7405f6bca9011a9694dd385d170049 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Tue, 17 May 2022 17:35:27 +1200 Subject: [PATCH] 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 --- manifests/drivers/pxe.pp | 12 ++-- manifests/params.pp | 8 +++ manifests/pxe.pp | 46 +++++++++++++ manifests/pxe/common.pp | 5 ++ ...fi_pxe_bootfile_name-eb2244dc9b9fd954.yaml | 12 ++++ spec/classes/ironic_drivers_pxe_spec.rb | 5 +- spec/classes/ironic_pxe_spec.rb | 64 +++++++++++++++++++ 7 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/uefi_pxe_bootfile_name-eb2244dc9b9fd954.yaml diff --git a/manifests/drivers/pxe.pp b/manifests/drivers/pxe.pp index 03bf07d7..e9395654 100644 --- a/manifests/drivers/pxe.pp +++ b/manifests/drivers/pxe.pp @@ -71,8 +71,11 @@ # Defaults to $::os_service_default. # # [*uefi_pxe_bootfile_name*] -# (optional) Bootfile DHCP parameter for UEFI boot mode. -# Defaults to $::os_service_default. +# (optional) Bootfile DHCP parameter for UEFI boot mode for the +# 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*] # (optional) Template file for PXE configuration for UEFI boot loader. @@ -137,7 +140,7 @@ class ironic::drivers::pxe ( $images_path = $::os_service_default, $tftp_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_ipxe_bootfile_name = 'snponly.efi', $ipxe_timeout = $::os_service_default, @@ -156,6 +159,7 @@ class ironic::drivers::pxe ( $tftp_root_real = pick($::ironic::pxe::common::tftp_root, $tftp_root) $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_pxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_pxe_bootfile_name, $uefi_pxe_bootfile_name) if $ip_version != undef { 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/tftp_master_path': value => $tftp_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_ipxe_bootfile_name': value => $uefi_ipxe_bootfile_name_real; 'pxe/ipxe_timeout': value => $ipxe_timeout_real; diff --git a/manifests/params.pp b/manifests/params.pp index 82b4fc07..c24322cf 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -66,6 +66,10 @@ class ironic::params { $syslinux_package = 'syslinux-tftpboot' $syslinux_path = '/tftpboot' $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': { $common_package_name = 'ironic-common' @@ -98,6 +102,10 @@ class ironic::params { $syslinux_path = '/var/lib/tftpboot' } $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: { fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, \ diff --git a/manifests/pxe.pp b/manifests/pxe.pp index 04c060ed..4e43a026 100644 --- a/manifests/pxe.pp +++ b/manifests/pxe.pp @@ -59,6 +59,12 @@ # driver. # 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*] # (optional) Override wheter to use xinetd instead of dnsmasq as the tftp # service facilitator. @@ -78,6 +84,7 @@ class ironic::pxe ( $tftp_bind_host = undef, $ipxe_name_base = 'ipxe-snponly', $uefi_ipxe_bootfile_name = 'snponly.efi', + $uefi_pxe_bootfile_name = 'bootx64.efi', $tftp_use_xinetd = $::ironic::params::xinetd_available, $dnsmasq_log_facility = undef, ) inherits ironic::params { @@ -89,6 +96,7 @@ class ironic::pxe ( $http_root_real = pick($::ironic::pxe::common::http_root, $http_root) $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_pxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_pxe_bootfile_name, $uefi_pxe_bootfile_name) if $::os['family'] == 'RedHat' { $arch = "-${::os['architecture']}" @@ -246,6 +254,44 @@ class ironic::pxe ( 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' |> include apache diff --git a/manifests/pxe/common.pp b/manifests/pxe/common.pp index 712b0b71..afd0b6aa 100644 --- a/manifests/pxe/common.pp +++ b/manifests/pxe/common.pp @@ -41,12 +41,17 @@ # (optional) Name of efi file used to boot servers with iPXE + UEFI. # 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 ( $tftp_root = undef, $http_root = undef, $http_port = undef, $ipxe_timeout = undef, $uefi_ipxe_bootfile_name = undef, + $uefi_pxe_bootfile_name = undef, ) { include ironic::deps } diff --git a/releasenotes/notes/uefi_pxe_bootfile_name-eb2244dc9b9fd954.yaml b/releasenotes/notes/uefi_pxe_bootfile_name-eb2244dc9b9fd954.yaml new file mode 100644 index 00000000..bd68665d --- /dev/null +++ b/releasenotes/notes/uefi_pxe_bootfile_name-eb2244dc9b9fd954.yaml @@ -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. \ No newline at end of file diff --git a/spec/classes/ironic_drivers_pxe_spec.rb b/spec/classes/ironic_drivers_pxe_spec.rb index 39ae78ae..455e7bb7 100644 --- a/spec/classes/ironic_drivers_pxe_spec.rb +++ b/spec/classes/ironic_drivers_pxe_spec.rb @@ -24,6 +24,7 @@ describe 'ironic::drivers::pxe' do let :default_params do { :uefi_ipxe_bootfile_name => 'snponly.efi', + :uefi_pxe_bootfile_name => 'bootx64.efi', } end @@ -47,9 +48,9 @@ describe 'ironic::drivers::pxe' do is_expected.to contain_ironic_config('pxe/images_path').with_value('') is_expected.to contain_ironic_config('pxe/tftp_master_path').with_value('') is_expected.to contain_ironic_config('pxe/instance_master_path').with_value('') - is_expected.to contain_ironic_config('pxe/uefi_pxe_bootfile_name').with_value('') is_expected.to contain_ironic_config('pxe/uefi_pxe_config_template').with_value('') 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('') is_expected.to contain_ironic_config('pxe/file_permission').with_value('') is_expected.to contain_ironic_config('pxe/loader_file_paths').with_value('') @@ -79,8 +80,8 @@ describe 'ironic::drivers::pxe' do :images_path => '/mnt/images', :tftp_master_path => '/mnt/master_images', :instance_master_path => '/mnt/ironic/master_images', - :uefi_pxe_bootfile_name => 'bootx64.efi', :uefi_ipxe_bootfile_name => 'ipxe.efi', + :uefi_pxe_bootfile_name => 'shim-x64.efi', :uefi_pxe_config_template => 'foo-uefi', :ipxe_timeout => '60', :pxe_bootfile_name => 'bootx64', diff --git a/spec/classes/ironic_pxe_spec.rb b/spec/classes/ironic_pxe_spec.rb index 7e81d5b7..8bbb42d7 100644 --- a/spec/classes/ironic_pxe_spec.rb +++ b/spec/classes/ironic_pxe_spec.rb @@ -76,6 +76,43 @@ describe 'ironic::pxe' do ) 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 before :each do params.merge!( @@ -128,6 +165,29 @@ describe 'ironic::pxe' do 'backup' => false, ) 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 context 'when excluding syslinux' do @@ -252,14 +312,18 @@ describe 'ironic::pxe' do case facts[:osfamily] when 'Debian' { + :grub_efi_package => 'grub-efi-amd64-signed', :ipxe_package => 'ipxe', + :shim_package => 'shim-signed', :syslinux_package => 'syslinux-common', } when 'RedHat' { :dnsmasq_tftp_package => 'openstack-ironic-dnsmasq-tftp-server', :dnsmasq_tftp_service => 'openstack-ironic-dnsmasq-tftp-server', + :grub_efi_package => 'grub2-efi-x64', :ipxe_package => 'ipxe-bootimgs', + :shim_package => 'shim', :syslinux_package => 'syslinux-tftpboot', } end