Class: Puppet::X509::CertProvider Private

Inherits:
Object
  • Object
show all
Includes:
PemStore
Defined in:
lib/puppet/x509/cert_provider.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

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.

Constant Summary collapse

VALID_CERTNAME =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Only allow printing ascii characters, excluding /

/\A[ -.0-~]+\Z/
CERT_DELIMITERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m
CRL_DELIMITERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

/-----BEGIN X509 CRL-----.*?-----END X509 CRL-----/m

Instance Method Summary collapse

Methods included from PemStore

#delete_pem, #load_pem, #save_pem

Constructor Details

#initialize(capath: Puppet[:localcacert], crlpath: Puppet[:hostcrl], privatekeydir: Puppet[:privatekeydir], certdir: Puppet[:certdir], requestdir: Puppet[:requestdir], hostprivkey: Puppet.settings.set_by_config?(:hostprivkey) ? Puppet[:hostprivkey] : nil, hostcert: Puppet.settings.set_by_config?(:hostcert) ? Puppet[:hostcert] : nil) ⇒ CertProvider

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of CertProvider.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/puppet/x509/cert_provider.rb', line 20

def initialize(capath: Puppet[:localcacert],
               crlpath: Puppet[:hostcrl],
               privatekeydir: Puppet[:privatekeydir],
               certdir: Puppet[:certdir],
               requestdir: Puppet[:requestdir],
               hostprivkey: Puppet.settings.set_by_config?(:hostprivkey) ? Puppet[:hostprivkey] : nil,
               hostcert: Puppet.settings.set_by_config?(:hostcert) ? Puppet[:hostcert] : nil)
  @capath = capath
  @crlpath = crlpath
  @privatekeydir = privatekeydir
  @certdir = certdir
  @requestdir = requestdir
  @hostprivkey = hostprivkey
  @hostcert = hostcert
end

Instance Method Details

#ca_last_updateTime?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return the time when the CA bundle was last updated.

Returns:

  • (Time, nil)

    Time when the CA bundle was last updated, or nil if we don’t have a CA bundle



156
157
158
159
160
161
# File 'lib/puppet/x509/cert_provider.rb', line 156

def ca_last_update
  stat = Puppet::FileSystem.stat(@capath)
  Time.at(stat.mtime)
rescue Errno::ENOENT
  nil
end

#ca_last_update=(time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the CA bundle last updated time.

Parameters:

  • time (Time)

    The last updated time



168
169
170
# File 'lib/puppet/x509/cert_provider.rb', line 168

def ca_last_update=(time)
  Puppet::FileSystem.touch(@capath, mtime: time)
end

#create_request(name, private_key) ⇒ Puppet::X509::Request

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Create a certificate signing request (CSR).

Parameters:

Returns:

  • (Puppet::X509::Request)

    The request



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/puppet/x509/cert_provider.rb', line 301

def create_request(name, private_key)
  options = {}

  if Puppet[:dns_alt_names] && Puppet[:dns_alt_names] != ''
    options[:dns_alt_names] = Puppet[:dns_alt_names]
  end

  csr_attributes = Puppet::SSL::CertificateRequestAttributes.new(Puppet[:csr_attributes])
  if csr_attributes.load
    options[:csr_attributes] = csr_attributes.custom_attributes
    options[:extension_requests] = csr_attributes.extension_requests
  end

  csr = Puppet::SSL::CertificateRequest.new(name)
  csr.generate(private_key, options)
end

#crl_last_updateTime?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return the time when the CRL was last updated.

Returns:

  • (Time, nil)

    Time when the CRL was last updated, or nil if we don’t have a CRL



134
135
136
137
138
139
# File 'lib/puppet/x509/cert_provider.rb', line 134

def crl_last_update
  stat = Puppet::FileSystem.stat(@crlpath)
  Time.at(stat.mtime)
rescue Errno::ENOENT
  nil
end

