X-Git-Url: https://git.adam-barratt.org.uk/?a=blobdiff_plain;f=3rdparty%2Fmodules%2Fcertregen%2Flib%2Fpuppet_x%2Fcertregen%2Fca.rb;fp=3rdparty%2Fmodules%2Fcertregen%2Flib%2Fpuppet_x%2Fcertregen%2Fca.rb;h=c9e74574736b754bf490e121b73473fcedd5d1c1;hb=8c20cc97eaf30a0aaf9abfba2f33d5b5f9f06ae2;hp=0000000000000000000000000000000000000000;hpb=1f80b78f88d98160faf661374fc8e760252d131b;p=mirror%2Fdsa-puppet.git diff --git a/3rdparty/modules/certregen/lib/puppet_x/certregen/ca.rb b/3rdparty/modules/certregen/lib/puppet_x/certregen/ca.rb new file mode 100644 index 000000000..c9e745747 --- /dev/null +++ b/3rdparty/modules/certregen/lib/puppet_x/certregen/ca.rb @@ -0,0 +1,137 @@ +require 'securerandom' +require 'shellwords' + +require 'puppet' +require 'puppet/util/execution' +require 'puppet/util/package' + +require 'puppet/feature/chloride' + +module PuppetX + module Certregen + module CA + module_function + + def setup + Puppet::SSL::Host.ca_location = :only + Puppet.settings.preferred_run_mode = "master" + + if !Puppet::SSL::CertificateAuthority.ca? + raise "Unable to set up CA: this node is not a CA server." + end + + if Puppet::SSL::Certificate.indirection.find('ca').nil? + raise "Unable to set up CA: the CA certificate is not present." + end + + Puppet::SSL::CertificateAuthority.instance + end + + def backup + cacert_backup_path = File.join(Puppet[:cadir], "ca_crt.#{Time.now.to_i}.pem") + Puppet.notice("Backing up current CA certificate to #{cacert_backup_path}") + FileUtils.cp(Puppet[:cacert], cacert_backup_path) + end + + # Generate an updated CA certificate with the same subject as the existing CA certificate + # and synchronize the new CA certificate with the local CA certificate. + def regenerate(ca, cert = Puppet::SSL::Certificate.indirection.find("ca")) + Puppet[:ca_name] = cert.content.subject.to_a[0][1] + + request = Puppet::SSL::CertificateRequest.new(Puppet::SSL::Host::CA_NAME) + request.generate(ca.host.key) + PuppetX::Certregen::CA.sign(ca, Puppet::SSL::CA_NAME, + {allow_dns_alt_names: false, self_signing_csr: request}) + FileUtils.cp(Puppet[:cacert], Puppet[:localcacert]) + end + + # Copy the current CA certificate and CRL to the given host. + # + # @note Only Linux systems are supported and requires that the localcacert/hostcrl setting on the + # given host is the default path. + # + # @param [String] hostname The host to copy the CA cert to + # @param [Hash] config the Chloride host config + # @return [void] + def distribute(hostname, config) + host = Chloride::Host.new(hostname, config) + host.ssh_connect + + Puppet.debug("SSH status for #{hostname}: #{host.ssh_status}") + + log_events = lambda do |event| + event.data[:messages].each do |data| + Puppet.info "[#{data.severity}:#{data.hostname}]: #{data.message.inspect}" + end + end + + distribute_cacert(host, log_events) + distribute_crl(host, log_events) + end + + def distribute_cacert(host, blk) + src = Puppet[:cacert] + dst ='/etc/puppetlabs/puppet/ssl/certs/ca.pem' # @todo: query node for localcacert + distribute_file(host, src, dst, blk) + end + + def distribute_crl(host, blk) + src = Puppet[:cacrl] + dst ='/etc/puppetlabs/puppet/ssl/crl.pem' # @todo: query node for hostcrl + distribute_file(host, src, dst, blk) + end + + def distribute_file(host, src, dst, blk) + tmp = "#{File.basename(src)}.tmp.#{SecureRandom.uuid}" + + copy_action = Chloride::Action::FileCopy.new(to_host: host, from: src, to: tmp) + copy_action.go(&blk) + if copy_action.success? + Puppet.info "Copied #{src} to #{host.hostname}:#{tmp}" + else + raise "Failed to copy #{src} to #{host.hostname}:#{tmp}: #{copy_action.status}" + end + + move_action = Chloride::Action::Execute.new(host: host, cmd: "cp #{tmp} #{dst}", sudo: true) + move_action.go(&blk) + + if move_action.success? + Puppet.info "Updated #{host.hostname}:#{dst}" + else + raise "Failed to copy #{tmp} to #{host.hostname}:#{dst}" + end + + end + + + # Enumerate Puppet nodes without relying on PuppetDB + # + # If the Puppet CA certificate has expired we cannot rely on PuppetDB working + # or being able to connect to Postgres via the network. In order to access + # this information while the CA is in a degraded state we perform the query + # directly via a local psql call. + def certnames + psql = '/opt/puppetlabs/server/bin/psql -d pe-puppetdb --pset format=unaligned --pset t=on -c %s' + query = 'SELECT certname FROM certnames WHERE deactivated IS NULL AND expired IS NULL;' + cmd = psql % Shellwords.escape(query) + Puppet::Util::Execution.execute(cmd, + uid: 'pe-postgres', + gid: 'pe-postgres').split("\n") + + end + + # Abstract API changes for CA cert signing + # + # @param ca [Puppet::SSL::CertificateAuthority] + # @param hostname [String] + # @param options [Hash] + def sign(ca, hostname, options) + if Puppet::Util::Package.versioncmp(Puppet::PUPPETVERSION, "4.6.0") != -1 + ca.sign(hostname, options) + else + ca.sign(hostname, options[:allow_dns_alt_names], options[:self_signing_csr]) + end + end + end + end +end