Giuseppe Lavagetto has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/327189 )

Change subject: puppet-ecdsacert: various tweaks
......................................................................


puppet-ecdsacert: various tweaks

- Unify puppet-ecdsacert and puppet-wildcardsign
- Add logging
- Add cleanup logic
- Add the CN of the cert to the SAN list automatically

Change-Id: I8c48eb6c4f59b17005036f4ffe9785a1e4a11dd4
---
M modules/puppetmaster/files/puppet_ecdsacert.rb
D modules/puppetmaster/files/puppet_wildcardsign.rb
M modules/puppetmaster/manifests/init.pp
3 files changed, 80 insertions(+), 54 deletions(-)

Approvals:
  Giuseppe Lavagetto: Looks good to me, approved
  jenkins-bot: Verified
  Volans: Looks good to me, but someone else must approve



diff --git a/modules/puppetmaster/files/puppet_ecdsacert.rb 
b/modules/puppetmaster/files/puppet_ecdsacert.rb
index 0a33719..4e8188a 100755
--- a/modules/puppetmaster/files/puppet_ecdsacert.rb
+++ b/modules/puppetmaster/files/puppet_ecdsacert.rb
@@ -1,16 +1,44 @@
 #!/usr/bin/env ruby
 # Copyright (c) 2016 Giuseppe Lavagetto, Wikimedia Foundation
 # Loosely based on 
https://github.com/ripienaar/mcollective-choria/blob/master/lib/mcollective/util/choria.rb
+require 'json'
+require 'logger'
 require 'net/http'
 require 'openssl'
-require 'yaml'
 require 'optparse'
-require 'json'
+require 'yaml'
+
+require 'puppet'
+require 'puppet/ssl/certificate_authority'
+require 'puppet/util/command_line'
 
 OpenSSL::PKey::EC.send(:alias_method, :private?, :private_key?)
 
 class PuppetECDSAGenError < StandardError
 end
+
+args = {
+  configfile: nil,
+  cert_dir: '/var/lib/puppet/ssl/certs',
+  key_dir: '/var/lib/puppet/ssl/private_keys',
+  organization: 'Wikimedia Foundation, Inc.',
+  country: 'US',
+  state: 'California',
+  locality: 'San Francisco',
+  puppetca: 'puppet',
+  altnames: [],
+  asn1_oid: 'prime256v1'
+}
+
+
+Log = Logger.new(STDOUT)
+
+Log.level = Logger::INFO
+Log.formatter = proc do |severity, datetime, _, msg|
+  date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
+  format("%s %-5s (puppet-ecdsacert): %s\n", date_format, severity, msg)
+end
+
 
 # Ecdsa certificates generator class
 # Generates the cert, the CSR, and sends the signing request to the 
puppetmaster
@@ -28,7 +56,12 @@
     parse_config args[:configfile] if args[:configfile]
 
     @common_name = args[:common_name]
-    @dns_alt_names = args[:altnames]
+    @dns_alt_names = args[:altnames].map { |domain| "DNS:#{domain}" }
+    # We need the CN in the SAN if we want to validate against it
+    @dns_alt_names << "DNS:#{@common_name}"
+    Log.info "Creating and signing ECDSA certificate for #{@common_name}"
+    Log.debug "DNS subjectAltNames: #{@dns_alt_names}"
+    Log.debug "Using NIST curve #{@config[:asn1_oid]}"
   end
 
   def parse_config(filename)
@@ -46,6 +79,7 @@
     ec_domain_key.generate_key
 
     private_key_file = File.join @config[:key_dir], "#{@common_name}.key"
+    Log.info "Storing the private key in #{private_key_file}"
     File.open(private_key_file, 'w', 0o0640) { |f| 
f.write(ec_domain_key.to_pem) }
     ec_domain_key
   end
@@ -64,6 +98,7 @@
     csr.public_key = ec_public
     csr_alt_names csr
     csr.sign ec_domain_key, OpenSSL::Digest::SHA256.new
+    Log.debug "Generated CSR at #{csr_path}"
     File.open(csr_path, "w", 0o0644) {|f| f.write(csr.to_pem)}
   end
 
@@ -79,10 +114,9 @@
   end
 
   def csr_alt_names(csr)
-    san_list = @dns_alt_names.map { |domain| "DNS:#{domain}" }
     extensions = [
       OpenSSL::X509::ExtensionFactory.new.create_extension(
-        'subjectAltName', san_list.join(',')
+        'subjectAltName', @dns_alt_names.join(',')
       )
     ]
     # add SAN extension to the CSR
@@ -109,27 +143,42 @@
     req = Net::HTTP::Put.new("/production/certificate_request/#{@common_name}",
                              'Content-Type' => 'text/plain')
     req.body = File.read csr_path
+    Log.info "Submitting CSR for signing to #{@config[:puppetca]}"
     resp, _ = https.request(req)
     fail(PuppetECDSAGenError,
          format('Signing request to %s failed with code %s: %s',
                 @config[:puppetca], resp.code, resp.body)
         ) unless resp.code == '200'