#crl_last_update=(time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the CRL last updated time.

Parameters:

  • time (Time)

    The last updated time



146
147
148
# File 'lib/puppet/x509/cert_provider.rb', line 146

def crl_last_update=(time)
  Puppet::FileSystem.touch(@crlpath, mtime: time)
end

#delete_request(name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Delete a named certificate signing request (CSR) from the configured ‘requestdir`.

Parameters:

  • name (String)

    The request identity

Returns:

  • (Boolean)

    true if the CSR was deleted



354
355
356
357
358
359
# File 'lib/puppet/x509/cert_provider.rb', line 354

def delete_request(name)
  path = to_path(@requestdir, name)
  delete_pem(path)
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to delete certificate request for '%{name}'") % {name: name}, e)
end

#load_cacerts(required: false) ⇒ Array<OpenSSL::X509::Certificate>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load CA certs from the configured ‘capath`.

Parameters:

  • required (Boolean) (defaults to: false)

    If true, raise if they are missing

Returns:

Raises:

  • (Puppet::Error)

    if the certs cannot be loaded

  • (OpenSSL::X509::CertificateError)

    The ‘pem` text does not contain a valid cert



56
57
58
59
60
61
62
63
64
# File 'lib/puppet/x509/cert_provider.rb', line 56

def load_cacerts(required: false)
  pem = load_pem(@capath)
  if !pem && required
    raise Puppet::Error, _("The CA certificates are missing from '%{path}'") % { path: @capath }
  end
  pem ? load_cacerts_from_pem(pem) : nil
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to load CA certificates from '%{capath}'") % {capath: @capath}, e)
end

#load_cacerts_from_pem(pem) ⇒ Array<OpenSSL::X509::Certificate>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load PEM encoded CA certificates.

Parameters:

  • pem (String)

    PEM encoded certificate(s)

Returns:

Raises:

  • (OpenSSL::X509::CertificateError)

    The ‘pem` text does not contain a valid cert



73
74
75
76
77
78
79
80
# File 'lib/puppet/x509/cert_provider.rb', line 73

def load_cacerts_from_pem(pem)
  # TRANSLATORS 'PEM' is an acronym and shouldn't be translated
  raise OpenSSL::X509::CertificateError, _("Failed to parse CA certificates as PEM") if pem !~ CERT_DELIMITERS

  pem.scan(CERT_DELIMITERS).map do |text|
    OpenSSL::X509::Certificate.new(text)
  end
end

#load_client_cert(name, required: false) ⇒ OpenSSL::X509::Request

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a named client cert from the configured ‘certdir`.

Parameters:

  • name (String)

    The client cert identity

  • required (Boolean) (defaults to: false)

    If true, raise it is missing

Returns:

Raises:

  • (Puppet::Error)

    if the client cert cannot be loaded

  • (OpenSSL::X509::CertificateError)

    The ‘pem` text does not contain a valid cert



272
273
274
275
276
277
278
279
280
281
# File 'lib/puppet/x509/cert_provider.rb', line 272

def load_client_cert(name, required: false)
  path = @hostcert || to_path(@certdir, name)
  pem = load_pem(path)
  if !pem && required
    raise Puppet::Error, _("The client certificate is missing from '%{path}'") % { path: path }
  end
  pem ? load_client_cert_from_pem(pem) : nil
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to load client certificate for '%{name}'") % {name: name}, e)
end

#load_client_cert_from_pem(pem) ⇒ OpenSSL::X509::Certificate

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a PEM encoded certificate.

Parameters:

  • pem (String)

    PEM encoded cert

Returns:

Raises:

  • (OpenSSL::X509::CertificateError)

    The ‘pem` text does not contain a valid cert



290
291
292
# File 'lib/puppet/x509/cert_provider.rb', line 290

def load_client_cert_from_pem(pem)
  OpenSSL::X509::Certificate.new(pem)
end

#load_crls(required: false) ⇒ Array<OpenSSL::X509::CRL>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load CRLs from the configured ‘crlpath` path.

