File: //var/cache/puppet/lib/puppet/type/cfssl_certificate.rb
# TODO: refactoring and clean up
require 'pathname'
require 'puppet/type/file/owner'
require 'puppet/type/file/group'
require 'puppet/type/file/mode'
require 'puppet/parameter/boolean'
Puppet::Type.newtype(:cfssl_certificate) do
@doc = 'Generate ssl certificate from CloudFlare SSL Server Daemon'
ensurable do
newvalue(:present, invalidate_refreshes: true) do
unless provider.exists?
provider.create
end
end
newvalue(:absent) do
if provider.exists?
provider.destroy
end
end
end
newparam(:server) do
# string
desc 'The cfssl Server (http{s}?://localhost:8888)'
end
newparam(:trusted_ca_file) do
# string
desc 'Path to the file of a trusted certificate authority'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
end
newparam(:profile) do
# string
desc 'The profile to use'
end
newparam(:bundle, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Do we want cfssl to return a bundle'
defaultto(:false)
end
newparam(:label) do
# string
desc 'The label to use'
end
newparam(:subject) do
# hash
desc 'the certificate subject which overrides the ones in the CSR'
end
newparam(:hosts) do
# array
desc 'an array of SAN (subject alternative names) which overrides the ones in the CSR'
end
newparam(:serial_sequence) do
# array
desc 'an array of SAN (subject alternative names) which overrides the ones in the CSR'
end
newparam(:manifest) do
# hash
desc 'The cfssl certificate manifest'
end
newparam(:authkey) do
# 32 character long hex string
desc 'The authkey to use against the selected profile'
end
newparam(:name) do
# string
desc 'The file basename'
end
newparam(:certdir) do
# string
desc 'The path for save files .crt .key .pem'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
end
newparam(:certname) do
# string
desc 'The file basename to write'
defaultto { "#{@resource[:name]}.crt" }
end
newparam(:certpath) do
# string
desc 'Path to certificate file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:certname]) }
end
newparam(:cert_keepchain, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Keep certificate chain'
defaultto(:true)
end
newparam(:keyname) do
# string
desc 'The key file basename to write'
defaultto { "#{@resource[:name]}.key" }
end
newparam(:keypath) do
# string
desc 'Path to private key file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:keyname]) }
end
newparam(:csrname) do
# string
desc 'The CSR file basename to write'
defaultto { "#{@resource[:name]}.csr" }
end
newparam(:csrpath) do
# string
desc 'Path to certificate request file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:csrname]) }
end
newparam(:csr_keep, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Create CSR file'
defaultto { @resource[:bundle] }
end
newparam(:certfile_cert_keyname) do
# string
desc 'The Combined cert + key file basename to write'
defaultto { "#{@resource[:name]}.pem" }
end
newparam(:certfile_cert_keypath) do
# string
desc 'Path to combined cert + key file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:certfile_cert_keyname]) }
end
newparam(:certfile_cert_key_keep, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Create certfile_cert_key file'
defaultto { @resource[:bundle] }
end
newparam(:certbundlename) do
# string
desc 'The certificate bundle file basename to write'
defaultto { "#{@resource[:name]}-bundle.pem" }
end
newparam(:certbundlepath) do
# string
desc 'Path to certificate bundle file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:certbundlename]) }
end
newparam(:certbundle_keep, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Create certificate bundle file'
defaultto { @resource[:bundle] }
end
newparam(:fullchainname) do
# string
desc 'The fullchain file basename to write'
defaultto { "#{@resource[:name]}-fullchain.pem" }
end
newparam(:fullchainpath) do
# string
desc 'Path to fullchain file'
validate do |value|
unless Puppet::Util.absolute_path?(value, :posix) || Puppet::Util.absolute_path?(value, :windows)
raise ArgumentError, _("File paths must be fully qualified, not '%{_value}'") % { _value: value }
end
end
defaultto { File.join(@resource[:certdir], @resource[:fullchainname]) }
end
newparam(:fullchain_keep, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Create fullchain file'
defaultto { @resource[:bundle] }
end
newparam(:show_diff, boolean: true, parent: Puppet::Parameter::Boolean) do
# boolean
desc 'Show diff'
defaultto { ( ! @resource[:bundle] ) }
end
newparam(:renew_before_expiry) do
# integer
desc 'Certificate renewal before expiration in days'
defaultto(14)
end
newparam(:owner, parent: Puppet::Type::File::Owner) do
desc <<-DOC
Specifies the owner of the destination file. Valid options: a string containing a username or integer containing a uid.
DOC
end
newparam(:group, parent: Puppet::Type::File::Group) do
desc <<-DOC
Specifies a permissions group for the destination file. Valid options: a string containing a group name or integer containing a
gid.
DOC
end
newparam(:mode, parent: Puppet::Type::File::Mode) do
desc <<-DOC
Specifies the permissions mode of the destination file. Valid options: a string containing a permission mode value in octal notation.
DOC
end
autorequire(:file) do
[
Pathname.new(self[:certpath]).parent.to_s,
Pathname.new(self[:keypath]).parent.to_s,
Pathname.new(self[:csrpath]).parent.to_s,
Pathname.new(self[:certfile_cert_keypath]).parent.to_s,
Pathname.new(self[:certbundlepath]).parent.to_s,
Pathname.new(self[:fullchainpath]).parent.to_s,
].compact.uniq
end
def generate
file_opts = {
ensure: ((self[:ensure] == :absent) ? :absent : :file),
checksum: :none,
}
# TODO: validate_cmd
# https://puppet.com/docs/puppet/latest/types/file.html#file-attribute-validate_cmd
[
:owner,
:group,
:mode,
:show_diff,
].each do |param|
file_opts[param] = self[param] unless self[param].nil?
end
[
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:certpath]),
),
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:keypath],
show_diff: false),
),
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:csrpath],
ensure: (file_opts[:ensure] != :absent && self[:csr_keep]) ? :file : :absent),
),
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:certfile_cert_keypath],
show_diff: false,
ensure: (file_opts[:ensure] != :absent && self[:certfile_cert_key_keep]) ? :file : :absent),
),
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:certbundlepath],
ensure: (file_opts[:ensure] != :absent && self[:certbundle_keep]) ? :file : :absent),
),
Puppet::Type.type(:file).new(
file_opts.merge(path: self[:fullchainpath],
ensure: (file_opts[:ensure] != :absent && self[:fullchain_keep]) ? :file : :absent),
),
]
end
def eval_generate
[
catalog.resource("File[#{self[:certpath]}]"),
catalog.resource("File[#{self[:keypath]}]"),
catalog.resource("File[#{self[:csrpath]}]"),
catalog.resource("File[#{self[:certfile_cert_keypath]}]"),
catalog.resource("File[#{self[:certbundlepath]}]"),
catalog.resource("File[#{self[:fullchainpath]}]"),
]
end
def refresh
provider.create
end
end
# vim: et ts=8 sts=2 sw=2 fdm=marker