Class: Chef::Knife::WindowsCertGenerate
- Inherits:
-
Chef::Knife
- Object
- Chef::Knife
- Chef::Knife::WindowsCertGenerate
- Includes:
- Mixin::PowershellExec
- Defined in:
- lib/chef/knife/windows_cert_generate.rb
Instance Attribute Summary collapse
-
#hostname ⇒ Object
Returns the value of attribute hostname.
-
#thumbprint ⇒ Object
Returns the value of attribute thumbprint.
Instance Method Summary collapse
- #certificates_already_exist?(file_path) ⇒ Boolean
-
#check_for_local_password ⇒ Object
in the world of No Certs On Disk, we store a password for a p12/pfx in Keychain or the Registry.
- #generate_certificate(rsa_key) ⇒ Object
- #generate_keypair ⇒ Object
- #prompt_for_passphrase ⇒ Object
- #run ⇒ Object
- #set_local_password(password) ⇒ Object
- #write_certificate_to_file(cert, file_path, rsa_key, store_key) ⇒ Object
Instance Attribute Details
#hostname ⇒ Object
Returns the value of attribute hostname.
28 29 30 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 28 def hostname @hostname end |
#thumbprint ⇒ Object
Returns the value of attribute thumbprint.
28 29 30 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 28 def thumbprint @thumbprint end |
Instance Method Details
#certificates_already_exist?(file_path) ⇒ Boolean
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 159 def certificates_already_exist?(file_path) certs_exists = false %w{pem pfx b64}.each do |extn| if File.exist?("#{file_path}.#{extn}") certs_exists = true break end end if certs_exists begin confirm("Do you really want to overwrite existing certificates") rescue SystemExit # Need to handle this as confirming with N/n raises SystemExit exception exit! end end end |
#check_for_local_password ⇒ Object
in the world of No Certs On Disk, we store a password for a p12/pfx in Keychain or the Registry. A p12/Pfx MUST have a password associated with it because it holds a private key Here we check to see if that password is already set.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 126 def check_for_local_password if ChefUtils.windows? powershell_code = <<-CHECKFORPASSWORD Try { $localpass = Get-ItemPropertyValue -Path "HKLM:\\Software\Progress\Authenticator" -Name "PfxPass" -ErrorAction Stop return $localpass } Catch { return $false } CHECKFORPASSWORD powershell_exec!(powershell_code).result elsif ChefUtils.macos? nil end end |
#generate_certificate(rsa_key) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 86 def generate_certificate(rsa_key) @hostname = config[:hostname] if config[:hostname] # Create a self-signed X509 certificate from the rsa_key (unencrypted) cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect cert.subject = OpenSSL::X509::Name.parse "/CN=#{@hostname}" cert.issuer = cert.subject cert.public_key = rsa_key.public_key cert.not_before = Time.now cert.not_after = cert.not_before + 2 * 365 * config[:cert_validity].to_i * 60 * 60 # 2 years validity ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = cert cert.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false)) cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false)) cert.add_extension(ef.create_extension("extendedKeyUsage", "1.3.6.1.5.5.7.3.1", false)) cert.sign(rsa_key, OpenSSL::Digest.new("SHA1")) @thumbprint = OpenSSL::Digest::SHA1.new(cert.to_der) cert end |
#generate_keypair ⇒ Object
68 69 70 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 68 def generate_keypair OpenSSL::PKey::RSA.new(config[:key_length].to_i) end |
#prompt_for_passphrase ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 72 def prompt_for_passphrase passphrase = "" begin print "Passphrases do not match. Try again.\n" unless passphrase.empty? print "Enter certificate passphrase (empty for no passphrase):" passphrase = STDIN.gets return passphrase.strip if passphrase == "\n" print "Enter same passphrase again:" confirm_passphrase = STDIN.gets end until passphrase == confirm_passphrase passphrase.strip end |
#run ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 177 def run STDOUT.sync = STDERR.sync = true # takes user specified first cli value as a destination file path for generated cert. # allowing for output_file to be ommitted if config[:output_file] == nil? config[:output_file] = File.join(::Chef::Config[:file_cache_path], "chef-#{config[:hostname]}") end file_path = @name_args.empty? ? config[:output_file].sub(/\.(\w+)$/, "") : @name_args.first # check if certs already exists at given file path certificates_already_exist? file_path if config[:store_in_certstore] == "true" || config[:store_in_certstore] == "True" || config[:store_in_certstore] == "TRUE" store_key = true else store_key = false end begin filename = File.basename(file_path) rsa_key = generate_keypair cert = generate_certificate rsa_key write_certificate_to_file cert, file_path, rsa_key, store_key ui.info "Generated Certificates:" ui.info "- #{filename}.pfx - PKCS12 format key pair. Contains public and private keys, can be used with an SSL server." ui.info "- #{filename}.b64 - Base64 encoded PKCS12 key pair. Contains public and private keys, used by some cloud provider API's to configure SSL servers." ui.info "- #{filename}.pem - Base64 encoded public certificate only. Required by the client to connect to the server." ui.info "Certificate Thumbprint: #{@thumbprint.to_s.upcase}" rescue => e puts "ERROR: + #{e}" end end |
#set_local_password(password) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 143 def set_local_password(password) print "The password you just specified is being stored in the Registry. It will be used as the default until explicitly updated\n" more_powershell_code = <<-SETTHEPASSWORD $my_pwd = ConvertTo-SecureString -String "#{password}" -Force -AsPlainText; if (-not (Test-Path HKLM:\\SOFTWARE\\Progress)){ New-Item -Path "HKLM:\\SOFTWARE\\Progress\\Authenticator" -Force New-ItemProperty -path "HKLM:\\SOFTWARE\\Progress\\Authenticator" -name "PfxPass" -value $my_pwd -PropertyType String } else{ Set-ItemProperty -path "HKLM:\\SOFTWARE\\Progress\\Authenticator" -name "PfxPass" -value $my_pwd } SETTHEPASSWORD powershell_exec!(more_powershell_code) end |
#write_certificate_to_file(cert, file_path, rsa_key, store_key) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/chef/knife/windows_cert_generate.rb', line 110 def write_certificate_to_file(cert, file_path, rsa_key, store_key) File.open(file_path + ".pem", "wb") { |f| f.print cert.to_pem } config[:cert_passphrase] = prompt_for_passphrase unless config[:cert_passphrase] if store_key == true set_local_password(config[:cert_passphrase]) end pfx = OpenSSL::PKCS12.create("#{config[:cert_passphrase]}", file_path, rsa_key, cert) File.open(file_path + ".pfx", "wb") { |f| f.print pfx.to_der } File.open(file_path + ".b64", "wb") { |f| f.print Base64.strict_encode64(pfx.to_der) } end |