From 85ff76913ebdac40fefd805ab479298b97b915e7 Mon Sep 17 00:00:00 2001 From: Josh Partlow Date: Thu, 31 Aug 2023 17:23:54 -0700 Subject: [PATCH] (PE-36580) Add r10k_known_hosts to install plan Starting with PE 2023.3, updates to r10k libraries from PE-35980 changes in libgit2 now verify host keys. Because of this code manager now needs to be configured with known hosts public key information for the r10k remote host. Without this, PE will install but code manager will fail to deploy. This patch will fail the plan early if installing PE 2023.3+, with r10k_private_key (so using ssh protocol) and no r10k_known_hosts array. --- REFERENCE.md | 27 +++++++++++++++ plans/install.pp | 2 ++ plans/subplans/install.pp | 25 ++++++++++++-- spec/plans/subplans/install_spec.rb | 51 ++++++++++++++++++++++++++++- types/known_hosts.pp | 10 ++++++ 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 types/known_hosts.pp diff --git a/REFERENCE.md b/REFERENCE.md index 6ca9b911..7e748988 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -37,6 +37,7 @@ ### Data types +* [`Peadm::Known_hosts`](#Peadm--Known_hosts) * [`Peadm::Ldap_config`](#Peadm--Ldap_config) * [`Peadm::Pe_version`](#Peadm--Pe_version) * [`Peadm::Pem`](#Peadm--Pem) @@ -776,6 +777,23 @@ Data type: `TargetSpec` ## Data types +### `Peadm::Known_hosts` + +The Peadm::Known_hosts data type. + +Alias of + +```puppet +Array[Struct[ + 'title' => Optional[String[1]], + 'ensure' => Optional[Enum['present','absent']], + 'name' => String[1], + 'type' => String[1], + 'key' => String[1], + 'host_aliases' => Optional[Variant[String[1],Array[String[1]]]], + ]] +``` + ### `Peadm::Ldap_config` The Peadm::Ldap_config data type. @@ -1548,6 +1566,7 @@ The following parameters are available in the `peadm::install` plan: * [`r10k_remote`](#-peadm--install--r10k_remote) * [`r10k_private_key_file`](#-peadm--install--r10k_private_key_file) * [`r10k_private_key_content`](#-peadm--install--r10k_private_key_content) +* [`r10k_known_hosts`](#-peadm--install--r10k_known_hosts) * [`deploy_environment`](#-peadm--install--deploy_environment) * [`license_key_file`](#-peadm--install--license_key_file) * [`license_key_content`](#-peadm--install--license_key_content) @@ -1714,6 +1733,14 @@ Data type: `Optional[Peadm::Pem]` +Default value: `undef` + +##### `r10k_known_hosts` + +Data type: `Optional[Peadm::Known_hosts]` + + + Default value: `undef` ##### `deploy_environment` diff --git a/plans/install.pp b/plans/install.pp index aefb69dc..8eead8d9 100644 --- a/plans/install.pp +++ b/plans/install.pp @@ -53,6 +53,7 @@ Optional[String] $r10k_remote = undef, Optional[String] $r10k_private_key_file = undef, Optional[Peadm::Pem] $r10k_private_key_content = undef, + Optional[Peadm::Known_hosts] $r10k_known_hosts = undef, Optional[String] $deploy_environment = undef, # License Key @@ -94,6 +95,7 @@ r10k_remote => $r10k_remote, r10k_private_key_file => $r10k_private_key_file, r10k_private_key_content => $r10k_private_key_content, + r10k_known_hosts => $r10k_known_hosts, # License Key license_key_file => $license_key_file, diff --git a/plans/subplans/install.pp b/plans/subplans/install.pp index 168fe06c..74e3d957 100644 --- a/plans/subplans/install.pp +++ b/plans/subplans/install.pp @@ -11,6 +11,12 @@ # over to the primary at /etc/puppetlabs/puppetserver/ssh/id-control_repo.rsa # If the file does not exist the value will simply be supplied to the primary # +# @param r10k_known_hosts +# Puppet Enterprise 2023.3+ requires host key verification for the +# r10k_remote host. When setting \$r10k_private_key, you must also provide +# \$r10k_known_hosts information in the form of an array of hashes with +# 'name', 'type' and 'key' information for hostname, key-type and public key. +# # @param license_key_file # The license key to use with Puppet Enterprise. If this is a local file it # will be copied over to the MoM at /etc/puppetlabs/license.key @@ -50,6 +56,7 @@ Optional[String] $r10k_remote = undef, Optional[String] $r10k_private_key_file = undef, Optional[Peadm::Pem] $r10k_private_key_content = undef, + Optional[Peadm::Known_hosts] $r10k_known_hosts = undef, # License key Optional[String] $license_key_file = undef, @@ -125,7 +132,21 @@ # either be undef or else the key content to write. $r10k_private_key = peadm::file_or_content('r10k_private_key', $r10k_private_key_file, $r10k_private_key_content) - # Same for license key + # Determine whether r10k_known_hosts is required and has been provided. + $is_pe_2023_3_or_greater = (versioncmp($version, '2023.3.0') >= 0) + if (($is_pe_2023_3_or_greater) and + ($r10k_private_key =~ NotUndef) and + ($r10k_known_hosts =~ Undef)) { + fail_plan("In Puppet Enterprise 2023.3+ r10k 4.0 requires host key verification for the r10k_remote host. When setting \$r10k_private_key, you must also provide \$r10k_known_hosts information in the form of an array of hashes with 'name', 'type' and 'key' information for hostname, key-type and public key. Puppet Enterprise version: ${version}, r10k_known_hosts: ${r10k_known_hosts}") + } + $r10k_known_hosts_config = $r10k_known_hosts ? { + undef => {}, + default => { + 'puppet_enterprise::profile::master::r10k_known_hosts' => $r10k_known_hosts, + }, + } + + # Process user input for license key (same process as for r10k private key above). $license_key = peadm::file_or_content('license_key', $license_key_file, $license_key_content) $precheck_results = run_task('peadm::precheck', $all_targets) @@ -170,7 +191,7 @@ undef => undef, default => '/etc/puppetlabs/puppetserver/ssh/id-control_repo.rsa', }, - } + $puppetdb_database_temp_config + $pe_conf_data) + } + $r10k_known_hosts_config + $puppetdb_database_temp_config + $pe_conf_data) $primary_postgresql_pe_conf = peadm::generate_pe_conf({ 'console_admin_password' => 'not used', diff --git a/spec/plans/subplans/install_spec.rb b/spec/plans/subplans/install_spec.rb index 4a687adf..354f6d02 100644 --- a/spec/plans/subplans/install_spec.rb +++ b/spec/plans/subplans/install_spec.rb @@ -4,7 +4,7 @@ # Include the BoltSpec library functions include BoltSpec::Plans - it 'minimum variables to run' do + before(:each) do allow_any_task allow_any_plan allow_any_command @@ -35,7 +35,9 @@ # rubocop:enable AnyInstance ## ########## + end + it 'minimum variables to run' do params = { 'primary_host' => 'primary', 'console_password' => 'puppetlabs', @@ -44,4 +46,51 @@ expect(run_plan('peadm::subplans::install', params)).to be_ok end + + it 'installs 2023.2 without r10k_known_hosts' do + params = { + 'primary_host' => 'primary', + 'console_password' => 'puppetlabs', + 'version' => '2023.2.0', + 'r10k_remote' => 'git@github.com:puppetlabs/nothing', + 'r10k_private_key_content' => '-----BEGINfoo', + } + + expect(run_plan('peadm::subplans::install', params)).to be_ok + end + + it 'fails if 2023.3+ and r10k_private_key set but r10k_known_hosts not set' do + params = { + 'primary_host' => 'primary', + 'console_password' => 'puppetlabs', + 'version' => '2023.3.0', + 'r10k_remote' => 'git@github.com:puppetlabs/nothing', + 'r10k_private_key_content' => '-----BEGINfoo', + 'permit_unsafe_versions' => true, + } + + result = run_plan('peadm::subplans::install', params) + expect(result).not_to be_ok + expect(result.value.message).to match(%r{Puppet Enterprise 2023\.3\+ .*requires host key verification}) + end + + it 'installs 2023.3+ with r10k_private_key and r10k_known_hosts' do + params = { + 'primary_host' => 'primary', + 'console_password' => 'puppetlabs', + 'version' => '2023.3.0', + 'r10k_remote' => 'git@github.com:puppetlabs/nothing', + 'r10k_private_key_content' => '-----BEGINfoo', + 'r10k_known_hosts' => [ + { + 'name' => 'test', + 'type' => 'key-type', + 'key' => 'abcdef', + }, + ], + 'permit_unsafe_versions' => true, + } + + expect(run_plan('peadm::subplans::install', params)).to be_ok + end end diff --git a/types/known_hosts.pp b/types/known_hosts.pp new file mode 100644 index 00000000..d08805ea --- /dev/null +++ b/types/known_hosts.pp @@ -0,0 +1,10 @@ +type Peadm::Known_hosts = Array[ + Struct[ + 'title' => Optional[String[1]], + 'ensure' => Optional[Enum['present','absent']], + 'name' => String[1], + 'type' => String[1], + 'key' => String[1], + 'host_aliases' => Optional[Variant[String[1],Array[String[1]]]], + ] +]