Parameters:

  • required (Boolean) (defaults to: false)

    If true, raise if they are missing

Returns:

  • (Array<OpenSSL::X509::CRL>)

    Array of CRLs

Raises:

  • (Puppet::Error)

    if the CRLs cannot be loaded

  • (OpenSSL::X509::CRLError)

    The ‘pem` text does not contain a valid CRL



102
103
104
105
106
107
108
109
110
# File 'lib/puppet/x509/cert_provider.rb', line 102

def load_crls(required: false)
  pem = load_pem(@crlpath)
  if !pem && required
    raise Puppet::Error, _("The CRL is missing from '%{path}'") % { path: @crlpath }
  end
  pem ? load_crls_from_pem(pem) : nil
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to load CRLs from '%{crlpath}'") % {crlpath: @crlpath}, e)
end

#load_crls_from_pem(pem) ⇒ Array<OpenSSL::X509::CRL>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load PEM encoded CRL(s).

Parameters:

  • pem (String)

    PEM encoded CRL(s)

Returns:

  • (Array<OpenSSL::X509::CRL>)

    Array of CRLs

Raises:

  • (OpenSSL::X509::CRLError)

    The ‘pem` text does not contain a valid CRL



119
120
121
122
123
124
125
126
# File 'lib/puppet/x509/cert_provider.rb', line 119

def load_crls_from_pem(pem)
  # TRANSLATORS 'PEM' is an acronym and shouldn't be translated
  raise OpenSSL::X509::CRLError, _("Failed to parse CRLs as PEM") if pem !~ CRL_DELIMITERS

  pem.scan(CRL_DELIMITERS).map do |text|
    OpenSSL::X509::CRL.new(text)
  end
end

#load_private_key(name, required: false, password: nil) ⇒ OpenSSL::PKey::RSA, OpenSSL::PKey::EC

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a private key from the configured ‘privatekeydir`. For historical reasons, names are case-insensitive.

Parameters:

  • name (String)

    The private key identity

  • required (Boolean) (defaults to: false)

    If true, raise if it is missing

  • password (String, nil) (defaults to: 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.

Returns:

Raises:

  • (Puppet::Error)

    if the private key cannot be loaded

  • (OpenSSL::PKey::PKeyError)

    The ‘pem` text does not contain a valid key



209
210
211
212
213
214
215
216
217
218
# File 'lib/puppet/x509/cert_provider.rb', line 209

def load_private_key(name, required: false, password: nil)
  path = @hostprivkey || to_path(@privatekeydir, name)
  pem = load_pem(path)
  if !pem && required
    raise Puppet::Error, _("The private key is missing from '%{path}'") % { path: path }
  end
  pem ? load_private_key_from_pem(pem, password: password) : nil
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to load private key for '%{name}'") % {name: name}, e)
end

#load_private_key_from_pem(pem, password: nil) ⇒ OpenSSL::PKey::RSA, OpenSSL::PKey::EC

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a PEM encoded private key.