-    puts resp.message
+    Log.info "CSR request succeeded"
+  end
+
+  def cleanup
+    Log.debug "Removing file #{csr_path} if present"
+    File.delete csr_path if File.exists? csr_path
   end
 end
 
-args = {
-  configfile: nil,
-  cert_dir: '/var/lib/puppet/ssl/certs',
-  key_dir: '/var/lib/puppet/ssl/private_keys',
-  organization: 'Wikimedia Foundation',
-  country: 'US',
-  state: 'CA',
-  locality: 'San Francisco',
-  puppetca: 'puppet',
-  altnames: [],
-  asn1_oid: 'prime256v1'
-}
+module Puppet
+  module SSL
+    # Extend the signing checks
+    module CertificateAuthorityExtensions
+      def check_internal_signing_policies(hostname, csr, _allow_dns_alt_names)
+        super(hostname, csr, true)
+      rescue Puppet::SSL::CertificateAuthority::CertificateSigningError => e
+        if e.message.start_with?("CSR '#{csr.name}' subjectAltName contains a 
wildcard")
+          true
+        else
+          raise
+        end
+      end
+    end
+    # Extend the base class
+    class CertificateAuthority
+      prepend Puppet::SSL::CertificateAuthorityExtensions
+    end
+  end
+end
+
 
 OptionParser.new do |opts|
   opts.banner = "Usage: puppetecdsamanager [-c configfile] [-a SAN1,SAN2] 
common-name "
@@ -139,11 +188,14 @@
   opts.on('-a', '--alt-names ALT1,ALT2', 'Subjective alt names') do |altnames|
     args[:altnames] = altnames.split(/,\s*/).map
   end
+  opts.on('-d', '--debug', 'Show debug information') do
+    Log.level = Logger::DEBUG
+  end
 end.parse!
 
 args[:common_name] = ARGV.shift || ''
 
-fail(PuppetECDSAGenError, 'You must provide a common name') unless 
args[:common_name]
+fail(PuppetECDSAGenError, 'You must provide a common name') unless 
args[:common_name] != ''
 
 begin
   manager = PuppetECDSAGen.new args
@@ -151,6 +203,12 @@
   manager.generate_csr(ecdsa_key)
   manager.sign
 rescue PuppetECDSAGenError => e
-  puts "Error: #{e.message}"
+  Log.error "#{e.message}"
   exit 1
+ensure
+  manager.cleanup unless manager.nil?
 end
+
+Log.info "Now signing the certificate"
+# Now sign the cert using puppet's own commandline interpreter
+Puppet::Util::CommandLine.new('cert', ['sign', args[:common_name]]).execute
diff --git a/modules/puppetmaster/files/puppet_wildcardsign.rb 
b/modules/puppetmaster/files/puppet_wildcardsign.rb
deleted file mode 100755
index 6818bac..0000000
--- a/modules/puppetmaster/files/puppet_wildcardsign.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env ruby
-# Copyright (c) 2016 Giuseppe Lavagetto, Wikimedia Foundation
-# Shameful hack to allow signing certs with wildcard SANs when we want it
-# Useful for issuing internal certificates for exposing services.
-require 'puppet'
-require 'puppet/ssl/certificate_authority'
-require 'puppet/util/command_line'
-module Puppet
-  module SSL
-    # Extend the signing checks
-    module CertificateAuthorityExtensions
-      def check_internal_signing_policies(hostname, csr, _allow_dns_alt_names)
-        super(hostname, csr, true)
-      rescue Puppet::SSL::CertificateAuthority::CertificateSigningError => e
-        if e.message.start_with?("CSR '#{csr.name}' subjectAltName contains a 
wildcard")
-          true
-        else
-          raise
-        end
-      end
-    end
-    # Extend the base class
-    class CertificateAuthority
-      prepend Puppet::SSL::CertificateAuthorityExtensions
-    end
-  end
-end
-
-name = ARGV.shift || fail('The name of the certificate to sign must be 
provided.')
-Puppet::Util::CommandLine.new('cert', ['sign', name]).execute
diff --git a/modules/puppetmaster/manifests/init.pp 
b/modules/puppetmaster/manifests/init.pp
index 4f32975..263111d 100644
--- a/modules/puppetmaster/manifests/init.pp
+++ b/modules/puppetmaster/manifests/init.pp
@@ -183,15 +183,13 @@
     }
     # Small utility to generate ECDSA certs and submit the CSR to the puppet 
master
     file { '/usr/local/bin/puppet-ecdsacert':
+        ensure => absent,
         source => 'puppet:///modules/puppetmaster/puppet_ecdsacert.rb',
         mode   => '0550',
         owner  => 'root',
         group  => 'root',
     }
     file { '/usr/local/bin/puppet-wildcardsign':
-        source => 'puppet:///modules/puppetmaster/puppet_wildcardsign.rb',
-        mode   => '0550',
-        owner  => 'root',
-        group  => 'root',
+        ensure => absent,
     }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/327189
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I8c48eb6c4f59b17005036f4ffe9785a1e4a11dd4
Gerrit-PatchSet: 5
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: Volans <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to