class Puppet::Application::Ssl
Public Class Methods
new(command_line = Puppet::Util::CommandLine.new)
click to toggle source
Calls superclass method
Puppet::Application::new
# File lib/puppet/application/ssl.rb 90 def initialize(command_line = Puppet::Util::CommandLine.new) 91 super(command_line) 92 93 @cert_provider = Puppet::X509::CertProvider.new 94 @ssl_provider = Puppet::SSL::SSLProvider.new 95 @machine = Puppet::SSL::StateMachine.new 96 @session = Puppet.runtime[:http].create_session 97 end
Public Instance Methods
clean(certname)
click to toggle source
# File lib/puppet/application/ssl.rb 233 def clean(certname) 234 # make sure cert has been removed from the CA 235 if certname == Puppet[:ca_server] 236 cert = nil 237 238 begin 239 ssl_context = @machine.ensure_ca_certificates 240 route = create_route(ssl_context) 241 _, cert = route.get_certificate(certname, ssl_context: ssl_context) 242 rescue Puppet::HTTP::ResponseError => e 243 if e.response.code.to_i != 404 244 raise Puppet::Error.new(_("Failed to connect to the CA to determine if certificate %{certname} has been cleaned") % { certname: certname }, e) 245 end 246 rescue => e 247 raise Puppet::Error.new(_("Failed to connect to the CA to determine if certificate %{certname} has been cleaned") % { certname: certname }, e) 248 end 249 250 if cert 251 raise Puppet::Error, _(<<END) % { certname: certname } 252 The certificate %{certname} must be cleaned from the CA first. To fix this, 253 run the following commands on the CA: 254 puppetserver ca clean --certname %{certname} 255 puppet ssl clean 256 END 257 end 258 end 259 260 paths = { 261 'private key' => Puppet[:hostprivkey], 262 'public key' => Puppet[:hostpubkey], 263 'certificate request' => Puppet[:hostcsr], 264 'certificate' => Puppet[:hostcert], 265 'private key password file' => Puppet[:passfile] 266 } 267 if options[:localca] 268 paths['local CA certificate'] = Puppet[:localcacert] 269 paths['local CRL'] = Puppet[:hostcrl] 270 end 271 paths.each_pair do |label, path| 272 if Puppet::FileSystem.exist?(path) 273 Puppet::FileSystem.unlink(path) 274 Puppet.notice _("Removed %{label} %{path}") % { label: label, path: path } 275 end 276 end 277 end
download_cert(ssl_context)
click to toggle source
# File lib/puppet/application/ssl.rb 190 def download_cert(ssl_context) 191 key = @cert_provider.load_private_key(Puppet[:certname]) 192 193 # try to download cert 194 route = create_route(ssl_context) 195 Puppet.info _("Downloading certificate '%{name}' from %{url}") % { name: Puppet[:certname], url: route.url } 196 197 _, x509 = route.get_certificate(Puppet[:certname], ssl_context: ssl_context) 198 cert = OpenSSL::X509::Certificate.new(x509) 199 Puppet.notice _("Downloaded certificate '%{name}' with fingerprint %{fingerprint}") % { name: Puppet[:certname], fingerprint: fingerprint(cert) } 200 201 # verify client cert before saving 202 @ssl_provider.create_context( 203 cacerts: ssl_context.cacerts, crls: ssl_context.crls, private_key: key, client_cert: cert 204 ) 205 @cert_provider.save_client_cert(Puppet[:certname], cert) 206 @cert_provider.delete_request(Puppet[:certname]) 207 cert 208 rescue Puppet::HTTP::ResponseError => e 209 if e.response.code == 404 210 return nil 211 else 212 raise Puppet::Error.new(_("Failed to download certificate: %{message}") % { message: e.message }, e) 213 end 214 rescue => e 215 raise Puppet::Error.new(_("Failed to download certificate: %{message}") % { message: e.message }, e) 216 end
help()
click to toggle source
# File lib/puppet/application/ssl.rb 12 def help 13 <<-HELP 14 puppet-ssl(8) -- #{summary} 15 ======== 16 17 SYNOPSIS 18 -------- 19 Manage SSL keys and certificates for SSL clients needing 20 to communicate with a puppet infrastructure. 21 22 USAGE 23 ----- 24 puppet ssl <action> [-h|--help] [-v|--verbose] [-d|--debug] [--localca] [--target CERTNAME] 25 26 27 OPTIONS 28 ------- 29 30 * --help: 31 Print this help message. 32 33 * --verbose: 34 Print extra information. 35 36 * --debug: 37 Enable full debugging. 38 39 * --localca 40 Also clean the local CA certificate and CRL. 41 42 * --target CERTNAME 43 Clean the specified device certificate instead of this host's certificate. 44 45 ACTIONS 46 ------- 47 48 * bootstrap: 49 Perform all of the steps necessary to request and download a client 50 certificate. If autosigning is disabled, then puppet will wait every 51 `waitforcert` seconds for its certificate to be signed. To only attempt 52 once and never wait, specify a time of 0. Since `waitforcert` is a 53 Puppet setting, it can be specified as a time interval, such as 30s, 54 5m, 1h. 55 56 * submit_request: 57 Generate a certificate signing request (CSR) and submit it to the CA. If 58 a private and public key pair already exist, they will be used to generate 59 the CSR. Otherwise a new key pair will be generated. If a CSR has already 60 been submitted with the given `certname`, then the operation will fail. 61 62 * download_cert: 63 Download a certificate for this host. If the current private key matches 64 the downloaded certificate, then the certificate will be saved and used 65 for subsequent requests. If there is already an existing certificate, it 66 will be overwritten. 67 68 * verify: 69 Verify the private key and certificate are present and match, verify the 70 certificate is issued by a trusted CA, and check revocation status. 71 72 * clean: 73 Remove the private key and certificate related files for this host. If 74 `--localca` is specified, then also remove this host's local copy of the 75 CA certificate(s) and CRL bundle. if `--target CERTNAME` is specified, then 76 remove the files for the specified device on this host instead of this host. 77 78 * show: 79 Print the full-text version of this host's certificate. 80 HELP 81 end
main()
click to toggle source
# File lib/puppet/application/ssl.rb 104 def main 105 if command_line.args.empty? 106 raise Puppet::Error, _("An action must be specified.") 107 end 108 109 if options[:target] 110 # Override the following, as per lib/puppet/application/device.rb 111 Puppet[:certname] = options[:target] 112 Puppet[:confdir] = File.join(Puppet[:devicedir], Puppet[:certname]) 113 Puppet[:vardir] = File.join(Puppet[:devicedir], Puppet[:certname]) 114 Puppet.settings.use(:main, :agent, :device) 115 else 116 Puppet.settings.use(:main, :agent) 117 end 118 119 Puppet::SSL::Oids.register_puppet_oids 120 Puppet::SSL::Oids.load_custom_oid_file(Puppet[:trusted_oid_mapping_file]) 121 122 certname = Puppet[:certname] 123 action = command_line.args.first 124 case action 125 when 'submit_request' 126 ssl_context = @machine.ensure_ca_certificates 127 if submit_request(ssl_context) 128 cert = download_cert(ssl_context) 129 unless cert 130 Puppet.info(_("The certificate for '%{name}' has not yet been signed") % { name: certname }) 131 end 132 end 133 when 'download_cert' 134 ssl_context = @machine.ensure_ca_certificates 135 cert = download_cert(ssl_context) 136 unless cert 137 raise Puppet::Error, _("The certificate for '%{name}' has not yet been signed") % { name: certname } 138 end 139 when 'verify' 140 verify(certname) 141 when 'clean' 142 clean(certname) 143 when 'bootstrap' 144 if !Puppet::Util::Log.sendlevel?(:info) 145 Puppet::Util::Log.level = :info 146 end 147 @machine.ensure_client_certificate 148 Puppet.notice(_("Completed SSL initialization")) 149 when 'show' 150 show(certname) 151 else 152 raise Puppet::Error, _("Unknown action '%{action}'") % { action: action } 153 end 154 end
setup_logs()
click to toggle source
# File lib/puppet/application/ssl.rb 99 def setup_logs 100 set_log_level(options) 101 Puppet::Util::Log.newdestination(:console) 102 end
show(certname)
click to toggle source
# File lib/puppet/application/ssl.rb 156 def show(certname) 157 password = @cert_provider.load_private_key_password 158 ssl_context = @ssl_provider.load_context(certname: certname, password: password) 159 puts ssl_context.client_cert.to_text 160 end
submit_request(ssl_context)
click to toggle source
# File lib/puppet/application/ssl.rb 162 def submit_request(ssl_context) 163 key = @cert_provider.load_private_key(Puppet[:certname]) 164 unless key 165 if Puppet[:key_type] == 'ec' 166 Puppet.info _("Creating a new EC SSL key for %{name} using curve %{curve}") % { name: Puppet[:certname], curve: Puppet[:named_curve] } 167 key = OpenSSL::PKey::EC.generate(Puppet[:named_curve]) 168 else 169 Puppet.info _("Creating a new SSL key for %{name}") % { name: Puppet[:certname] } 170 key = OpenSSL::PKey::RSA.new(Puppet[:keylength].to_i) 171 end 172 @cert_provider.save_private_key(Puppet[:certname], key) 173 end 174 175 csr = @cert_provider.create_request(Puppet[:certname], key) 176 route = create_route(ssl_context) 177 route.put_certificate_request(Puppet[:certname], csr, ssl_context: ssl_context) 178 @cert_provider.save_request(Puppet[:certname], csr) 179 Puppet.notice _("Submitted certificate request for '%{name}' to %{url}") % { name: Puppet[:certname], url: route.url } 180 rescue Puppet::HTTP::ResponseError => e 181 if e.response.code == 400 182 raise Puppet::Error.new(_("Could not submit certificate request for '%{name}' to %{url} due to a conflict on the server") % { name: Puppet[:certname], url: route.url }) 183 else 184 raise Puppet::Error.new(_("Failed to submit certificate request: %{message}") % { message: e.message }, e) 185 end 186 rescue => e 187 raise Puppet::Error.new(_("Failed to submit certificate request: %{message}") % { message: e.message }, e) 188 end
summary()
click to toggle source
# File lib/puppet/application/ssl.rb 8 def summary 9 _("Manage SSL keys and certificates for puppet SSL clients") 10 end
verify(certname)
click to toggle source
# File lib/puppet/application/ssl.rb 218 def verify(certname) 219 password = @cert_provider.load_private_key_password 220 ssl_context = @ssl_provider.load_context(certname: certname, password: password) 221 222 # print from root to client 223 ssl_context.client_chain.reverse.each_with_index do |cert, i| 224 digest = Puppet::SSL::Digest.new('SHA256', cert.to_der) 225 if i == ssl_context.client_chain.length - 1 226 Puppet.notice("Verified client certificate '#{cert.subject.to_utf8}' fingerprint #{digest}") 227 else 228 Puppet.notice("Verified CA certificate '#{cert.subject.to_utf8}' fingerprint #{digest}") 229 end 230 end 231 end
Private Instance Methods
create_route(ssl_context)
click to toggle source
# File lib/puppet/application/ssl.rb 285 def create_route(ssl_context) 286 @session.route_to(:ca, ssl_context: ssl_context) 287 end
fingerprint(cert)
click to toggle source
# File lib/puppet/application/ssl.rb 281 def fingerprint(cert) 282 Puppet::SSL::Digest.new(nil, cert.to_der) 283 end