diff --git a/REFERENCE.md b/REFERENCE.md index 1296999..827c686 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -6,22 +6,17 @@ ### Classes -* [`ca_cert`](#ca_cert): This module manages the user defined certificate authority (CA) -certificates on the server. On OSes that support a distrusted -folder the module also manages distrusting system default CA certificates. +* [`ca_cert`](#ca_cert): This module manages the shared system-wide truststore. ### Defined types -* [`ca_cert::ca`](#ca_cert--ca): Manage a user defined CA Certificate on a system. -On OSes that support distrusting pre-installed CAs this can be managed as well. +* [`ca_cert::ca`](#ca_cert--ca): Manage a CA Certificate in the the shared system-wide truststore. ## Classes ### `ca_cert` -This module manages the user defined certificate authority (CA) -certificates on the server. On OSes that support a distrusted -folder the module also manages distrusting system default CA certificates. +This module manages the shared system-wide truststore. #### Examples @@ -60,6 +55,7 @@ The following parameters are available in the `ca_cert` class: * [`update_cmd`](#-ca_cert--update_cmd) * [`trusted_cert_dir`](#-ca_cert--trusted_cert_dir) * [`distrusted_cert_dir`](#-ca_cert--distrusted_cert_dir) +* [`ca_certificates_conf`](#-ca_cert--ca_certificates_conf) * [`install_package`](#-ca_cert--install_package) * [`package_ensure`](#-ca_cert--package_ensure) * [`package_name`](#-ca_cert--package_name) @@ -95,6 +91,15 @@ Default provided by Hiera for supported Operating Systems. Default value: `undef` +##### `ca_certificates_conf` + +Data type: `Optional[Stdlib::Absolutepath]` + +Some distros use a configuration file to mark distrusted certificates. +Default provided by Hiera for supported Operating Systems. + +Default value: `undef` + ##### `install_package` Data type: `Boolean` @@ -198,8 +203,7 @@ Default value: `{}` ### `ca_cert::ca` -Manage a user defined CA Certificate on a system. -On OSes that support distrusting pre-installed CAs this can be managed as well. +Manage a CA Certificate in the the shared system-wide truststore. #### Examples @@ -215,55 +219,53 @@ ca_cert::ca { 'globalsign_org_intermediate': The following parameters are available in the `ca_cert::ca` defined type: -* [`ca_text`](#-ca_cert--ca--ca_text) -* [`source`](#-ca_cert--ca--source) * [`ensure`](#-ca_cert--ca--ensure) -* [`verify_https_cert`](#-ca_cert--ca--verify_https_cert) +* [`content`](#-ca_cert--ca--content) +* [`source`](#-ca_cert--ca--source) +* [`allow_insecure_source`](#-ca_cert--ca--allow_insecure_source) * [`checksum`](#-ca_cert--ca--checksum) * [`checksum_type`](#-ca_cert--ca--checksum_type) -##### `ca_text` +##### `ensure` -Data type: `Optional[String]` +Data type: `Enum['present', 'absent', 'trusted', 'distrusted']` -The text of the CA certificate to install. Required if text is the source -(default). If a different source is specified this parameter is ignored. +Whether or not the CA certificate should be on a system or not. +- `present`/`absent` is used to manage local/none default CAs. +- `trusted`/`distrusted` is used to manage system CAs. -Default value: `undef` +Default value: `'present'` -##### `source` +##### `content` -Data type: `String` +Data type: `Optional[String[1]]` -Where the CA certificate should be retrieved from. text, http, https, ftp, -file, and puppet protocols/sources are supported. If text, then the ca_text parameter -is also required. Defaults to text. +PEM formatted certificate content +This attribute is mutually exclusive with `source` -Default value: `'text'` +Default value: `undef` -##### `ensure` +##### `source` -Data type: `Enum['present', 'trusted', 'distrusted', 'absent']` +Data type: `Optional[String[1]]` -Whether or not the CA certificate should be on a system or not. Valid -values are trusted, present, distrusted, and absent. Note: untrusted is -not supported on Debian based systems - using it will log a warning -and treat it the same as absent. (defaults to trusted) +A source certificate, which will be copied into place on the local system. +This attribute is mutually exclusive with `content` +Uri support, see puppet-archive. -Default value: `'trusted'` +Default value: `undef` -##### `verify_https_cert` +##### `allow_insecure_source` Data type: `Boolean` -When retrieving a certificate whether or not to validate the CA of the -source. (defaults to true) +Wether to allow insecure download or not. -Default value: `true` +Default value: `false` ##### `checksum` -Data type: `Optional[String]` +Data type: `Optional[String[1]]` The checksum of the file. (defaults to undef) diff --git a/data/Archlinux-family.yaml b/data/Archlinux-family.yaml index a03beb4..8d929ec 100644 --- a/data/Archlinux-family.yaml +++ b/data/Archlinux-family.yaml @@ -1,4 +1,4 @@ --- ca_cert::update_cmd: 'trust extract-compat' -ca_cert::trusted_cert_dir: '/etc/ca-certificates/trust-source/anchors/' -ca_cert::distrusted_cert_dir: '/etc/ca-certificates/trust-source/blacklist' +ca_cert::trusted_cert_dir: '/etc/ca-certificates/trust-source/anchors' +ca_cert::distrusted_cert_dir: '/etc/ca-certificates/trust-source/blocklist' diff --git a/data/Debian-family.yaml b/data/Debian-family.yaml index 42a81c8..39191cb 100644 --- a/data/Debian-family.yaml +++ b/data/Debian-family.yaml @@ -1,3 +1,4 @@ --- -ca_cert::update_cmd: 'update-ca-certificates' -ca_cert::trusted_cert_dir: '/usr/local/share/ca-certificates' +ca_cert::update_cmd: 'update-ca-certificates' +ca_cert::trusted_cert_dir: '/usr/local/share/ca-certificates' +ca_cert::ca_certificates_conf: '/etc/ca-certificates.conf' diff --git a/data/RedHat-family-9.yaml b/data/RedHat-family-9.yaml new file mode 100644 index 0000000..a006784 --- /dev/null +++ b/data/RedHat-family-9.yaml @@ -0,0 +1,2 @@ +--- +ca_cert::distrusted_cert_dir: '/etc/pki/ca-trust/source/blocklist' diff --git a/manifests/ca.pp b/manifests/ca.pp index edb544f..a8fe87f 100644 --- a/manifests/ca.pp +++ b/manifests/ca.pp @@ -1,30 +1,27 @@ # @summary -# Manage a user defined CA Certificate on a system. -# On OSes that support distrusting pre-installed CAs this can be managed as well. +# Manage a CA Certificate in the the shared system-wide truststore. # # @example # ca_cert::ca { 'globalsign_org_intermediate': # source => 'http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt', # } # -# @param ca_text -# The text of the CA certificate to install. Required if text is the source -# (default). If a different source is specified this parameter is ignored. +# @param ensure +# Whether or not the CA certificate should be on a system or not. +# - `present`/`absent` is used to manage local/none default CAs. +# - `trusted`/`distrusted` is used to manage system CAs. # -# @param source -# Where the CA certificate should be retrieved from. text, http, https, ftp, -# file, and puppet protocols/sources are supported. If text, then the ca_text parameter -# is also required. Defaults to text. +# @param content +# PEM formatted certificate content +# This attribute is mutually exclusive with `source` # -# @param ensure -# Whether or not the CA certificate should be on a system or not. Valid -# values are trusted, present, distrusted, and absent. Note: untrusted is -# not supported on Debian based systems - using it will log a warning -# and treat it the same as absent. (defaults to trusted) +# @param source +# A source certificate, which will be copied into place on the local system. +# This attribute is mutually exclusive with `content` +# Uri support, see puppet-archive. # -# @param verify_https_cert -# When retrieving a certificate whether or not to validate the CA of the -# source. (defaults to true) +# @param allow_insecure_source +# Wether to allow insecure download or not. # # @param checksum # The checksum of the file. (defaults to undef) @@ -33,99 +30,85 @@ # The type of file checksum. (defauts to undef) # define ca_cert::ca ( - Enum['present', 'trusted', 'distrusted', 'absent'] $ensure = 'trusted', - String $source = 'text', - Boolean $verify_https_cert = true, - Optional[String] $ca_text = undef, - Optional[String] $checksum = undef, + Enum['present', 'absent', 'trusted', 'distrusted'] $ensure = 'present', + Boolean $allow_insecure_source = false, + Optional[String[1]] $source = undef, + Optional[String[1]] $content = undef, + Optional[String[1]] $checksum = undef, Optional[String[1]] $checksum_type = undef, ) { include ca_cert - if ($ensure == 'trusted' or $ensure == 'distrusted') and $source == 'text' and !$ca_text { - fail('ca_text is required if source is set to text') - } - - # Since Debian based OSes don't have explicit distrust directories - if $facts['os']['family'] == 'Debian' and $ensure == 'distrusted' { - warning("Cannot explicitly set CA distrust on ${facts['os']['name']}.") - warning("Ensuring that ${name} CA is absent from the trusted list.") - $adjusted_ensure = 'absent' - } - else { - $adjusted_ensure = $ensure - } - # Determine Full Resource Name $resource_name = "${name}.${ca_cert::ca_file_extension}" - $ca_cert = $adjusted_ensure ? { - 'distrusted' => "${ca_cert::distrusted_cert_dir}/${resource_name}", - default => "${ca_cert::trusted_cert_dir}/${resource_name}", + case $ensure { + 'present', 'absent': { + $ca_cert = "${ca_cert::trusted_cert_dir}/${resource_name}" + } + 'trusted', 'distrusted': { + $ca_cert = "${ca_cert::distrusted_cert_dir}/${resource_name}" + } + default: {} } - case $adjusted_ensure { - 'present', 'trusted', 'distrusted': { - $source_array = split($source, ':') - $protocol_type = $source_array[0] - case $protocol_type { - 'puppet': { - file { $resource_name: - ensure => 'file', - source => $source, - path => $ca_cert, - owner => 'root', - group => $ca_cert::ca_file_group, - mode => $ca_cert::ca_file_mode, - notify => Exec['ca_cert_update'], - } - } - 'ftp', 'https', 'http': { + # On Debian we trust/distrust Os provided CAs in config + if $facts['os']['family'] == 'Debian' and member(['trusted', 'distrusted'], $ensure) { + if $ensure == 'trusted' { + exec { "trust ca ${resource_name}": + command => "sed -ri \'s|!(.*)${resource_name}|\\1${resource_name}|\' ${ca_cert::ca_certificates_conf}", + onlyif => "grep -q ${resource_name} ${ca_cert::ca_certificates_conf} && grep -q \'^!.*${resource_name}\' ${ca_cert::ca_certificates_conf}", + path => ['/bin','/usr/bin'], + notify => Exec['ca_cert_update'], + } + } else { + exec { "distrust ca ${resource_name}": + command => "sed -ri \'s|(.*)${resource_name}|!\\1${resource_name}|\' ${ca_cert::ca_certificates_conf}", + onlyif => "grep -q ${resource_name} ${ca_cert::ca_certificates_conf} && grep -q \'^[^!].*${resource_name}\' ${ca_cert::ca_certificates_conf}", + path => ['/bin','/usr/bin'], + notify => Exec['ca_cert_update'], + } + } + } + else { + case $ensure { + 'present', 'distrusted': { + if $source { archive { $ca_cert: ensure => 'present', source => $source, checksum => $checksum, checksum_type => $checksum_type, - allow_insecure => !$verify_https_cert, + allow_insecure => $allow_insecure_source, notify => Exec['ca_cert_update'], } - } - 'file': { - $source_path = $source_array[1] - file { $resource_name: + -> file { $ca_cert: ensure => 'file', - source => $source_path, - path => $ca_cert, owner => 'root', group => $ca_cert::ca_file_group, mode => $ca_cert::ca_file_mode, notify => Exec['ca_cert_update'], } - } - 'text': { - file { $resource_name: + } elsif $content { + file { $ca_cert: ensure => 'file', - content => $ca_text, - path => $ca_cert, + content => $content, owner => 'root', group => $ca_cert::ca_file_group, mode => $ca_cert::ca_file_mode, notify => Exec['ca_cert_update'], } - } - default: { - fail('Protocol must be puppet, file, http, https, ftp, or text.') + } else { + fail('Either `source` or `content` is required') } } - } - 'absent': { - file { $ca_cert: - ensure => absent, - notify => Exec['ca_cert_update'], + 'absent', 'trusted': { + file { $ca_cert: + ensure => absent, + notify => Exec['ca_cert_update'], + } } - } - default: { - fail("Ca_cert::Ca[${name}] - ensure must be set to present, trusted, distrusted, or absent.") + default: {} } } } diff --git a/manifests/init.pp b/manifests/init.pp index 0598e73..58ec5d7 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,7 +1,5 @@ # @summary -# This module manages the user defined certificate authority (CA) -# certificates on the server. On OSes that support a distrusted -# folder the module also manages distrusting system default CA certificates. +# This module manages the shared system-wide truststore. # # @example Basic usage # class { 'ca_cert': } @@ -34,6 +32,10 @@ # Absolute directory path to the folder containing distrusted certificates. # Default provided by Hiera for supported Operating Systems. # +# @param ca_certificates_conf +# Some distros use a configuration file to mark distrusted certificates. +# Default provided by Hiera for supported Operating Systems. +# # @param install_package # Whether or not this module should install the ca_certificates package. # The package contains the system default (typically Mozilla) CA @@ -82,6 +84,7 @@ String[1] $update_cmd, Stdlib::Absolutepath $trusted_cert_dir, Optional[Stdlib::Absolutepath] $distrusted_cert_dir = undef, + Optional[Stdlib::Absolutepath] $ca_certificates_conf = undef, Boolean $install_package = true, Stdlib::Ensure::Package $package_ensure = 'installed', String[1] $package_name = 'ca-certificates', diff --git a/spec/acceptance/ca_cert_ca_spec.rb b/spec/acceptance/ca_cert_ca_spec.rb index b63405c..45a5c19 100644 --- a/spec/acceptance/ca_cert_ca_spec.rb +++ b/spec/acceptance/ca_cert_ca_spec.rb @@ -2,31 +2,36 @@ case host_inventory['facter']['os']['family'] when 'Debian' - trusted_ca_file_remote = '/usr/local/share/ca-certificates/Globalsign_Org_Intermediate.crt' - absent_ca_file_remote = '/etc/pki/ca-trust/source/blacklist/CACert.crt' + trusted_ca_file_remote = '/usr/local/share/ca-certificates/DigiCert_G5_TLS_ECC_SHA384_2021_CA1.crt' trusted_ca_file_text = '/usr/local/share/ca-certificates/InCommon.crt' + ca_certificates_conf = '/etc/ca-certificates.conf' + ca_certificates_bundle = '/etc/ssl/certs/ca-certificates.crt' when 'RedHat' - trusted_ca_file_remote = '/etc/pki/ca-trust/source/anchors/Globalsign_Org_Intermediate.crt' - untrusted_ca_file_remote = '/etc/pki/ca-trust/source/blacklist/CACert.crt' + trusted_ca_file_remote = '/etc/pki/ca-trust/source/anchors/DigiCert_G5_TLS_ECC_SHA384_2021_CA1.crt' trusted_ca_file_text = '/etc/pki/ca-trust/source/anchors/InCommon.crt' + untrusted_ca_file_remote = if host_inventory['facter']['os']['release']['major'] < '9' + '/etc/pki/ca-trust/source/blacklist/DigiCert_Global_Root_G3.crt' + else + '/etc/pki/ca-trust/source/blocklist/DigiCert_Global_Root_G3.crt' + end + ca_certificates_bundle = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem' when 'Archlinux' - trusted_ca_file_remote = '/etc/ca-certificates/trust-source/anchors/Globalsign_Org_Intermediate.crt' - untrusted_ca_file_remote = '/etc/ca-certificates/trust-source/blacklist/CACert.crt' + trusted_ca_file_remote = '/etc/ca-certificates/trust-source/anchors/DigiCert_G5_TLS_ECC_SHA384_2021_CA1.crt' trusted_ca_file_text = '/etc/ca-certificates/trust-source/anchors/InCommon.crt' + untrusted_ca_file_remote = '/etc/ca-certificates/trust-source/blocklist/DigiCert_Global_Root_G3.crt' + ca_certificates_bundle = '/etc/ca-certificates/extracted/tls-ca-bundle.pem' end describe 'ca_cert::ca' do - context 'with some normal usage' do + context 'add local trusted ca certificates' do let(:manifest) do <<~EOS - include ::ca_cert + ca_cert::ca { 'DigiCert_G5_TLS_ECC_SHA384_2021_CA1': + source => 'https://cacerts.digicert.com/DigiCertG5TLSECCSHA3842021CA1-1.crt.pem', + } - ca_cert::ca { 'Globalsign_Org_Intermediate': - source => 'http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt', - } - - ca_cert::ca { 'InCommon': - ca_text => '-----BEGIN CERTIFICATE----- + ca_cert::ca { 'InCommon': + content => '-----BEGIN CERTIFICATE----- MIIEwzCCA6ugAwIBAgIQf3HB06ImsNKxE/PmgWdkPjANBgkqhkiG9w0BAQUFADBv MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF @@ -54,12 +59,7 @@ kGGmSavOPN/mymTugmU5RZUWukEGAJi6DFZh5MbGhgHPZqkiKQLWPc/EKo2Z3vsJ FJ4O0dXG14HdrSSrrAcF4h1ow3BmX9M= -----END CERTIFICATE-----', - } - - ca_cert::ca { 'CACert': - source => 'http://www.cacert.org/certs/root.crt', - ensure => 'distrusted', - } + } EOS end @@ -73,15 +73,112 @@ it { is_expected.to be_file } end + describe file(ca_certificates_bundle) do + its(:content) do + # DigiCert_G5_TLS_ECC_SHA384_2021_CA1 + is_expected.to match %r{IvZuhDckSAkMNGICMQD4lvGyMGMQirgiqAaMdybUTpcDTLtRQPKiGVZOoSaRtq8o} + # InCommon + is_expected.to match %r{kGGmSavOPN/mymTugmU5RZUWukEGAJi6DFZh5MbGhgHPZqkiKQLWPc/EKo2Z3vsJ} + # DigiCert_Global_Root_G3 + is_expected.to match %r{oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8} + end + end + end + + context 'distrust a os provided ca certificate' do + let(:manifest) do + <<~EOS + ca_cert::ca { 'DigiCert_Global_Root_G3': + source => 'https://cacerts.digicert.com/DigiCertGlobalRootG3.crt.pem', + ensure => 'distrusted', + } + EOS + end + + it_behaves_like 'an idempotent resource' + case host_inventory['facter']['os']['family'] when 'Debian' - describe file(absent_ca_file_remote) do - it { is_expected.not_to be_file } + describe file(ca_certificates_conf) do + its(:content) { is_expected.to match %r{^!.*DigiCert_Global_Root_G3.crt} } end else describe file(untrusted_ca_file_remote) do it { is_expected.to be_file } end end + + describe file(ca_certificates_bundle) do + its(:content) do + # DigiCert_Global_Root_G3 + is_expected.not_to match %r{oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8} + end + end + end + + context 'trust a os provided ca certificate' do + let(:manifest) do + <<~EOS + ca_cert::ca { 'DigiCert_Global_Root_G3': + source => 'https://cacerts.digicert.com/DigiCertGlobalRootG3.crt.pem', + ensure => 'trusted', + } + EOS + end + + it_behaves_like 'an idempotent resource' + + case host_inventory['facter']['os']['family'] + when 'Debian' + describe file(ca_certificates_conf) do + its(:content) { is_expected.to match %r{^[^!].*DigiCert_Global_Root_G3.crt} } + end + else + describe file(untrusted_ca_file_remote) do + it { is_expected.not_to exist } + end + end + + describe file(ca_certificates_bundle) do + its(:content) do + # DigiCert_Global_Root_G3 + is_expected.to match %r{oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8} + end + end + end + + context 'remove local trusted ca certificates' do + let(:manifest) do + <<~EOS + ca_cert::ca { 'DigiCert_G5_TLS_ECC_SHA384_2021_CA1': + ensure => 'absent', + } + + ca_cert::ca { 'InCommon': + ensure => 'absent', + } + EOS + end + + it_behaves_like 'an idempotent resource' + + describe file(trusted_ca_file_remote) do + it { is_expected.not_to exist } + end + + describe file(trusted_ca_file_text) do + it { is_expected.not_to exist } + end + + describe file(ca_certificates_bundle) do + its(:content) do + # DigiCert_G5_TLS_ECC_SHA384_2021_CA1 + is_expected.not_to match %r{IvZuhDckSAkMNGICMQD4lvGyMGMQirgiqAaMdybUTpcDTLtRQPKiGVZOoSaRtq8o} + # InCommon + is_expected.not_to match %r{kGGmSavOPN/mymTugmU5RZUWukEGAJi6DFZh5MbGhgHPZqkiKQLWPc/EKo2Z3vsJ} + # DigiCert_Global_Root_G3 + is_expected.to match %r{oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8} + end + end end end diff --git a/spec/classes/ca_cert_spec.rb b/spec/classes/ca_cert_spec.rb index cb8b461..73d667b 100644 --- a/spec/classes/ca_cert_spec.rb +++ b/spec/classes/ca_cert_spec.rb @@ -9,7 +9,7 @@ trusted_cert_dir = '/etc/pki/ca-trust/source/anchors' update_cmd = 'update-ca-trust extract' when 'Archlinux' - trusted_cert_dir = '/etc/ca-certificates/trust-source/anchors/' + trusted_cert_dir = '/etc/ca-certificates/trust-source/anchors' update_cmd = 'trust extract-compat' when 'Suse' trusted_cert_dir = '/etc/pki/trust/anchors' @@ -63,8 +63,10 @@ it { is_expected.to contain_ca_cert__ca('ca1') } # from ./spec/fixtures/hiera it { is_expected.to contain_ca_cert__ca('ca2') } # from ./spec/fixtures/hiera - it { is_expected.to contain_file('ca1.crt').with_source('puppet:///modules/ca_cert/ca1.pem') } - it { is_expected.to contain_file('ca2.crt').with_source('puppet:///modules/ca_cert/ca2.pem') } + it { is_expected.to contain_archive("#{trusted_cert_dir}/ca1.crt").with_source('puppet:///modules/ca_cert/ca1.pem') } + it { is_expected.to contain_archive("#{trusted_cert_dir}/ca2.crt").with_source('puppet:///modules/ca_cert/ca2.pem') } + it { is_expected.to contain_file("#{trusted_cert_dir}/ca1.crt").with_ensure('file') } + it { is_expected.to contain_file("#{trusted_cert_dir}/ca2.crt").with_ensure('file') } context 'with always_update_certs set to true' do let(:params) { { always_update_certs: true } } diff --git a/spec/defines/ca_spec.rb b/spec/defines/ca_spec.rb index 8703639..ee5d8d3 100644 --- a/spec/defines/ca_spec.rb +++ b/spec/defines/ca_spec.rb @@ -2,7 +2,11 @@ describe 'ca_cert::ca', type: :define do let(:title) { 'Globalsign_Org_Intermediate' } - let(:pre_condition) { 'class {"ca_cert": }' } + let(:pre_condition) do + 'class {"ca_cert": + ca_certs => {}, + }' + end on_supported_os.sort.each do |os, facts| # define os specific defaults @@ -11,10 +15,14 @@ trusted_cert_dir = '/usr/local/share/ca-certificates' when 'RedHat' trusted_cert_dir = '/etc/pki/ca-trust/source/anchors' - distrusted_cert_dir = '/etc/pki/ca-trust/source/blacklist' + distrusted_cert_dir = if facts[:os]['release']['major'] < '9' + '/etc/pki/ca-trust/source/blacklist' + else + '/etc/pki/ca-trust/source/blocklist' + end when 'Archlinux' - trusted_cert_dir = '/etc/ca-certificates/trust-source/anchors/' - distrusted_cert_dir = '/etc/ca-certificates/trust-source/blacklist' + trusted_cert_dir = '/etc/ca-certificates/trust-source/anchors' + distrusted_cert_dir = '/etc/ca-certificates/trust-source/blocklist' when 'Suse' trusted_cert_dir = '/etc/pki/trust/anchors' distrusted_cert_dir = '/etc/pki/trust/blacklist' @@ -29,28 +37,21 @@ let(:facts) { facts } context 'with default values for parameters' do - it { expect { is_expected.to contain_class(:subject) }.to raise_error(Puppet::Error, %r{ca_text is required if source is set to text}) } + it { is_expected.to compile.and_raise_error(%r{Either `source` or `content` is required}) } end - context 'with ca_text set to valid value' do - let(:params) { { ca_text: 'testing' } } - - it { is_expected.to compile } + context 'with content set to valid value' do + let(:params) { { content: 'testing' } } - it { is_expected.to contain_ca_cert__ca('ca1') } - it { is_expected.to contain_ca_cert__ca('ca2') } it { is_expected.to contain_exec('ca_cert_update') } it { is_expected.to contain_file('trusted_certs') } - it { is_expected.to contain_file('ca1.crt') } - it { is_expected.to contain_file('ca2.crt') } it { is_expected.to contain_package('ca-certificates') } it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_file("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { 'ensure' => 'file', 'content' => 'testing', - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", 'owner' => 'root', 'group' => ca_file_group, 'mode' => ca_file_mode, @@ -60,157 +61,102 @@ end end - context 'with source set to valid string "puppet:///testing.crt"' do - let(:params) { { source: 'puppet:///testing.crt' } } - - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'source' => 'puppet:///testing.crt', - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) - end - end - - context 'with source set to valid string "puppet:///testing.pem"' do - let(:params) { { source: 'puppet:///testing.pem' } } - - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'source' => 'puppet:///testing.pem', - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) - end - end - - %w[ftp https http].each do |protocol| - context "with source set to valid string \"#{protocol}://testing.crt\"" do - let(:params) { { source: "#{protocol}://testing.crt" } } + { + 'puppet' => { 'hostname' => nil, 'path' => 'testing.crt' }, + 'file' => { 'hostname' => nil, 'path' => 'testing.pem' }, + 'ftp' => { 'hostname' => 'ftp.myorg.com', 'path' => 'testing.crt' }, + 'http' => { 'hostname' => 'www.myorg.com', 'path' => 'testing.pem' }, + }.each do |key, values| + context "with source set to \"#{key}://#{values['hostname']}/#{values['path']}\"" do + let(:params) { { source: "#{key}://#{values['hostname']}/#{values['path']}" } } it do - is_expected.to contain_archive("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_archive("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { 'ensure' => 'present', - 'source' => "#{protocol}://testing.crt", + 'source' => "#{key}://#{values['hostname']}/#{values['path']}", 'checksum' => nil, 'checksum_type' => nil, 'allow_insecure' => false, + 'before' => ["File[#{trusted_cert_dir}/#{title}.#{ca_file_extension}]"], 'notify' => 'Exec[ca_cert_update]', } ) - end - end - - context "with source set to valid string \"#{protocol}://testing.pem\"" do - let(:params) { { source: "#{protocol}://testing.pem" } } - - it do - is_expected.to contain_archive("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_file("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { - 'ensure' => 'present', - 'source' => "#{protocol}://testing.pem", - 'checksum' => nil, - 'checksum_type' => nil, - 'allow_insecure' => false, - 'notify' => 'Exec[ca_cert_update]', + 'ensure' => 'file', + 'owner' => 'root', + 'group' => ca_file_group, + 'mode' => ca_file_mode, + 'notify' => 'Exec[ca_cert_update]', } ) end end end - context 'with source set to valid string "file:/testing.crt"' do - let(:params) { { source: 'file:/testing.crt' } } + context 'with ensure set to "trusted"' do + let(:params) { { ensure: 'trusted' } } - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'source' => '/testing.crt', - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) - end - end + it { is_expected.not_to contain_archive("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } - context 'with source set to valid string "file:/testing.pem"' do - let(:params) { { source: 'file:/testing.pem' } } + case facts[:os]['family'] + when 'Debian' + it { is_expected.to contain_exec("trust ca #{title}.#{ca_file_extension}") } + it { is_expected.not_to contain_file("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } + else + it { is_expected.not_to contain_exec("#{title}.#{ca_file_extension}") } - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'source' => '/testing.pem', - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) + it do + is_expected.to contain_file("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( + { + 'ensure' => 'absent', + 'notify' => 'Exec[ca_cert_update]', + } + ) + end end end - context 'with ensure set to valid string "present"' do - let(:params) { { ensure: 'present' } } + context 'with ensure set to "distrusted" and no source or content' do + let(:params) { { ensure: 'distrusted' } } - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'content' => nil, - 'path' => "#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) + case facts[:os]['family'] + when 'Debian' + it { is_expected.to contain_exec("distrust ca #{title}.#{ca_file_extension}") } + it { is_expected.not_to contain_archive("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } + it { is_expected.not_to contain_file("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } + else + it { is_expected.to compile.and_raise_error(%r{Either `source` or `content` is required}) } end end - context 'with ensure set to valid string "distrusted"' do - let(:params) { { ensure: 'distrusted' } } + context 'with ensure set to "distrusted" and valid source' do + let(:params) { { ensure: 'distrusted', source: 'puppet:///testing.crt' } } - it { expect { is_expected.to contain_class(:subject) }.to raise_error(Puppet::Error, %r{ca_text is required if source is set to text}) } - end - - context 'with ensure set to valid string "distrusted" when source is "file:/dummy.pem"' do - let(:params) { { ensure: 'distrusted', source: 'file:/dummy.pem' } } + case facts[:os]['family'] + when 'Debian' + it { is_expected.to contain_exec("distrust ca #{title}.#{ca_file_extension}") } + it { is_expected.not_to contain_archive("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } + it { is_expected.not_to contain_file("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}") } + else + it { is_expected.not_to contain_exec("distrust ca #{title}.#{ca_file_extension}") } - if facts[:os]['family'] == 'Debian' it do - is_expected.to contain_file("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_archive("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { - 'ensure' => 'absent', - 'notify' => 'Exec[ca_cert_update]', + 'ensure' => 'present', + 'source' => 'puppet:///testing.crt', + 'checksum' => nil, + 'checksum_type' => nil, + 'allow_insecure' => false, + 'before' => ["File[#{distrusted_cert_dir}/#{title}.#{ca_file_extension}]"], + 'notify' => 'Exec[ca_cert_update]', } ) - end - else - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_file("#{distrusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { 'ensure' => 'file', - 'source' => '/dummy.pem', - 'path' => "#{distrusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", 'owner' => 'root', 'group' => ca_file_group, 'mode' => ca_file_mode, @@ -221,40 +167,11 @@ end end - context 'with ensure set to valid string "distrusted" when ca_text is "testing"' do - let(:params) { { ensure: 'distrusted', ca_text: 'testing' } } - - if facts[:os]['family'] == 'Debian' - it do - is_expected.to contain_file("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'absent', - 'notify' => 'Exec[ca_cert_update]', - } - ) - end - else - it do - is_expected.to contain_file("Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( - { - 'ensure' => 'file', - 'content' => 'testing', - 'path' => "#{distrusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}", - 'owner' => 'root', - 'group' => ca_file_group, - 'mode' => ca_file_mode, - 'notify' => 'Exec[ca_cert_update]', - } - ) - end - end - end - - context 'with ensure set to valid string "absent"' do + context 'with ensure set to "absent"' do let(:params) { { ensure: 'absent' } } it do - is_expected.to contain_file("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").only_with( + is_expected.to contain_file("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").only_with( { 'ensure' => 'absent', 'notify' => 'Exec[ca_cert_update]', @@ -263,24 +180,22 @@ end end - %w[ftp https http].each do |protocol| - context "with verify_https_cert set to valid false when source set to valid string \"#{protocol}://testing.pem\"" do - let(:params) { { verify_https_cert: false, source: "#{protocol}://testing.pem" } } + context 'with allow_insecure_source set to true' do + let(:params) { { allow_insecure_source: true, source: 'https://www.myorg.com/testing.pem' } } - it { is_expected.to contain_archive("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").with_allow_insecure(true) } - end + it { is_expected.to contain_archive("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").with_allow_insecure(true) } + end - context "with checksum set to valid value when source set to valid string \"#{protocol}://testing.pem\"" do - let(:params) { { checksum: 'testing', source: "#{protocol}://testing.pem" } } + context 'with checksum' do + let(:params) { { checksum: 'testing', source: 'https://www.myorg.com/testing.pem' } } - it { is_expected.to contain_archive("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").with_checksum('testing') } - end + it { is_expected.to contain_archive("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").with_checksum('testing') } + end - context "with checksum_type set to valid value when source set to valid string \"#{protocol}://testing.pem\"" do - let(:params) { { checksum_type: 'testing', source: "#{protocol}://testing.pem" } } + context 'with checksum_type' do + let(:params) { { checksum_type: 'testing', source: 'https://www.myorg.com/testing.pem' } } - it { is_expected.to contain_archive("#{trusted_cert_dir}/Globalsign_Org_Intermediate.#{ca_file_extension}").with_checksum_type('testing') } - end + it { is_expected.to contain_archive("#{trusted_cert_dir}/#{title}.#{ca_file_extension}").with_checksum_type('testing') } end end end