Parameters:

  • pem (String)

    PEM encoded private key

  • password (String, nil) (defaults to: 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.

Returns:

Raises:

  • (OpenSSL::PKey::PKeyError)

    The ‘pem` text does not contain a valid key



230
231
232
233
234
235
# File 'lib/puppet/x509/cert_provider.rb', line 230

def load_private_key_from_pem(pem, password: nil)
  # set a non-nil password to ensure openssl doesn't prompt
  password ||= ''

  OpenSSL::PKey.read(pem, password)
end

#load_private_key_passwordString?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load the private key password.

Returns:

  • (String, nil)

    The private key password as a binary string or nil if there is none.



243
244
245
246
247
# File 'lib/puppet/x509/cert_provider.rb', line 243

def load_private_key_password
  Puppet::FileSystem.read(Puppet[:passfile], :encoding => Encoding::BINARY)
rescue Errno::ENOENT
  nil
end

#load_request(name) ⇒ OpenSSL::X509::Request

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a named certificate signing request (CSR) from the configured ‘requestdir`.

Parameters:

  • name (String)

    The request identity

Returns:

Raises:

  • (Puppet::Error)

    if the cert request cannot be saved

  • (OpenSSL::X509::RequestError)

    The ‘pem` text does not contain a valid request



340
341
342
343
344
345
346
# File 'lib/puppet/x509/cert_provider.rb', line 340

def load_request(name)
  path = to_path(@requestdir, name)
  pem = load_pem(path)
  pem ? load_request_from_pem(pem) : nil
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to load certificate request for '%{name}'") % {name: name}, e)
end

#load_request_from_pem(pem) ⇒ OpenSSL::X509::Request

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Load a PEM encoded certificate signing request (CSR).

Parameters:

  • pem (String)

    PEM encoded request

Returns:

Raises:

  • (OpenSSL::X509::RequestError)

    The ‘pem` text does not contain a valid request



368
369
370
# File 'lib/puppet/x509/cert_provider.rb', line 368

def load_request_from_pem(pem)
  OpenSSL::X509::Request.new(pem)
end

#save_cacerts(certs) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Save ‘certs` to the configured `capath`.

Parameters:

Raises:



42
43
44
45
46
# File 'lib/puppet/x509/cert_provider.rb', line 42

def save_cacerts(certs)
  save_pem(certs.map(&:to_pem).join, @capath, **permissions_for_setting(:localcacert))
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to save CA certificates to '%{capath}'") % {capath: @capath}, e)
end

#save_client_cert(name, cert) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Save a named client cert to the configured ‘certdir`.

Parameters:

Raises:



256
257
258
259
260
261
# File 'lib/puppet/x509/cert_provider.rb', line 256

def save_client_cert(name, cert)
  path = @hostcert || to_path(@certdir, name)
  save_pem(cert.to_pem, path, **permissions_for_setting(:hostcert))
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to save client certificate for '%{name}'") % {name: name}, e)
end

#save_crls(crls) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Save ‘crls` to the configured `crlpath`.

Parameters:

  • crls (Array<OpenSSL::X509::CRL>)

    Array of CRLs to save

Raises:



88
89
90
91
92
# File 'lib/puppet/x509/cert_provider.rb', line 88

def save_crls(crls)
  save_pem(crls.map(&:to_pem).join, @crlpath, **permissions_for_setting(:hostcrl))
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to save CRLs to '%{crlpath}'") % {crlpath: @crlpath}, e)
end

#save_private_key(name, key, password: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Save named private key in the configured ‘privatekeydir`. For historical reasons, names are case insensitive.

Parameters:

  • name (String)

    The private key identity

  • key (OpenSSL::PKey::RSA)

    private key

  • password (String, nil) (defaults to: 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.

Raises:



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/puppet/x509/cert_provider.rb', line 183

def save_private_key(name, key, password: nil)
  pem = if password
          cipher = OpenSSL::Cipher::AES.new(128, :CBC)
          key.export(cipher, password)
        else
          key.to_pem
        end
  path = @hostprivkey || to_path(@privatekeydir, name)
  save_pem(pem, path, **permissions_for_setting(:hostprivkey))
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to save private key for '%{name}'") % {name: name}, e)
end

#save_request(name, csr) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Save a certificate signing request (CSR) to the configured ‘requestdir`.

Parameters:

Raises:



325
326
327
328
329
330
# File 'lib/puppet/x509/cert_provider.rb', line 325

def save_request(name, csr)
  path = to_path(@requestdir, name)
  save_pem(csr.to_pem, path, **permissions_for_setting(:hostcsr))
rescue SystemCallError => e
  raise Puppet::Error.new(_("Failed to save certificate request for '%{name}'") % {name: name}, e)
end