class Puppet::X509::CertProvider
Class for loading and saving cert related objects. By default the provider loads and saves based on puppet's default settings, such as `Puppet`. The providers sets the permissions on files it saves, such as the private key. All of the `load_*` methods take an optional `required` parameter. If an object doesn't exist, then by default the provider returns `nil`. However, if the `required` parameter is true, then an exception will be raised instead.
@api private
Constants
- CERT_DELIMITERS
- CRL_DELIMITERS
- VALID_CERTNAME
Only allow printing ascii characters, excluding /
Public Class Methods
# File lib/puppet/x509/cert_provider.rb 20 def initialize(capath: Puppet[:localcacert], 21 crlpath: Puppet[:hostcrl], 22 privatekeydir: Puppet[:privatekeydir], 23 certdir: Puppet[:certdir], 24 requestdir: Puppet[:requestdir], 25 hostprivkey: Puppet.settings.set_by_config?(:hostprivkey) ? Puppet[:hostprivkey] : nil, 26 hostcert: Puppet.settings.set_by_config?(:hostcert) ? Puppet[:hostcert] : nil) 27 @capath = capath 28 @crlpath = crlpath 29 @privatekeydir = privatekeydir 30 @certdir = certdir 31 @requestdir = requestdir 32 @hostprivkey = hostprivkey 33 @hostcert = hostcert 34 end
Public Instance Methods
Create a certificate signing request (CSR).
@param name [String] the request identity @param private_key [OpenSSL::PKey::RSA] private key @return [Puppet::X509::Request] The request
@api private
# File lib/puppet/x509/cert_provider.rb 279 def create_request(name, private_key) 280 options = {} 281 282 if Puppet[:dns_alt_names] && Puppet[:dns_alt_names] != '' 283 options[:dns_alt_names] = Puppet[:dns_alt_names] 284 end 285 286 csr_attributes = Puppet::SSL::CertificateRequestAttributes.new(Puppet[:csr_attributes]) 287 if csr_attributes.load 288 options[:csr_attributes] = csr_attributes.custom_attributes 289 options[:extension_requests] = csr_attributes.extension_requests 290 end 291 292 csr = Puppet::SSL::CertificateRequest.new(name) 293 csr.generate(private_key, options) 294 end
Return the time when the CRL was last updated.
@return [Time, nil] Time when the CRL was last updated, or nil if we don't
have a CRL
@api private
# File lib/puppet/x509/cert_provider.rb 134 def crl_last_update 135 stat = Puppet::FileSystem.stat(@crlpath) 136 Time.at(stat.mtime) 137 rescue Errno::ENOENT 138 nil 139 end
Set the CRL last updated time.
@param time [Time] The last updated time
@api private
# File lib/puppet/x509/cert_provider.rb 146 def crl_last_update=(time) 147 Puppet::FileSystem.touch(@crlpath, mtime: time) 148 end
Delete a named certificate signing request (CSR) from the configured `requestdir`.
@param name [String] The request identity @return [Boolean] true if the CSR was deleted
@api private
# File lib/puppet/x509/cert_provider.rb 332 def delete_request(name) 333 path = to_path(@requestdir, name) 334 delete_pem(path) 335 rescue SystemCallError => e 336 raise Puppet::Error.new(_("Failed to delete certificate request for '%{name}'") % {name: name}, e) 337 end
Load CA certs from the configured `capath`.
@param required [Boolean] If true, raise if they are missing @return (see load_cacerts_from_pem) @raise (see load_cacerts_from_pem) @raise [Puppet::Error] if the certs cannot be loaded
@api private
# File lib/puppet/x509/cert_provider.rb 56 def load_cacerts(required: false) 57 pem = load_pem(@capath) 58 if !pem && required 59 raise Puppet::Error, _("The CA certificates are missing from '%{path}'") % { path: @capath } 60 end 61 pem ? load_cacerts_from_pem(pem) : nil 62 rescue SystemCallError => e 63 raise Puppet::Error.new(_("Failed to load CA certificates from '%{capath}'") % {capath: @capath}, e) 64 end
Load PEM encoded CA certificates.
@param pem [String] PEM encoded certificate(s) @return [Array<OpenSSL::X509::Certificate>] Array of CA certs @raise [OpenSSL::X509::CertificateError] The `pem` text does not contain a valid cert
@api private
# File lib/puppet/x509/cert_provider.rb 73 def load_cacerts_from_pem(pem) 74 # TRANSLATORS 'PEM' is an acronym and shouldn't be translated 75 raise OpenSSL::X509::CertificateError, _("Failed to parse CA certificates as PEM") if pem !~ CERT_DELIMITERS 76 77 pem.scan(CERT_DELIMITERS).map do |text| 78 OpenSSL::X509::Certificate.new(text) 79 end 80 end
Load a named client cert from the configured `certdir`.
@param name [String] The client cert identity @param required [Boolean] If true, raise it is missing @return (see load_request_from_pem) @raise (see load_client_cert_from_pem) @raise [Puppet::Error] if the client cert cannot be loaded
@api private
# File lib/puppet/x509/cert_provider.rb 250 def load_client_cert(name, required: false) 251 path = @hostcert || to_path(@certdir, name) 252 pem = load_pem(path) 253 if !pem && required 254 raise Puppet::Error, _("The client certificate is missing from '%{path}'") % { path: path } 255 end 256 pem ? load_client_cert_from_pem(pem) : nil 257 rescue SystemCallError => e 258 raise Puppet::Error.new(_("Failed to load client certificate for '%{name}'") % {name: name}, e) 259 end
Load a PEM encoded certificate.
@param pem [String] PEM encoded cert @return [OpenSSL::X509::Certificate] the certificate @raise [OpenSSL::X509::CertificateError] The `pem` text does not contain a valid cert
@api private
# File lib/puppet/x509/cert_provider.rb 268 def load_client_cert_from_pem(pem) 269 OpenSSL::X509::Certificate.new(pem) 270 end
Load CRLs from the configured `crlpath` path.
@param required [Boolean] If true, raise if they are missing @return (see load_crls_from_pem) @raise (see load_crls_from_pem) @raise [Puppet::Error] if the CRLs cannot be loaded
@api private
# File lib/puppet/x509/cert_provider.rb 102 def load_crls(required: false) 103 pem = load_pem(@crlpath) 104 if !pem && required 105 raise Puppet::Error, _("The CRL is missing from '%{path}'") % { path: @crlpath } 106 end 107 pem ? load_crls_from_pem(pem) : nil 108 rescue SystemCallError => e 109 raise Puppet::Error.new(_("Failed to load CRLs from '%{crlpath}'") % {crlpath: @crlpath}, e) 110 end
Load PEM encoded CRL(s).
@param pem [String] PEM encoded CRL(s) @return [Array<OpenSSL::X509::CRL>] Array of CRLs @raise [OpenSSL::X509::CRLError] The `pem` text does not contain a valid CRL
@api private
# File lib/puppet/x509/cert_provider.rb 119 def load_crls_from_pem(pem) 120 # TRANSLATORS 'PEM' is an acronym and shouldn't be translated 121 raise OpenSSL::X509::CRLError, _("Failed to parse CRLs as PEM") if pem !~ CRL_DELIMITERS 122 123 pem.scan(CRL_DELIMITERS).map do |text| 124 OpenSSL::X509::CRL.new(text) 125 end 126 end
Load a private key from the configured `privatekeydir`. For historical reasons, names are case-insensitive.
@param name [String] The private key identity @param required [Boolean] If true, raise if it is missing @param password [String, nil] If the private key is encrypted, decrypt
it using the password. If the key is encrypted, but a password is not specified, then the key cannot be loaded.
@return (see load_private_key_from_pem) @raise (see load_private_key_from_pem) @raise [Puppet::Error] if the private key cannot be loaded
@api private
# File lib/puppet/x509/cert_provider.rb 187 def load_private_key(name, required: false, password: nil) 188 path = @hostprivkey || to_path(@privatekeydir, name) 189 pem = load_pem(path) 190 if !pem && required 191 raise Puppet::Error, _("The private key is missing from '%{path}'") % { path: path } 192 end 193 pem ? load_private_key_from_pem(pem, password: password) : nil 194 rescue SystemCallError => e 195 raise Puppet::Error.new(_("Failed to load private key for '%{name}'") % {name: name}, e) 196 end
Load a PEM encoded private key.
@param pem [String] PEM encoded private key @param password [String, nil] If the private key is encrypted, decrypt
it using the password. If the key is encrypted, but a password is not specified, then the key cannot be loaded.
@return [OpenSSL::PKey::RSA, OpenSSL::PKey::EC] The private key @raise [OpenSSL::PKey::PKeyError] The `pem` text does not contain a valid key
@api private
# File lib/puppet/x509/cert_provider.rb 208 def load_private_key_from_pem(pem, password: nil) 209 # set a non-nil password to ensure openssl doesn't prompt 210 password ||= '' 211 212 OpenSSL::PKey.read(pem, password) 213 end
Load the private key password.
@return [String, nil] The private key password as a binary string or nil
if there is none.
@api private
# File lib/puppet/x509/cert_provider.rb 221 def load_private_key_password 222 Puppet::FileSystem.read(Puppet[:passfile], :encoding => Encoding::BINARY) 223 rescue Errno::ENOENT 224 nil 225 end
Load a named certificate signing request (CSR) from the configured `requestdir`.
@param name [String] The request identity @return (see load_request_from_pem) @raise (see load_request_from_pem) @raise [Puppet::Error] if the cert request cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 318 def load_request(name) 319 path = to_path(@requestdir, name) 320 pem = load_pem(path) 321 pem ? load_request_from_pem(pem) : nil 322 rescue SystemCallError => e 323 raise Puppet::Error.new(_("Failed to load certificate request for '%{name}'") % {name: name}, e) 324 end
Load a PEM encoded certificate signing request (CSR).
@param pem [String] PEM encoded request @return [OpenSSL::X509::Request] the request @raise [OpenSSL::X509::RequestError] The `pem` text does not contain a valid request
@api private
# File lib/puppet/x509/cert_provider.rb 346 def load_request_from_pem(pem) 347 OpenSSL::X509::Request.new(pem) 348 end
Save `certs` to the configured `capath`.
@param certs [Array<OpenSSL::X509::Certificate>] Array of CA certs to save @raise [Puppet::Error] if the certs cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 42 def save_cacerts(certs) 43 save_pem(certs.map(&:to_pem).join, @capath, **permissions_for_setting(:localcacert)) 44 rescue SystemCallError => e 45 raise Puppet::Error.new(_("Failed to save CA certificates to '%{capath}'") % {capath: @capath}, e) 46 end
Save a named client cert to the configured `certdir`.
@param name [String] The client cert identity @param cert [OpenSSL::X509::Certificate] The cert to save @raise [Puppet::Error] if the client cert cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 234 def save_client_cert(name, cert) 235 path = @hostcert || to_path(@certdir, name) 236 save_pem(cert.to_pem, path, **permissions_for_setting(:hostcert)) 237 rescue SystemCallError => e 238 raise Puppet::Error.new(_("Failed to save client certificate for '%{name}'") % {name: name}, e) 239 end
Save `crls` to the configured `crlpath`.
@param crls [Array<OpenSSL::X509::CRL>] Array of CRLs to save @raise [Puppet::Error] if the CRLs cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 88 def save_crls(crls) 89 save_pem(crls.map(&:to_pem).join, @crlpath, **permissions_for_setting(:hostcrl)) 90 rescue SystemCallError => e 91 raise Puppet::Error.new(_("Failed to save CRLs to '%{crlpath}'") % {crlpath: @crlpath}, e) 92 end
Save named private key in the configured `privatekeydir`. For historical reasons, names are case insensitive.
@param name [String] The private key identity @param key [OpenSSL::PKey::RSA] private key @param password [String, nil] If non-nil, derive an encryption key
from the password, and use that to encrypt the private key. If nil, save the private key unencrypted.
@raise [Puppet::Error] if the private key cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 161 def save_private_key(name, key, password: nil) 162 pem = if password 163 cipher = OpenSSL::Cipher::AES.new(128, :CBC) 164 key.export(cipher, password) 165 else 166 key.to_pem 167 end 168 path = @hostprivkey || to_path(@privatekeydir, name) 169 save_pem(pem, path, **permissions_for_setting(:hostprivkey)) 170 rescue SystemCallError => e 171 raise Puppet::Error.new(_("Failed to save private key for '%{name}'") % {name: name}, e) 172 end
Save a certificate signing request (CSR) to the configured `requestdir`.
@param name [String] the request identity @param csr [OpenSSL::X509::Request] the request @raise [Puppet::Error] if the cert request cannot be saved
@api private
# File lib/puppet/x509/cert_provider.rb 303 def save_request(name, csr) 304 path = to_path(@requestdir, name) 305 save_pem(csr.to_pem, path, **permissions_for_setting(:hostcsr)) 306 rescue SystemCallError => e 307 raise Puppet::Error.new(_("Failed to save certificate request for '%{name}'") % {name: name}, e) 308 end
Private Instance Methods
# File lib/puppet/x509/cert_provider.rb 357 def permissions_for_setting(name) 358 setting = Puppet.settings.setting(name) 359 perm = { mode: setting.mode.to_i(8) } 360 if Puppet.features.root? && !Puppet::Util::Platform.windows? 361 perm[:owner] = setting.owner 362 perm[:group] = setting.group 363 end 364 perm 365 end
# File lib/puppet/x509/cert_provider.rb 352 def to_path(base, name) 353 raise _("Certname %{name} must not contain unprintable or non-ASCII characters") % { name: name.inspect } unless name =~ VALID_CERTNAME 354 File.join(base, "#{name.downcase}.pem") 355 end