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