diff --git a/documentation/install.md b/documentation/install.md index 7488bb4f..e2509946 100644 --- a/documentation/install.md +++ b/documentation/install.md @@ -107,7 +107,19 @@ Example params.json Bolt parameters file (shown: Extra Large with DR): } ``` -Review the [peadm::install plan](../plans/install.pp) to learn about more advanced installation options. It is possible to supply an ssh private key and git clone URL for a control-repo as part of installation, for example. +Example params.json Bolt parameters file (shown: Standard): + +```json +{ + "primary_host": "pe-xl-core-0.lab1.puppet.vm", + + "console_password": "puppetlabs", + "dns_alt_names": [ "puppet", "puppet.lab1.puppet.vm" ], + "version": "2021.5.0", +} +``` + +Review the [peadm::install plan](../plans/install.pp) to learn about more advanced installation options. For example, it is possible to: supply an ssh private key and git clone URL for a control-repo as part of installation; supply the LDAP configuration data for PE; and similar complete automation tie-ins. ## Offline usage diff --git a/plans/install.pp b/plans/install.pp index 8d8590f6..44e1a319 100644 --- a/plans/install.pp +++ b/plans/install.pp @@ -16,6 +16,11 @@ # specified, PEAdm will attempt to download PE installation media from its # standard public source. When specified, PEAdm will download directly from the # URL given. +# @param ldap_config +# If specified, configures PE RBAC DS with the supplied configuration hash. +# The parameter should be set to a valid set of connection settings as +# documented for the PE RBAC /ds endpoint. See: +# https://puppet.com/docs/pe/latest/rbac_api_v1_directory.html#put_ds-request_format # plan peadm::install ( # Standard @@ -38,6 +43,7 @@ Optional[String] $internal_compiler_a_pool_address = undef, Optional[String] $internal_compiler_b_pool_address = undef, Optional[Hash] $pe_conf_data = { }, + Optional[Peadm::Ldap_config] $ldap_config = undef, # Code Manager Optional[String] $r10k_remote = undef, @@ -109,6 +115,7 @@ internal_compiler_a_pool_address => $internal_compiler_a_pool_address, internal_compiler_b_pool_address => $internal_compiler_b_pool_address, deploy_environment => $deploy_environment, + ldap_config => $ldap_config, # Other stagingdir => $stagingdir, diff --git a/plans/subplans/configure.pp b/plans/subplans/configure.pp index 6d039e9f..e6d04f44 100644 --- a/plans/subplans/configure.pp +++ b/plans/subplans/configure.pp @@ -13,6 +13,9 @@ # A load balancer address directing traffic to any of the "B" pool # compilers. This is used for DR configuration in large and extra large # architectures. +# @param ldap_config +# This hash contains the options necessary for configuring the LDAP +# connection on the main server. # plan peadm::subplans::configure ( # Standard @@ -27,11 +30,12 @@ Optional[Peadm::SingleTargetSpec] $replica_postgresql_host = undef, # Common Configuration - String $compiler_pool_address = $primary_host.peadm::certname(), - Optional[String] $internal_compiler_a_pool_address = undef, - Optional[String] $internal_compiler_b_pool_address = undef, - Optional[String] $token_file = undef, - Optional[String] $deploy_environment = undef, + String $compiler_pool_address = $primary_host.peadm::certname(), + Optional[String] $internal_compiler_a_pool_address = undef, + Optional[String] $internal_compiler_b_pool_address = undef, + Optional[String] $token_file = undef, + Optional[String] $deploy_environment = undef, + Optional[Peadm::Ldap_config] $ldap_config = undef, # Other String $stagingdir = '/tmp', @@ -105,6 +109,21 @@ ) } + if $ldap_config { + # Run the task to configure ldap + $ldap_result = run_task('peadm::pe_ldap_config', $primary_target, + pe_main => $primary_target.peadm::certname(), + ldap_config => $ldap_config, + '_catch_errors' => true, + ) + + # If there was an LDAP failure, note it and continue. + if $ldap_result[0].error { + out::message('There was a problem with the LDAP configuration, configuration must be completed manually.') + out::message($ldap_result.to_data) + } + } + # Run Puppet everywhere to pick up last remaining config tweaks run_task('peadm::puppet_runonce', peadm::flatten_compact([ $primary_target, diff --git a/tasks/pe_ldap_config.json b/tasks/pe_ldap_config.json new file mode 100644 index 00000000..fe388dd9 --- /dev/null +++ b/tasks/pe_ldap_config.json @@ -0,0 +1,17 @@ +{ + "description": "Set the ldap config in the PE console", + "parameters": { + "ldap_config": { + "type": "Peadm::Ldap_config", + "description": "The hash of options for ldap." + }, + "pe_main": { + "type": "String", + "description": "The PE Main server" + } + }, + "input_method": "stdin", + "implementations": [ + {"name": "pe_ldap_config.rb"} + ] +} diff --git a/tasks/pe_ldap_config.rb b/tasks/pe_ldap_config.rb new file mode 100755 index 00000000..fd393ee1 --- /dev/null +++ b/tasks/pe_ldap_config.rb @@ -0,0 +1,63 @@ +#!/opt/puppetlabs/puppet/bin/ruby +# Puppet Task Name: pe_ldap_config +# +# Update the LDAP configuration +# + +require 'json' +require 'net/http' +require 'open3' + +def main + params = JSON.parse(STDIN.read) + data = params['ldap_config'] + pe_main = params['pe_main'] + + caf = ['/opt/puppetlabs/bin/puppet', 'config', 'print', 'localcacert'] + cafout, cafstatus = Open3.capture2(*caf) + unless cafstatus.success? + raise 'Could not get the CA file path.' + end + + cert = ['/opt/puppetlabs/bin/puppet', 'config', 'print', 'hostcert'] + certout, certstatus = Open3.capture2(*cert) + unless certstatus.success? + raise 'Could not get the Cert file path.' + end + + key = ['/opt/puppetlabs/bin/puppet', 'config', 'print', 'hostprivkey'] + keyout, keystatus = Open3.capture2(*key) + unless keystatus.success? + raise 'Could not get the Key file path.' + end + + uri = URI("https://#{pe_main}:4433/rbac-api/v1/ds") + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.ca_file = cafout.strip + http.cert = OpenSSL::X509::Certificate.new(File.read(certout.strip)) + http.key = OpenSSL::PKey::RSA.new(File.read(keyout.strip)) + + req = Net::HTTP::Put.new(uri, 'Content-type' => 'application/json') + req.body = data.to_json + + resp = http.request(req) + + puts resp.body + raise "API response code #{resp.code}" unless resp.code == '200' +end + +begin + main +rescue => e + result = { + '_error' => { + 'msg' => e.message, + 'kind' => 'RuntimeError', + 'details' => e.message, + } + } + puts result.to_json + exit(1) +end diff --git a/types/ldap_config.pp b/types/ldap_config.pp new file mode 100644 index 00000000..ab75d005 --- /dev/null +++ b/types/ldap_config.pp @@ -0,0 +1,25 @@ +type Peadm::Ldap_config = Struct[{ + base_dn => String, + connect_timeout => Integer, + disable_ldap_matching_rule_in_chain => Boolean, + display_name => String, + group_lookup_attr => String, + group_member_attr => String, + group_name_attr => String, + group_object_class => String, + Optional[group_rdn] => Optional[String], + Optional[help_link] => Optional[String], + hostname => String, + Optional[login] => Optional[String], + Optional[password] => Optional[String], + port => Integer, + search_nested_groups => Boolean, + ssl => Boolean, + ssl_hostname_validation => Boolean, + ssl_wildcard_validation => Boolean, + start_tls => Boolean, + user_display_name_attr => String, + user_email_attr => String, + user_lookup_attr => String, + Optional[user_rdn] => Optional[String], +}]