diff --git a/lib/puppet/provider/ca/katello_ssl_tool.rb b/lib/puppet/provider/ca/katello_ssl_tool.rb index 62beca22..7cbb842c 100644 --- a/lib/puppet/provider/ca/katello_ssl_tool.rb +++ b/lib/puppet/provider/ca/katello_ssl_tool.rb @@ -6,14 +6,17 @@ protected def generate! - if existing_pubkey + extra_args = [] + extra_args += [ '--other-ca-certs', resource[:other_certs].join(',') ] unless resource[:other_certs].empty? + if existing_pubkey || resource[:other_certs].any? FileUtils.mkdir_p(build_path) - FileUtils.cp(existing_pubkey, build_path(File.basename(pubkey))) + FileUtils.cp(existing_pubkey, build_path(File.basename(pubkey))) if existing_pubkey katello_ssl_tool('--gen-ca', '--ca-cert-dir', target_path('certs'), '--ca-cert', File.basename(pubkey), '--ca-cert-rpm', rpmfile_base_name, - '--rpm-only') + '--rpm-only', + extra_args) else katello_ssl_tool('--gen-ca', '-p', "file:#{resource[:password_file]}", @@ -23,6 +26,7 @@ def generate! '--ca-cert', File.basename(pubkey), '--ca-key', File.basename(privkey), '--ca-cert-rpm', rpmfile_base_name, + extra_args, *common_args) end diff --git a/lib/puppet/provider/katello_ssl_tool.rb b/lib/puppet/provider/katello_ssl_tool.rb index ee689cfa..c3012eae 100644 --- a/lib/puppet/provider/katello_ssl_tool.rb +++ b/lib/puppet/provider/katello_ssl_tool.rb @@ -51,6 +51,16 @@ def generate? return false unless resource[:generate] return true if resource[:regenerate] return true if File.exists?(update_file) + return true if needs_generate? + end + + def needs_generate? + if resource.class == Puppet::Type::Ca && resource[:other_certs].any? + default_ca = IO.read(pubkey) + resource[:other_certs].each do |cert| + return true unless default_ca.include? IO.read(cert) + end + end return files_to_generate.any? { |file| ! File.exist?(file) } end diff --git a/lib/puppet/type/ca.rb b/lib/puppet/type/ca.rb index 49193616..8254d078 100644 --- a/lib/puppet/type/ca.rb +++ b/lib/puppet/type/ca.rb @@ -5,4 +5,20 @@ instance_eval(&Certs::CERT_COMMON_PARAMS) + newparam(:other_certs, :array_matching => :all) do + validate do |value| + unless value.is_a?(Array) || value.is_a?(String) || value.is_a?(Symbol) + raise Puppet::Error, "Puppet::Type::Ca: other_certs parameter must be an array or a string, + got #{value.class.name}." + end + end + + munge do |value| + return [value] if value.is_a?(String) || value.is_a?(Symbol) + value + end + + defaultto Array.new + end + end diff --git a/manifests/ca.pp b/manifests/ca.pp index fe9d909b..20125fd2 100644 --- a/manifests/ca.pp +++ b/manifests/ca.pp @@ -21,6 +21,7 @@ $ca_cert_stripped = $certs::ca_cert_stripped, $ca_key_password = $certs::ca_key_password, $ca_key_password_file = $certs::ca_key_password_file, + $other_default_ca_certs = $::certs::other_default_ca_certs, ) { file { $ca_key_password_file: @@ -42,6 +43,7 @@ generate => $generate, deploy => $deploy, password_file => $ca_key_password_file, + other_certs => $other_default_ca_certs, } $default_ca = Ca[$default_ca_name] diff --git a/manifests/init.pp b/manifests/init.pp index 6b006705..732210b2 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -67,6 +67,9 @@ # # $group:: The group who should own the certs # +# $other_default_ca_certs:: Certificates to be included with ours, Generally this would be +# the Public CA certificates from the other nodes in a Katello cluster +# # $default_ca_name:: The name of the default CA # # $server_ca_name:: The name of the server CA (used for https) @@ -98,6 +101,7 @@ String $default_ca_name = $certs::params::default_ca_name, String $server_ca_name = $certs::params::server_ca_name, Optional[Stdlib::Absolutepath] $tar_file = $certs::params::tar_file, + Array[Stdlib::Absolutepath] $other_default_ca_certs = $::certs::params::other_default_ca_certs, ) inherits certs::params { if $server_cert { diff --git a/manifests/params.pp b/manifests/params.pp index ffb543c9..70ff1bea 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -16,6 +16,7 @@ $regenerate_ca = false $deploy = true + $other_default_ca_certs = [] $default_ca_name = 'katello-default-ca' $server_ca_name = 'katello-server-ca' diff --git a/spec/acceptance/certs_ca_spec.rb b/spec/acceptance/certs_ca_spec.rb new file mode 100644 index 00000000..a48cf11b --- /dev/null +++ b/spec/acceptance/certs_ca_spec.rb @@ -0,0 +1,141 @@ +require 'spec_helper_acceptance' + +describe 'certs with default params' do + context 'with default params' do + let(:pp) do + <<-EOS + $repo = 'latest' + $dist = 'el7' + + package { 'epel-release': + ensure => installed, + } + + yumrepo { 'katello': + descr => 'Katello latest', + baseurl => "https://fedorapeople.org/groups/katello/releases/yum/${repo}/katello/${dist}/\\$basearch/", + gpgkey => 'https://raw.githubusercontent.com/Katello/katello-packaging/master/repos/RPM-GPG-KEY-katello-2015', + gpgcheck => '0', + enabled => '1', + } + class { '::certs':} + EOS + end + + it_behaves_like 'a idempotent resource' + + describe package('katello-certs-tools') do + it { is_expected.to be_installed } + end + + describe x509_certificate('/etc/pki/katello-certs-tools/certs/katello-default-ca.crt') do + it { should be_certificate } + it { should be_valid } + it { should have_purpose 'SSL server CA' } + its(:issuer) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + its(:subject) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + end + + describe x509_certificate('/etc/pki/katello-certs-tools/certs/katello-server-ca.crt') do + it { should be_certificate } + it { should be_valid } + it { should have_purpose 'SSL server CA' } + its(:issuer) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + its(:subject) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + end + end + + context 'with custom server certs' do + before(:all) do + beforepp = <<-EOS + # Mark server-ca for update + file { '/root/ssl-build/katello-server-ca.update': + ensure => file, + } + + Exec { + path => ['/usr/bin'], + } + + file { '/root/custom_cert': + ensure => directory, + } ~> + exec { 'Create CA key': + cwd => "/root/custom_cert", + command => "openssl genrsa -out ca.key 2048", + creates => "/root/custom_cert/ca.key", + } ~> + exec { 'Create CA certficates': + cwd => "/root/custom_cert", + command => 'openssl req -new -x509 -key ca.key -out ca.crt -nodes -x509 -subj "/C=US/ST=North Carolina/L=Raleigh/O=CustomKatelloCA/CN=www.custom-katello-ca.example.com"', + creates => "/root/custom_cert/ca.crt", + } ~> + exec { 'Create custom key': + cwd => "/root/custom_cert", + command => "openssl genrsa -out katello.example.com.key 2048", + creates => "/root/custom_cert/katello.example.com.key", + } ~> + exec { 'Create CSR': + cwd => "/root/custom_cert", + command => 'openssl req -new -key katello.example.com.key -out katello.example.com.csr -nodes -subj "/C=US/ST=North Carolina/L=Raleigh/O=Katello/CN=www.katello.example.com"', + creates => "/root/custom_cert/katello.example.com.csr", + } ~> + exec { 'Sign CSR': + cwd => "/root/custom_cert", + command => 'openssl x509 -req -in katello.example.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out katello.example.com.crt', + creates => "/root/custom_cert/katello.example.com.crt", + } + EOS + apply_manifest(beforepp) + end + + let(:pp) do + <<-EOS + $repo = 'latest' + $dist = 'el7' + + package { 'epel-release': + ensure => installed, + } + + yumrepo { 'katello': + descr => 'Katello latest', + baseurl => "https://fedorapeople.org/groups/katello/releases/yum/${repo}/katello/${dist}/\\$basearch/", + gpgkey => 'https://raw.githubusercontent.com/Katello/katello-packaging/master/repos/RPM-GPG-KEY-katello-2015', + gpgcheck => '0', + enabled => '1', + } + + class { '::certs': + server_cert => "/root/custom_cert/katello.example.com.crt", + server_ca_cert => "/root/custom_cert/ca.crt", + server_key => "/root/custom_cert/katello.example.com.key", + server_cert_req => "/root/custom_cert/katello.example.com.csr", + } + EOS + end + + it_behaves_like 'a idempotent resource' + + describe package('katello-certs-tools') do + it { is_expected.to be_installed } + end + + describe x509_certificate('/etc/pki/katello-certs-tools/certs/katello-default-ca.crt') do + it { should be_certificate } + it { should be_valid } + it { should have_purpose 'SSL server CA' } + its(:issuer) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + its(:subject) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=Katello/OU=SomeOrgUnit/CN=#{fact('fqdn')}" } + end + + + describe x509_certificate('/etc/pki/katello-certs-tools/certs/katello-server-ca.crt') do + it { should be_certificate } + it { should be_valid } + it { should have_purpose 'SSL server CA' } + its(:issuer) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=CustomKatelloCA/CN=www.custom-katello-ca.example.com" } + its(:subject) { should eq "/C=US/ST=North Carolina/L=Raleigh/O=CustomKatelloCA/CN=www.custom-katello-ca.example.com" } + end + end +end diff --git a/spec/classes/certs_ca_spec.rb b/spec/classes/certs_ca_spec.rb new file mode 100644 index 00000000..4bb5b4e7 --- /dev/null +++ b/spec/classes/certs_ca_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe 'certs::ca' do + let :facts do + on_supported_os['redhat-7-x86_64'] + end + + context 'without params ' do + let :pre_condition do + "class {'certs':}" + end + + describe 'with ca set' do + it { should contain_ca('katello-default-ca').with({ :other_certs => [] }) } + end + end + + context 'with params' do + let :pre_condition do + "class {'certs': other_default_ca_certs => ['/tmp/other-default-cert.crt', '/tmp/another-default-cert.crt']}" + end + + describe 'with ca set' do + it { should contain_ca('katello-default-ca').with({ :other_certs => ['/tmp/other-default-cert.crt', '/tmp/another-default-cert.crt'] }) } + end + end +end