diff --git a/files/certmonger-memcached-refresh.sh b/files/certmonger-memcached-refresh.sh new file mode 100644 index 000000000..ce105697a --- /dev/null +++ b/files/certmonger-memcached-refresh.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +container_cli=$(hiera -c /etc/puppet/hiera.yaml container_cli podman) +container_name=$($container_cli ps --format="{{.Names}}" | grep metrics_qdr) + +service_certificate="$(hiera -c /etc/puppet/hiera.yaml tripleo::profile::base::memcached::certificate_specs.service_certificate)" +service_key="$(hiera -c /etc/puppet/hiera.yaml tripleo::profile::base::memcached::certificate_specs.service_key)" + +# Copy the new cert and key from the mount-point to the real path +$container_cli exec "$container_name" cp "/var/lib/kolla/config_files/src-tls$service_certificate" "$service_certificate" +$container_cli exec "$container_name" cp "/var/lib/kolla/config_files/src-tls$service_key" "$service_key" + +# Set appropriate permissions +$container_cli exec "$container_name" chown qdrouterd:qdrouterd "$service_certificate" +$container_cli exec "$container_name" chown qdrouterd:qdrouterd "$service_key" + +# Send refresh_certs command to memcached +memcached_ip="$(hiera -c /etc/puppet/hiera.yaml memcached::listen.0 127.0.0.1)" +memcached_port="$(hiera -c /etc/puppet/hiera.yaml memcached::tcp_port 11211)" +echo refresh_certs | openssl s_client -connect $memcached_ip:$memcached_port diff --git a/manifests/certmonger/memcached.pp b/manifests/certmonger/memcached.pp new file mode 100644 index 000000000..f239141a5 --- /dev/null +++ b/manifests/certmonger/memcached.pp @@ -0,0 +1,79 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: tripleo::certmonger::memcached +# +# Request a certificate for Memcached and do the necessary setup. +# +# === Parameters +# +# [*hostname*] +# The hostname of the node. this will be set in the CN of the certificate. +# +# [*service_certificate*] +# The path to the certificate that will be used for TLS in this service. +# +# [*service_key*] +# The path to the key that will be used for TLS in this service. +# +# [*certmonger_ca*] +# (Optional) The CA that certmonger will use to generate the certificates. +# Defaults to hiera('certmonger_ca', 'local'). +# +# [*postsave_cmd*] +# (Optional) Specifies the command to execute after requesting a certificate. +# If nothing is given, it will default to: "systemctl restart ${service name}" +# Defaults to undef. +# +# [*principal*] +# (Optional) The service principal that is set for the service in kerberos. +# Defaults to undef +# +class tripleo::certmonger::memcached ( + $hostname, + $service_certificate, + $service_key, + $certmonger_ca = hiera('certmonger_ca', 'local'), + $postsave_cmd = '/usr/bin/certmonger-memcached-refresh.sh', + $principal = undef, +) { + include ::certmonger + + ensure_resource('file', '/usr/bin/certmonger-memcached-refresh.sh', { + source => 'puppet:///modules/tripleo/certmonger-memcached-refresh.sh', + mode => '0700', + seltype => 'bin_t', + notify => Service['certmonger'] + }) + + certmonger_certificate { 'memcached' : + ensure => 'present', + certfile => $service_certificate, + keyfile => $service_key, + hostname => $hostname, + dnsname => $hostname, + principal => $principal, + postsave_cmd => $postsave_cmd, + ca => $certmonger_ca, + wait => true, + require => Class['::certmonger'], + } + + file { $service_certificate : + require => Certmonger_certificate['memcached'], + } + file { $service_key : + require => Certmonger_certificate['memcached'], + } +} diff --git a/manifests/profile/base/certmonger_user.pp b/manifests/profile/base/certmonger_user.pp index 302902879..f7a228ecf 100644 --- a/manifests/profile/base/certmonger_user.pp +++ b/manifests/profile/base/certmonger_user.pp @@ -92,6 +92,11 @@ # it will create. # Defaults to hiera('tripleo::profile::base::database::mysql::certificate_specs', {}). # +# [*memcached_certificate_specs*] +# (Optional) The specifications to give to certmonger for the certificate(s) +# it will create. +# Defaults to hiera('tripleo::profile::base::memcached::certificate_specs', {}). +# # [*rabbitmq_certificate_specs*] # (Optional) The specifications to give to certmonger for the certificate(s) # it will create. @@ -197,6 +202,7 @@ class tripleo::profile::base::certmonger_user ( $qemu_postsave_cmd = undef, $qdr_certificate_specs = hiera('tripleo::profile::base::metrics::qdr::certificate_specs', {}), $mysql_certificate_specs = hiera('tripleo::profile::base::database::mysql::certificate_specs', {}), + $memcached_certificate_specs = hiera('tripleo::profile::base::memcached::certificate_specs', {}), $rabbitmq_certificate_specs = hiera('tripleo::profile::base::rabbitmq::certificate_specs', {}), $redis_certificate_specs = hiera('redis_certificate_specs', {}), $etcd_certificate_specs = hiera('tripleo::profile::base::etcd::certificate_specs', {}), @@ -278,6 +284,9 @@ class tripleo::profile::base::certmonger_user ( unless empty($qdr_certificate_specs) { ensure_resource('class', 'tripleo::certmonger::metrics_qdr', $qdr_certificate_specs) } + unless empty($memcached_certificate_specs) { + ensure_resource('class', 'tripleo::certmonger::memcached', $memcached_certificate_specs) + } unless empty($mysql_certificate_specs) { ensure_resource('class', 'tripleo::certmonger::mysql', $mysql_certificate_specs) } diff --git a/manifests/profile/base/memcached.pp b/manifests/profile/base/memcached.pp index e33999a12..bdf614ff2 100644 --- a/manifests/profile/base/memcached.pp +++ b/manifests/profile/base/memcached.pp @@ -18,15 +18,46 @@ # # === Parameters # +# [*enable_internal_memcached_tls*] +# (Optional) Whether TLS in the internal network is enabled or not for +# Memcached servers. +# Defaults to undef +# +# [*certificate_specs*] +# (Optional) The specifications to give to certmonger for the certificate +# it will create. Note that the certificate nickname must be 'memcached' in +# the case of this service. +# Example with hiera: +# tripleo::profile::base::memcached::certificate_specs: +# hostname: +# service_certificate: +# service_key: +# principal: "memcached/" +# Defaults to {}. +# # [*step*] # (Optional) The current step in deployment. See tripleo-heat-templates # for more details. # Defaults to hiera('step') # class tripleo::profile::base::memcached ( - $step = Integer(hiera('step')), + $enable_internal_memcached_tls = false, + $certificate_specs = {}, + $step = Integer(hiera('step')), ) { if $step >= 1 { - include ::memcached + if $enable_internal_memcached_tls { + $tls_cert_chain = $certificate_specs['service_certificate'] + $tls_key = $certificate_specs['service_key'] + } else { + $tls_cert_chain = undef + $tls_key = undef + } + + class { '::memcached': + use_tls => $enable_internal_memcached_tls, + tls_cert_chain => $tls_cert_chain, + tls_key => $tls_key + } } } diff --git a/spec/classes/tripleo_certmonger_memcached_spec.rb b/spec/classes/tripleo_certmonger_memcached_spec.rb new file mode 100644 index 000000000..a53c1d9c2 --- /dev/null +++ b/spec/classes/tripleo_certmonger_memcached_spec.rb @@ -0,0 +1,60 @@ +# +# Copyright (C) 2020 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for tripleo +# + +require 'spec_helper' + +describe 'tripleo::certmonger::memcached' do + + shared_examples_for 'tripleo::certmonger::memcached' do + let :params do + { + :hostname => 'localhost', + :service_certificate => '/etc/pki/cert.crt', + :service_key => '/etc/pki/key.pem', + } + end + + it 'should include the base for using certmonger' do + is_expected.to contain_class('certmonger') + end + + it 'should request a certificate' do + is_expected.to contain_certmonger_certificate('memcached').with( + :ensure => 'present', + :certfile => '/etc/pki/cert.crt', + :keyfile => '/etc/pki/key.pem', + :hostname => 'localhost', + :dnsname => 'localhost', + :ca => 'local', + :wait => true, + ) + is_expected.to contain_file('/etc/pki/cert.crt') + is_expected.to contain_file('/etc/pki/key.pem') + end + end + + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge({}) + end + + it_behaves_like 'tripleo::certmonger::memcached' + end + end +end diff --git a/spec/classes/tripleo_profile_base_memcached_spec.rb b/spec/classes/tripleo_profile_base_memcached_spec.rb new file mode 100644 index 000000000..bc58e4efc --- /dev/null +++ b/spec/classes/tripleo_profile_base_memcached_spec.rb @@ -0,0 +1,76 @@ +# +# Copyright (C) 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'tripleo::profile::base::memcached' do + shared_examples_for 'tripleo::profile::base::memcached' do + context 'with step 0' do + let(:params) { { + :step => 0, + } } + + it { + is_expected.to contain_class('tripleo::profile::base::memcached') + is_expected.to_not contain_class('memcached') + } + end + + context 'with step 1' do + let(:params) { { + :step => 1, + } } + + it { + is_expected.to contain_class('tripleo::profile::base::memcached') + is_expected.to contain_class('memcached').with( + :use_tls => false, + :tls_cert_chain => nil, + :tls_key => nil + ) + } + end + + context 'with step 1 and tls enabled' do + let(:params) { { + :step => 1, + :enable_internal_memcached_tls => true, + :certificate_specs => { + 'service_certificate' => '/etc/pki/cert.crt', + 'service_key' => '/etc/pki/key.pem'} + } } + + it { + is_expected.to contain_class('tripleo::profile::base::memcached') + is_expected.to contain_class('memcached').with( + :use_tls => true, + :tls_cert_chain => '/etc/pki/cert.crt', + :tls_key => '/etc/pki/key.pem' + ) + } + end + end + + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge({ :hostname => 'node.example.com' }) + end + + it_behaves_like 'tripleo::profile::base::memcached' + end + end +end