class Puppetserver::Ca::Action::Prune
Constants
- BANNER
- SUMMARY
Public Class Methods
new(logger)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 37 def initialize(logger) @logger = logger end
parser(parsed = {})
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 231 def self.parser(parsed = {}) OptionParser.new do |opts| opts.banner = BANNER opts.on('--help', 'Display this command-specific help output') do |help| parsed['help'] = true end opts.on('--config CONF', 'Path to the puppet.conf file on disk') do |conf| parsed['config'] = conf end opts.on('--remove-duplicates', 'Remove duplicate entries from CRL(default)') do |remove_duplicates| parsed['remove-duplicates'] = true end opts.on('--remove-expired', 'Remove expired entries from CRL') do |remove_expired| parsed['remove-expired'] = true end opts.on('--remove-entries', 'Remove entries from CRL') do |remove_entries| parsed['remove-entries'] = true end opts.on('--serial NUMBER[,NUMBER]', Array, 'Serial numbers(s) in HEX to be removed from CRL') do |serialnumbers| parsed['serial'] = serialnumbers end opts.on('--certname NAME[,NAME]', Array, 'Name(s) of the cert(s) to be removed from CRL') do |certnames| parsed['certname'] = certnames end end end
Public Instance Methods
parse(args)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 258 def parse(args) results = {} parser = self.class.parser(results) errors = CliParsing.parse_with_errors(parser, args) errors_were_handled = Errors.handle_with_usage(@logger, errors, parser.help) if errors_were_handled exit_code = 1 else exit_code = nil end return results, exit_code end
prune_CRL(crl)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 115 def prune_CRL(crl) number_of_removed_duplicates = 0 existed_serial_number = Set.new() revoked_list = crl.revoked @logger.debug("Pruning duplicate entries in CRL for issuer " \ "#{crl.issuer.to_s(OpenSSL::X509::Name::RFC2253)}") if @logger.debug? revoked_list.delete_if do |revoked| if existed_serial_number.add?(revoked.serial) false else number_of_removed_duplicates += 1 @logger.debug("Removing duplicate of #{revoked.serial}, " \ "revoked on #{revoked.time}\n") if @logger.debug? true end end crl.revoked=(revoked_list) return number_of_removed_duplicates end
prune_expired(crl, key, inventory_file, cadir)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 199 def prune_expired (crl, key, inventory_file, cadir) serialnumbers = [] signed_dir = "#{cadir}/signed" @logger.debug("Checking inventory file #{inventory_file} for expired entries") if @logger.debug? errors = FileSystem.validate_file_paths(inventory_file) if errors.empty? File.open(inventory_file).each_line do |line| if line.match(/\/CN=.*$/) && line.split.length == 4 not_after = line.split[2] begin not_after = Time.parse(line.split[2]) serialnumbers.push(line.split.first) if not_after < Time.now rescue ArgumentError @logger.warn "Invalid not_after time found in inventory.txt file at #{line}" next end end end else @logger.warn "Reading inventory file at #{inventory_file} failed with error #{errors}" end @logger.debug("Checking CA dir #{cadir} for expired certs") Dir.foreach(signed_dir) do |filename| if File.extname(filename) == '.pem' raw = File.read("#{signed_dir}/#{filename}") certificate = OpenSSL::X509::Certificate.new(raw) serialnumbers.push(certificate.serial.to_s(16)) if certificate.not_after < Time.now end end prune_using_serial(crl, key, serialnumbers) end
prune_using_certname(crl, key, inventory_file, cadir, certnames)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 168 def prune_using_certname(crl, key, inventory_file, cadir, certnames) serialnumbers = [] @logger.debug("Checking inventory file #{inventory_file} for matching cert names") if @logger.debug? errors = FileSystem.validate_file_paths(inventory_file) if errors.empty? File.open(inventory_file).each_line do |line| certnames.each do |certname| if line.match(/\/CN=#{certname}$/) && line.split.length == 4 serialnumbers.push(line.split.first) certnames.delete(certname) end end end else @logger.warn "Reading inventory file at #{inventory_file} failed with error #{errors}" end if certnames @logger.debug("Checking CA dir #{cadir} for matching cert names") certnames.each do |certname| cert_file = "#{cadir}/signed/#{certname}.pem" if File.file?(cert_file) raw = File.read(cert_file) certificate = OpenSSL::X509::Certificate.new(raw) serial = certificate.serial serialnumbers.push(serial.to_s(16)) end end prune_using_serial(crl, key, serialnumbers) end end
prune_using_serial(crl, key, serialnumbers)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 148 def prune_using_serial(crl, key, serialnumbers) removed_serials = [] revoked_list = crl.revoked @logger.debug("Removing entries in CRL for issuer " \ "#{crl.issuer.to_s(OpenSSL::X509::Name::RFC2253)}") if @logger.debug? serialnumbers.each do |serial| if serial.match(/^(?:0[xX])?[A-Fa-f0-9]+$/) revoked_list.delete_if do |revoked| if revoked.serial == OpenSSL::BN.new(serial.hex) removed_serials.push(serial) true end end end end crl.revoked = (revoked_list) @logger.debug("Removed these CRL entries : #{removed_serials}") if @logger.debug? return removed_serials.length end
run(inputs)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 41 def run(inputs) config_path = inputs['config'] remove_duplicates = inputs['remove-duplicates'] remove_expired = inputs['remove-expired'] remove_entries = inputs['remove-entries'] serialnumbers = inputs['serial'] certnames = inputs['certname'] exit_code = 0 # Validate the config path. if config_path errors = FileSystem.validate_file_paths(config_path) return 1 if Errors.handle_with_usage(@logger, errors) end # Validate puppet config setting. puppet = Config::Puppet.new(config_path) puppet.load(logger: @logger) return 1 if Errors.handle_with_usage(@logger, puppet.errors) # Validate arguments if (remove_entries && (!serialnumbers && !certnames)) return 1 if Errors.handle_with_usage(@logger,["--remove-entries option require --serial or --certname values"]) end # Validate that we are offline return 1 if HttpClient.check_server_online(puppet.settings, @logger) # Getting the CRL(s) loader = X509Loader.new(puppet.settings[:cacert], puppet.settings[:cakey], puppet.settings[:cacrl]) inventory_file = puppet.settings[:cert_inventory] cadir = puppet.settings[:cadir] verified_crls = loader.crls.select { |crl| crl.verify(loader.key) } number_of_removed_duplicates = 0 number_of_removed_crl_entries = 0 if verified_crls.length == 1 puppet_crl = verified_crls.first @logger.inform("Total number of certificates found in Puppet's CRL is: #{puppet_crl.revoked.length}.") if remove_entries if serialnumbers number_of_removed_crl_entries += prune_using_serial(puppet_crl, loader.key, serialnumbers) end if certnames number_of_removed_crl_entries += prune_using_certname(puppet_crl, loader.key, inventory_file, cadir, certnames) end end if remove_expired number_of_removed_crl_entries += prune_expired(puppet_crl, loader.key, inventory_file, cadir) end if (remove_duplicates || (!remove_entries && !remove_expired)) number_of_removed_duplicates += prune_CRL(puppet_crl) end if (number_of_removed_duplicates > 0 || number_of_removed_crl_entries > 0) update_pruned_CRL(puppet_crl, loader.key) FileSystem.write_file(puppet.settings[:cacrl], loader.crls, 0644) @logger.inform("Removed #{number_of_removed_duplicates} duplicated certs from Puppet's CRL.") if number_of_removed_duplicates > 0 @logger.inform("Removed #{number_of_removed_crl_entries} certs from Puppet's CRL.") if number_of_removed_crl_entries > 0 else @logger.inform("No matching revocations found in the CRL for pruning") end else @logger.err("Could not identify Puppet's CRL. Aborting prune action.") exit_code = 1 end return exit_code end
update_pruned_CRL(crl, pkey)
click to toggle source
# File lib/puppetserver/ca/action/prune.rb, line 138 def update_pruned_CRL(crl, pkey) number_ext, other_ext = crl.extensions.partition{ |ext| ext.oid == "crlNumber" } number_ext.each do |crl_number| updated_crl_number = OpenSSL::BN.new(crl_number.value) + OpenSSL::BN.new(1) crl_number.value=(OpenSSL::ASN1::Integer(updated_crl_number)) end crl.extensions=(number_ext + other_ext) crl.sign(pkey, OpenSSL::Digest::SHA256.new) end