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 19 def initialize(capath: Puppet[:localcacert], 20 crlpath: Puppet[:hostcrl], 21 privatekeydir: Puppet[:privatekeydir], 22 certdir: Puppet[:certdir], 23 requestdir: Puppet[:requestdir], 24 hostprivkey: Puppet.settings.set_by_config?(:hostprivkey) ? Puppet[:hostprivkey] : nil, 25 hostcert: Puppet.settings.set_by_config?(:hostcert) ? Puppet[:hostcert] : nil) 26 @capath = capath 27 @crlpath = crlpath 28 @privatekeydir = privatekeydir 29 @certdir = certdir 30 @requestdir = requestdir 31 @hostprivkey = hostprivkey 32 @hostcert = hostcert 33 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 278 def create_request(name, private_key) 279 options = {} 280 281 if Puppet[:dns_alt_names] && Puppet[:dns_alt_names] != '' 282 options[:dns_alt_names] = Puppet[:dns_alt_names] 283 end 284 285 csr_attributes = Puppet::SSL::CertificateRequestAttributes.new(Puppet[:csr_attributes]) 286 if csr_attributes.load 287 options[:csr_attributes] = csr_attributes.custom_attributes 288 options[:extension_requests] = csr_attributes.extension_requests 289 end 290 291 csr = Puppet::SSL::CertificateRequest.new(name) 292 csr.generate(private_key, options) 293 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 133 def crl_last_update 134 stat = Puppet::FileSystem.stat(@crlpath) 135 Time.at(stat.mtime) 136 rescue Errno::ENOENT 137 nil 138 end
Set the CRL last updated time.
@param time [Time] The last updated time
@api private
# File lib/puppet/x509/cert_provider.rb 145 def crl_last_update=(time) 146 Puppet::FileSystem.touch(@crlpath, mtime: time) 147 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 331 def delete_request(name) 332 path = to_path(@requestdir, name) 333 delete_pem(path) 334 rescue SystemCallError => e 335 raise Puppet::Error.new(_("Failed to delete certificate request for '%{name}'") % {name: name}, e) 336 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 55 def load_cacerts(required: false) 56 pem = load_pem(@capath) 57 if !pem && required 58 raise Puppet::Error, _("The CA certificates are missing from '%{path}'") % { path: @capath } 59 end 60 pem ? load_cacerts_from_pem(pem) : nil 61 rescue SystemCallError => e 62 raise Puppet::Error.new(_("Failed to load CA certificates from '%{capath}'") % {capath: @capath}, e) 63 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 72 def load_cacerts_from_pem(pem) 73 # TRANSLATORS 'PEM' is an acronym and shouldn't be translated 74 raise OpenSSL::X509::CertificateError, _("Failed to parse CA certificates as PEM") if pem !~ CERT_DELIMITERS 75 76 pem.scan(CERT_DELIMITERS).map do |text| 77 OpenSSL::X509::Certificate.new(text) 78 end 79 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 249 def load_client_cert(name, required: false) 250 path = @hostcert || to_path(@certdir, name) 251 pem = load_pem(path) 252 if !pem && required 253 raise Puppet::Error, _("The client certificate is missing from '%{path}'") % { path: path } 254 end 255 pem ? load_client_cert_from_pem(pem) : nil 256 rescue SystemCallError => e 257 raise Puppet::Error.new(_("Failed to load client certificate for '%{name}'") % {name: name}, e) 258 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 267 def load_client_cert_from_pem(pem) 268 OpenSSL::X509::Certificate.new(pem) 269 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 101 def load_crls(required: false) 102 pem = load_pem(@crlpath) 103 if !pem && required 104 raise Puppet::Error, _("The CRL is missing from '%{path}'") % { path: @crlpath } 105 end 106 pem ? load_crls_from_pem(pem) : nil 107 rescue SystemCallError => e 108 raise Puppet::Error.new(_("Failed to load CRLs from '%{crlpath}'") % {crlpath: @crlpath}, e) 109 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 118 def load_crls_from_pem(pem) 119 # TRANSLATORS 'PEM' is an acronym and shouldn't be translated 120 raise OpenSSL::X509::CRLError, _("Failed to parse CRLs as PEM") if pem !~ CRL_DELIMITERS 121 122 pem.scan(CRL_DELIMITERS).map do |text| 123 OpenSSL::X509::CRL.new(text) 124 end 125 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 186 def load_private_key(name, required: false, password: nil) 187 path = @hostprivkey || to_path(@privatekeydir, name) 188 pem = load_pem(path) 189 if !pem && required 190 raise Puppet::Error, _("The private key is missing from '%{path}'") % { path: path } 191 end 192 pem ? load_private_key_from_pem(pem, password: password) : nil 193 rescue SystemCallError => e 194 raise Puppet::Error.new(_("Failed to load private key for '%{name}'") % {name: name}, e) 195 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 207 def load_private_key_from_pem(pem, password: nil) 208 # set a non-nil password to ensure openssl doesn't prompt 209 password ||= '' 210 211 OpenSSL::PKey.read(pem, password) 212 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 220 def load_private_key_password 221 Puppet::FileSystem.read(Puppet[:passfile], :encoding => Encoding::BINARY) 222 rescue Errno::ENOENT 223 nil 224 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 317 def load_request(name) 318 path = to_path(@requestdir, name) 319 pem = load_pem(path) 320 pem ? load_request_from_pem(pem) : nil 321 rescue SystemCallError => e 322 raise Puppet::Error.new(_("Failed to load certificate request for '%{name}'") % {name: name}, e) 323 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 345 def load_request_from_pem(pem) 346 OpenSSL::X509::Request.new(pem) 347 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 41 def save_cacerts(certs) 42 save_pem(certs.map(&:to_pem).join, @capath, **permissions_for_setting(:localcacert)) 43 rescue SystemCallError => e 44 raise Puppet::Error.new(_("Failed to save CA certificates to '%{capath}'") % {capath: @capath}, e) 45 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 233 def save_client_cert(name, cert) 234 path = @hostcert || to_path(@certdir, name) 235 save_pem(cert.to_pem, path, **permissions_for_setting(:hostcert)) 236 rescue SystemCallError => e 237 raise Puppet::Error.new(_("Failed to save client certificate for '%{name}'") % {name: name}, e) 238 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 87 def save_crls(crls) 88 save_pem(crls.map(&:to_pem).join, @crlpath, **permissions_for_setting(:hostcrl)) 89 rescue SystemCallError => e 90 raise Puppet::Error.new(_("Failed to save CRLs to '%{crlpath}'") % {crlpath: @crlpath}, e) 91 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 160 def save_private_key(name, key, password: nil) 161 pem = if password 162 cipher = OpenSSL::Cipher::AES.new(128, :CBC) 163 key.export(cipher, password) 164 else 165 key.to_pem 166 end 167 path = @hostprivkey || to_path(@privatekeydir, name) 168 save_pem(pem, path, **permissions_for_setting(:hostprivkey)) 169 rescue SystemCallError => e 170 raise Puppet::Error.new(_("Failed to save private key for '%{name}'") % {name: name}, e) 171 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 302 def save_request(name, csr) 303 path = to_path(@requestdir, name) 304 save_pem(csr.to_pem, path, **permissions_for_setting(:hostcsr)) 305 rescue SystemCallError => e 306 raise Puppet::Error.new(_("Failed to save certificate request for '%{name}'") % {name: name}, e) 307 end
Private Instance Methods
# File lib/puppet/x509/cert_provider.rb 356 def permissions_for_setting(name) 357 setting = Puppet.settings.setting(name) 358 perm = { mode: setting.mode.to_i(8) } 359 if Puppet.features.root? && !Puppet::Util::Platform.windows? 360 perm[:owner] = setting.owner 361 perm[:group] = setting.group 362 end 363 perm 364 end
# File lib/puppet/x509/cert_provider.rb 351 def to_path(base, name) 352 raise _("Certname %{name} must not contain unprintable or non-ASCII characters") % { name: name.inspect } unless name =~ VALID_CERTNAME 353 File.join(base, "#{name.downcase}.pem") 354 end