From d905ed08052ca5dc78b5f7f56f731394f19958ed Mon Sep 17 00:00:00 2001 From: Martin André Date: Wed, 23 Aug 2017 12:44:42 +0200 Subject: Use TLS proxy for Redis' internal TLS This uses the tls_proxy resource in front of the Redis server when internal TLS is enabled. bp tls-via-certmonger Co-Authored-By: Juan Antonio Osorio Robles Change-Id: Ia50933da9e59268b17f56db34d01dcc6b6c38147 (cherry picked from commit 2d1d7875aa6f0b68005c84189627bc0716a7693f) --- manifests/certmonger/redis.pp | 72 ++++++++++++++++++++++ manifests/haproxy.pp | 15 ++++- manifests/profile/base/aodh/evaluator.pp | 14 ++++- manifests/profile/base/ceilometer/agent/central.pp | 15 ++++- manifests/profile/base/ceilometer/agent/polling.pp | 13 +++- manifests/profile/base/certmonger_user.pp | 9 +++ manifests/profile/base/database/redis.pp | 71 ++++++++++++++++++++- manifests/profile/base/gnocchi/api.pp | 6 +- manifests/profile/pacemaker/database/redis.pp | 65 +++++++++++++++++++ 9 files changed, 267 insertions(+), 13 deletions(-) create mode 100644 manifests/certmonger/redis.pp diff --git a/manifests/certmonger/redis.pp b/manifests/certmonger/redis.pp new file mode 100644 index 0000000..1b3b119 --- /dev/null +++ b/manifests/certmonger/redis.pp @@ -0,0 +1,72 @@ +# Copyright 2017 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::redis +# +# Request a certificate for RabbitMQ 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::redis ( + $hostname, + $service_certificate, + $service_key, + $certmonger_ca = hiera('certmonger_ca', 'local'), + $postsave_cmd = undef, + $principal = undef, +) { + include ::certmonger + + certmonger_certificate { 'redis' : + 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['redis'], + } + file { $service_key : + require => Certmonger_certificate['redis'], + } +} diff --git a/manifests/haproxy.pp b/manifests/haproxy.pp index e41f0e6..9386036 100644 --- a/manifests/haproxy.pp +++ b/manifests/haproxy.pp @@ -1373,11 +1373,19 @@ class tripleo::haproxy ( } if $redis { + if $enable_internal_tls { + $redis_tcp_check_ssl_options = ['connect ssl'] + $redis_ssl_member_options = ['check-ssl', "ca-file ${ca_bundle}"] + } else { + $redis_tcp_check_ssl_options = [] + $redis_ssl_member_options = [] + } if $redis_password { - $redis_tcp_check_options = ["send AUTH\\ ${redis_password}\\r\\n"] + $redis_tcp_check_password_options = ["send AUTH\\ ${redis_password}\\r\\n"] } else { - $redis_tcp_check_options = [] + $redis_tcp_check_password_options = [] } + $redis_tcp_check_options = union($redis_tcp_check_ssl_options, $redis_tcp_check_password_options) haproxy::listen { 'redis': bind => $redis_bind_opts, options => { @@ -1397,7 +1405,8 @@ class tripleo::haproxy ( ports => '6379', ipaddresses => hiera('redis_node_ips', $controller_hosts_real), server_names => hiera('redis_node_names', $controller_hosts_names_real), - options => $haproxy_member_options, + options => union($haproxy_member_options, $redis_ssl_member_options), + verifyhost => false, } if $manage_firewall { include ::tripleo::firewall diff --git a/manifests/profile/base/aodh/evaluator.pp b/manifests/profile/base/aodh/evaluator.pp index 1b25b37..9b3462f 100644 --- a/manifests/profile/base/aodh/evaluator.pp +++ b/manifests/profile/base/aodh/evaluator.pp @@ -18,20 +18,30 @@ # # === Parameters # +# [*enable_internal_tls*] +# (Optional) Whether TLS in the internal network is enabled or not. +# Defaults to hiera('enable_internal_tls', false) +# # [*step*] # (Optional) The current step in deployment. See tripleo-heat-templates # for more details. # Defaults to hiera('step') # class tripleo::profile::base::aodh::evaluator ( - $step = Integer(hiera('step')), + $enable_internal_tls = hiera('enable_internal_tls', false), + $step = Integer(hiera('step')), ) { include ::tripleo::profile::base::aodh + if $enable_internal_tls { + $tls_query_param = '?ssl=true' + } else { + $tls_query_param = '' + } if $step >= 4 { class { '::aodh::evaluator': - coordination_url => join(['redis://:', hiera('aodh_redis_password'), '@', normalize_ip_for_uri(hiera('redis_vip')), ':6379/']), + coordination_url => join(['redis://:', hiera('aodh_redis_password'), '@', normalize_ip_for_uri(hiera('redis_vip')), ':6379/', $tls_query_param]), } } diff --git a/manifests/profile/base/ceilometer/agent/central.pp b/manifests/profile/base/ceilometer/agent/central.pp index b8f5d07..955917c 100644 --- a/manifests/profile/base/ceilometer/agent/central.pp +++ b/manifests/profile/base/ceilometer/agent/central.pp @@ -18,20 +18,31 @@ # # === Parameters # +# [*enable_internal_tls*] +# (Optional) Whether TLS in the internal network is enabled or not. +# Defaults to hiera('enable_internal_tls', false) +# # [*step*] # (Optional) The current step in deployment. See tripleo-heat-templates # for more details. # Defaults to hiera('step') # class tripleo::profile::base::ceilometer::agent::central ( - $step = Integer(hiera('step')), + $enable_internal_tls = hiera('enable_internal_tls', false), + $step = Integer(hiera('step')), ) { include ::tripleo::profile::base::ceilometer + if $enable_internal_tls { + $tls_query_param = '?ssl=true' + } else { + $tls_query_param = '' + } + if $step >= 4 { include ::ceilometer::agent::auth class { '::ceilometer::agent::central': - coordination_url => join(['redis://:', hiera('ceilometer_redis_password'), '@', normalize_ip_for_uri(hiera('redis_vip')), ':6379/']), + coordination_url => join(['redis://:', hiera('ceilometer_redis_password'), '@', normalize_ip_for_uri(hiera('redis_vip')), ':6379/', $tls_query_param]), } } diff --git a/manifests/profile/base/ceilometer/agent/polling.pp b/manifests/profile/base/ceilometer/agent/polling.pp index 84f5e46..043b5cd 100644 --- a/manifests/profile/base/ceilometer/agent/polling.pp +++ b/manifests/profile/base/ceilometer/agent/polling.pp @@ -26,6 +26,10 @@ # (Optional) Use compute namespace for polling agent. # Defaults to false. # +# [*enable_internal_tls*] +# (Optional) Whether TLS in the internal network is enabled or not. +# Defaults to hiera('enable_internal_tls', false) +# # [*ipmi_namespace*] # (Optional) Use ipmi namespace for polling agent. # Defaults to false. @@ -44,6 +48,7 @@ class tripleo::profile::base::ceilometer::agent::polling ( $central_namespace = hiera('central_namespace', false), $compute_namespace = hiera('compute_namespace', false), + $enable_internal_tls = hiera('enable_internal_tls', false), $ipmi_namespace = hiera('ipmi_namespace', false), $ceilometer_redis_password = hiera('ceilometer_redis_password', undef), $redis_vip = hiera('redis_vip', undef), @@ -55,13 +60,19 @@ class tripleo::profile::base::ceilometer::agent::polling ( include ::tripleo::profile::base::ceilometer::upgrade } + if $enable_internal_tls { + $tls_query_param = '?ssl=true' + } else { + $tls_query_param = '' + } + if $step >= 4 { include ::ceilometer::agent::auth class { '::ceilometer::agent::polling': central_namespace => $central_namespace, compute_namespace => $compute_namespace, ipmi_namespace => $ipmi_namespace, - coordination_url => join(['redis://:', $ceilometer_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/']), + coordination_url => join(['redis://:', $ceilometer_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/', $tls_query_param]), } } } diff --git a/manifests/profile/base/certmonger_user.pp b/manifests/profile/base/certmonger_user.pp index cc29cd5..54d9e15 100644 --- a/manifests/profile/base/certmonger_user.pp +++ b/manifests/profile/base/certmonger_user.pp @@ -78,6 +78,11 @@ # it will create. # Defaults to hiera('tripleo::profile::base::rabbitmq::certificate_specs', {}). # +# [*redis_certificate_specs*] +# (Optional) The specifications to give to certmonger for the certificate(s) +# it will create. +# Defaults to hiera('redis_certificate_specs', {}). +# # [*etcd_certificate_specs*] # (Optional) The specifications to give to certmonger for the certificate(s) # it will create. @@ -93,6 +98,7 @@ class tripleo::profile::base::certmonger_user ( $mongodb_certificate_specs = hiera('mongodb_certificate_specs',{}), $mysql_certificate_specs = hiera('tripleo::profile::base::database::mysql::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', {}), ) { unless empty($haproxy_certificates_specs) { @@ -137,6 +143,9 @@ class tripleo::profile::base::certmonger_user ( unless empty($rabbitmq_certificate_specs) { ensure_resource('class', 'tripleo::certmonger::rabbitmq', $rabbitmq_certificate_specs) } + unless empty($redis_certificate_specs) { + ensure_resource('class', 'tripleo::certmonger::redis', $redis_certificate_specs) + } unless empty($etcd_certificate_specs) { ensure_resource('class', 'tripleo::certmonger::etcd', $etcd_certificate_specs) } diff --git a/manifests/profile/base/database/redis.pp b/manifests/profile/base/database/redis.pp index e357359..8d4ed94 100644 --- a/manifests/profile/base/database/redis.pp +++ b/manifests/profile/base/database/redis.pp @@ -22,6 +22,26 @@ # (Optional) Hostname of Redis master # Defaults to hiera('bootstrap_nodeid') # +# [*certificate_specs*] +# (Optional) The specifications to give to certmonger for the certificate(s) +# it will create. +# Example with hiera: +# redis_certificate_specs: +# hostname: +# service_certificate: +# service_key: +# principal: "haproxy/" +# Defaults to hiera('redis_certificate_specs', {}). +# +# [*enable_internal_tls*] +# (Optional) Whether TLS in the internal network is enabled or not. +# Defaults to hiera('enable_internal_tls', false) +# +# [*redis_network*] +# (Optional) The network name where the redis endpoint is listening on. +# This is set by t-h-t. +# Defaults to hiera('redis_network', undef) +# # [*redis_node_ips*] # (Optional) List of Redis node ips # Defaults to hiera('redis_node_ips') @@ -31,12 +51,57 @@ # for more details. # Defaults to hiera('step') # +# [*tls_proxy_bind_ip*] +# IP on which the TLS proxy will listen on. Required only if +# enable_internal_tls is set. +# Defaults to undef +# +# [*tls_proxy_fqdn*] +# fqdn on which the tls proxy will listen on. required only used if +# enable_internal_tls is set. +# defaults to undef +# +# [*tls_proxy_port*] +# port on which the tls proxy will listen on. Only used if +# enable_internal_tls is set. +# defaults to 6379 +# class tripleo::profile::base::database::redis ( - $bootstrap_nodeid = hiera('bootstrap_nodeid'), - $redis_node_ips = hiera('redis_node_ips'), - $step = Integer(hiera('step')), + $bootstrap_nodeid = hiera('bootstrap_nodeid'), + $certificate_specs = hiera('redis_certificate_specs', {}), + $enable_internal_tls = hiera('enable_internal_tls', false), + $redis_network = hiera('redis_network', undef), + $redis_node_ips = hiera('redis_node_ips'), + $step = Integer(hiera('step')), + $tls_proxy_bind_ip = undef, + $tls_proxy_fqdn = undef, + $tls_proxy_port = 6379, ) { if $step >= 2 { + if $enable_internal_tls { + if !$redis_network { + fail('redis_network is not set in the hieradata.') + } + if !$tls_proxy_bind_ip { + fail('tls_proxy_bind_ip is not set in the hieradata.') + } + if !$tls_proxy_fqdn { + fail('tls_proxy_fqdn is required if internal TLS is enabled.') + } + $tls_certfile = $certificate_specs['service_certificate'] + $tls_keyfile = $certificate_specs['service_key'] + + include ::tripleo::stunnel + + ::tripleo::stunnel::service_proxy { 'redis': + accept_host => $tls_proxy_bind_ip, + accept_port => $tls_proxy_port, + connect_port => $tls_proxy_port, + certificate => $tls_certfile, + key => $tls_keyfile, + notify => Class['::redis'], + } + } if downcase($bootstrap_nodeid) == $::hostname { $slaveof = undef } else { diff --git a/manifests/profile/base/gnocchi/api.pp b/manifests/profile/base/gnocchi/api.pp index 88177fd..c958359 100644 --- a/manifests/profile/base/gnocchi/api.pp +++ b/manifests/profile/base/gnocchi/api.pp @@ -84,9 +84,11 @@ class tripleo::profile::base::gnocchi::api ( } $tls_certfile = $certificates_specs["httpd-${gnocchi_network}"]['service_certificate'] $tls_keyfile = $certificates_specs["httpd-${gnocchi_network}"]['service_key'] + $tls_query_param = '?ssl=true' } else { $tls_certfile = undef $tls_keyfile = undef + $tls_query_param = '' } if $step >= 4 and $sync_db { @@ -104,11 +106,11 @@ class tripleo::profile::base::gnocchi::api ( if $step >= 4 { class { '::gnocchi::storage': - coordination_url => join(['redis://:', $gnocchi_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/']), + coordination_url => join(['redis://:', $gnocchi_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/', $tls_query_param]), } class { '::gnocchi::storage::incoming::redis': - redis_url => join(['redis://:', $gnocchi_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/']), + redis_url => join(['redis://:', $gnocchi_redis_password, '@', normalize_ip_for_uri($redis_vip), ':6379/', $tls_query_param]), } case $gnocchi_backend { diff --git a/manifests/profile/pacemaker/database/redis.pp b/manifests/profile/pacemaker/database/redis.pp index bc91be7..e6a2bf8 100644 --- a/manifests/profile/pacemaker/database/redis.pp +++ b/manifests/profile/pacemaker/database/redis.pp @@ -22,6 +22,21 @@ # (Optional) The hostname of the node responsible for bootstrapping tasks # Defaults to hiera('redis_short_bootstrap_node_name') # +# [*certificate_specs*] +# (Optional) The specifications to give to certmonger for the certificate(s) +# it will create. +# Example with hiera: +# redis_certificate_specs: +# hostname: +# service_certificate: +# service_key: +# principal: "haproxy/" +# Defaults to hiera('redis_certificate_specs', {}). +# +# [*enable_internal_tls*] +# (Optional) Whether TLS in the internal network is enabled or not. +# Defaults to hiera('enable_internal_tls', false) +# # [*enable_load_balancer*] # (Optional) Whether load balancing is enabled for this cluster # Defaults to hiera('enable_load_balancer', true) @@ -39,16 +54,42 @@ # https://github.com/arioch/puppet-redis/pull/192. Set redis::ulimit via hiera # to control this limit. # +# [*redis_network*] +# (Optional) The network name where the redis endpoint is listening on. +# This is set by t-h-t. +# Defaults to hiera('redis_network', undef) +# # [*pcs_tries*] # (Optional) The number of times pcs commands should be retried. # Defaults to hiera('pcs_tries', 20) # +# [*tls_proxy_bind_ip*] +# IP on which the TLS proxy will listen on. Required only if +# enable_internal_tls is set. +# Defaults to undef +# +# [*tls_proxy_fqdn*] +# fqdn on which the tls proxy will listen on. required only used if +# enable_internal_tls is set. +# defaults to undef +# +# [*tls_proxy_port*] +# port on which the tls proxy will listen on. Only used if +# enable_internal_tls is set. +# defaults to 6379 +# class tripleo::profile::pacemaker::database::redis ( + $certificate_specs = hiera('redis_certificate_specs', {}), + $enable_internal_tls = hiera('enable_internal_tls', false), $bootstrap_node = hiera('redis_short_bootstrap_node_name'), $enable_load_balancer = hiera('enable_load_balancer', true), $step = Integer(hiera('step')), $redis_file_limit = undef, + $redis_network = hiera('redis_network', undef), $pcs_tries = hiera('pcs_tries', 20), + $tls_proxy_bind_ip = undef, + $tls_proxy_fqdn = undef, + $tls_proxy_port = 6379, ) { if $::hostname == downcase($bootstrap_node) { $pacemaker_master = true @@ -57,6 +98,30 @@ class tripleo::profile::pacemaker::database::redis ( } if $step >= 1 { + if $enable_internal_tls { + if !$redis_network { + fail('redis_network is not set in the hieradata.') + } + if !$tls_proxy_bind_ip { + fail('tls_proxy_bind_ip is not set in the hieradata.') + } + if !$tls_proxy_fqdn { + fail('tls_proxy_fqdn is required if internal TLS is enabled.') + } + $tls_certfile = $certificate_specs['service_certificate'] + $tls_keyfile = $certificate_specs['service_key'] + + include ::tripleo::stunnel + + ::tripleo::stunnel::service_proxy { 'redis': + accept_host => $tls_proxy_bind_ip, + accept_port => $tls_proxy_port, + connect_port => $tls_proxy_port, + certificate => $tls_certfile, + key => $tls_keyfile, + notify => Class['::redis'], + } + } # If the old hiera key exists we use that to set the ulimit in order not to break # operators which set it. We might remove this in a later release (post pike anyway) $old_redis_file_limit = hiera('redis_file_limit', undef) -- cgit 1.2.3-korg