Merge "Fix listeners with SNI certificates"

This commit is contained in:
Zuul 2019-11-14 20:43:30 +00:00 committed by Gerrit Code Review
commit 01a3ed55db
12 changed files with 130 additions and 160 deletions

View File

@ -30,7 +30,7 @@ LOG = logging.getLogger(__name__)
FRONTEND_BACKEND_PATTERN = re.compile(r'\n(frontend|backend)\s+(\S+)\n')
LISTENER_MODE_PATTERN = re.compile(r'^\s+mode\s+(.*)$', re.MULTILINE)
TLS_CERT_PATTERN = re.compile(r'^\s+bind\s+\S+\s+ssl crt\s+(.*)$',
TLS_CERT_PATTERN = re.compile(r'^\s+bind\s+\S+\s+ssl crt-list\s+(.*)$',
re.MULTILINE)
STATS_SOCKET_PATTERN = re.compile(r'stats socket\s+(\S+)')

View File

@ -145,7 +145,6 @@ class HaproxyAmphoraLoadBalancerDriver(
'process mode.', amphora.id, loadbalancer.id)
has_tcp = False
certs = {}
for listener in loadbalancer.listeners:
LOG.debug("%s updating listener %s on amphora %s",
self.__class__.__name__, listener.id, amphora.id)
@ -163,10 +162,8 @@ class HaproxyAmphoraLoadBalancerDriver(
else:
obj_id = loadbalancer.id
certs.update({
listener.tls_certificate_id:
self._process_tls_certificates(
listener, amphora, obj_id)['tls_cert']})
self._process_tls_certificates(listener, amphora, obj_id)
client_ca_filename = self._process_secret(
listener, listener.client_ca_tls_certificate_id,
amphora, obj_id)
@ -179,7 +176,6 @@ class HaproxyAmphoraLoadBalancerDriver(
if split_config:
config = self.jinja_split.build_config(
host_amphora=amphora, listener=listener,
tls_cert=certs[listener.tls_certificate_id],
haproxy_versions=haproxy_versions,
client_ca_filename=client_ca_filename,
client_crl=crl_filename,
@ -194,7 +190,6 @@ class HaproxyAmphoraLoadBalancerDriver(
# Generate HaProxy configuration from listener object
config = self.jinja_combo.build_config(
host_amphora=amphora, listeners=loadbalancer.listeners,
tls_certs=certs,
haproxy_versions=haproxy_versions,
client_ca_filename=client_ca_filename,
client_crl=crl_filename,
@ -414,11 +409,13 @@ class HaproxyAmphoraLoadBalancerDriver(
tls_cert = None
sni_certs = []
certs = []
cert_filename_list = []
data = cert_parser.load_certificates_data(
self.cert_manager, listener)
if data['tls_cert'] is not None:
tls_cert = data['tls_cert']
# Note, the first cert is the TLS default cert
certs.append(tls_cert)
if data['sni_certs']:
sni_certs = data['sni_certs']
@ -429,7 +426,17 @@ class HaproxyAmphoraLoadBalancerDriver(
pem = cert_parser.build_pem(cert)
md5 = hashlib.md5(pem).hexdigest() # nosec
name = '{id}.pem'.format(id=cert.id)
cert_filename_list.append(
os.path.join(
CONF.haproxy_amphora.base_cert_dir, obj_id, name))
self._upload_cert(amphora, obj_id, pem, md5, name)
if certs:
# Build and upload the crt-list file for haproxy
crt_list = "\n".join(cert_filename_list).encode('utf-8')
md5 = hashlib.md5(crt_list).hexdigest() # nosec
name = '{id}.pem'.format(id=listener.id)
self._upload_cert(amphora, obj_id, crt_list, md5, name)
return {'tls_cert': tls_cert, 'sni_certs': sni_certs}
def _process_secret(self, listener, secret_ref, amphora=None, obj_id=None):

View File

@ -81,15 +81,13 @@ class JinjaTemplater(object):
self.log_server = log_server
self.connection_logging = connection_logging
def build_config(self, host_amphora, listeners, tls_certs,
haproxy_versions, socket_path=None,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
def build_config(self, host_amphora, listeners, haproxy_versions,
socket_path=None, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Convert a logical configuration to the HAProxy version
:param host_amphora: The Amphora this configuration is hosted on
:param listener: The listener configuration
:param tls_certs: Dict of the TLS certificates for the listeners
:param socket_path: The socket path for Haproxy process
:return: Rendered configuration
"""
@ -104,8 +102,7 @@ class JinjaTemplater(object):
feature_compatibility[constants.HTTP_REUSE] = True
return self.render_loadbalancer_obj(
host_amphora, listeners, tls_certs=tls_certs,
socket_path=socket_path,
host_amphora, listeners, socket_path=socket_path,
feature_compatibility=feature_compatibility,
client_ca_filename=client_ca_filename, client_crl=client_crl,
pool_tls_certs=pool_tls_certs)
@ -144,15 +141,13 @@ class JinjaTemplater(object):
return log_format
def render_loadbalancer_obj(self, host_amphora, listeners,
tls_certs=None, socket_path=None,
feature_compatibility=None,
socket_path=None, feature_compatibility=None,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
"""Renders a templated configuration from a load balancer object
:param host_amphora: The Amphora this configuration is hosted on
:param listener: The listener configuration
:param tls_certs: Dict of the TLS certificates for the listener
:param client_ca_filename: The CA certificate for client authorization
:param socket_path: The socket path for Haproxy process
:return: Rendered configuration
@ -162,7 +157,6 @@ class JinjaTemplater(object):
host_amphora,
listeners[0].load_balancer,
listeners,
tls_certs,
feature_compatibility,
client_ca_filename=client_ca_filename,
client_crl=client_crl,
@ -182,9 +176,8 @@ class JinjaTemplater(object):
constants=constants)
def _transform_loadbalancer(self, host_amphora, loadbalancer, listeners,
tls_certs, feature_compatibility,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
feature_compatibility, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Transforms a load balancer into an object that will
be processed by the templating system
@ -194,7 +187,7 @@ class JinjaTemplater(object):
if listener.protocol == constants.PROTOCOL_UDP:
continue
listener_transforms.append(self._transform_listener(
listener, tls_certs, feature_compatibility, loadbalancer,
listener, feature_compatibility, loadbalancer,
client_ca_filename=client_ca_filename, client_crl=client_crl,
pool_tls_certs=pool_tls_certs))
@ -246,7 +239,7 @@ class JinjaTemplater(object):
'vrrp_priority': amphora.vrrp_priority
}
def _transform_listener(self, listener, tls_certs, feature_compatibility,
def _transform_listener(self, listener, feature_compatibility,
loadbalancer, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Transforms a listener into an object that will
@ -279,14 +272,12 @@ class JinjaTemplater(object):
ret_value['connection_limit'] = listener.connection_limit
else:
ret_value['connection_limit'] = constants.HAPROXY_MAX_MAXCONN
if listener.tls_certificate_id and tls_certs is not None:
ret_value['default_tls_path'] = '%s.pem' % (
os.path.join(self.base_crt_dir,
loadbalancer.id,
tls_certs[listener.tls_certificate_id].id))
if listener.sni_containers:
ret_value['crt_dir'] = os.path.join(
self.base_crt_dir, loadbalancer.id)
if listener.tls_certificate_id:
ret_value['crt_list_filename'] = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
loadbalancer.id, '{}.pem'.format(listener.id))
if listener.client_ca_tls_certificate_id:
ret_value['client_ca_tls_path'] = '%s' % (
os.path.join(self.base_crt_dir, loadbalancer.id,

View File

@ -27,17 +27,12 @@ peers {{ "%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
{% macro bind_macro(constants, listener, lb_vip_address) %}
{% if listener.default_tls_path %}
{% set def_crt_opt = ("ssl crt %s"|format(
listener.default_tls_path)|trim()) %}
{% if listener.crt_list_filename is defined %}
{% set def_crt_opt = ("ssl crt-list %s"|format(
listener.crt_list_filename)|trim()) %}
{% else %}
{% set def_crt_opt = "" %}
{% endif %}
{% if listener.crt_dir %}
{% set crt_dir_opt = "crt %s"|format(listener.crt_dir)|trim() %}
{% else %}
{% set crt_dir_opt = "" %}
{% endif %}
{% if listener.client_ca_tls_path and listener.client_auth %}
{% set client_ca_opt = "ca-file %s verify %s"|format(listener.client_ca_tls_path, listener.client_auth)|trim() %}
{% else %}
@ -49,7 +44,7 @@ peers {{ "%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
{% set ca_crl_opt = "" %}
{% endif %}
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
"%s %s %s %s"|format(def_crt_opt, crt_dir_opt, client_ca_opt, ca_crl_opt)|trim() }}
"%s %s %s"|format(def_crt_opt, client_ca_opt, ca_crl_opt)|trim() }}
{% endmacro %}

View File

@ -81,15 +81,13 @@ class JinjaTemplater(object):
self.log_server = log_server
self.connection_logging = connection_logging
def build_config(self, host_amphora, listener, tls_cert,
haproxy_versions, socket_path=None,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
def build_config(self, host_amphora, listener, haproxy_versions,
socket_path=None, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Convert a logical configuration to the HAProxy version
:param host_amphora: The Amphora this configuration is hosted on
:param listener: The listener configuration
:param tls_cert: The TLS certificates for the listener
:param socket_path: The socket path for Haproxy process
:return: Rendered configuration
"""
@ -104,7 +102,7 @@ class JinjaTemplater(object):
feature_compatibility[constants.HTTP_REUSE] = True
return self.render_loadbalancer_obj(
host_amphora, listener, tls_cert=tls_cert, socket_path=socket_path,
host_amphora, listener, socket_path=socket_path,
feature_compatibility=feature_compatibility,
client_ca_filename=client_ca_filename, client_crl=client_crl,
pool_tls_certs=pool_tls_certs)
@ -142,8 +140,7 @@ class JinjaTemplater(object):
log_format = log_format.replace(' ', '\\ ')
return log_format
def render_loadbalancer_obj(self, host_amphora, listener,
tls_cert=None, socket_path=None,
def render_loadbalancer_obj(self, host_amphora, listener, socket_path=None,
feature_compatibility=None,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
@ -151,21 +148,15 @@ class JinjaTemplater(object):
:param host_amphora: The Amphora this configuration is hosted on
:param listener: The listener configuration
:param tls_cert: The TLS certificates for the listener
:param client_ca_filename: The CA certificate for client authorization
:param socket_path: The socket path for Haproxy process
:return: Rendered configuration
"""
feature_compatibility = feature_compatibility or {}
loadbalancer = self._transform_loadbalancer(
host_amphora,
listener.load_balancer,
listener,
tls_cert,
feature_compatibility,
client_ca_filename=client_ca_filename,
client_crl=client_crl,
pool_tls_certs=pool_tls_certs)
host_amphora, listener.load_balancer, listener,
feature_compatibility, client_ca_filename=client_ca_filename,
client_crl=client_crl, pool_tls_certs=pool_tls_certs)
if not socket_path:
socket_path = '%s/%s.sock' % (self.base_amp_path, listener.id)
return self._get_template().render(
@ -180,15 +171,14 @@ class JinjaTemplater(object):
constants=constants)
def _transform_loadbalancer(self, host_amphora, loadbalancer, listener,
tls_cert, feature_compatibility,
client_ca_filename=None, client_crl=None,
pool_tls_certs=None):
feature_compatibility, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Transforms a load balancer into an object that will
be processed by the templating system
"""
t_listener = self._transform_listener(
listener, tls_cert, feature_compatibility, loadbalancer,
listener, feature_compatibility, loadbalancer,
client_ca_filename=client_ca_filename, client_crl=client_crl,
pool_tls_certs=pool_tls_certs)
ret_value = {
@ -229,7 +219,7 @@ class JinjaTemplater(object):
'vrrp_priority': amphora.vrrp_priority
}
def _transform_listener(self, listener, tls_cert, feature_compatibility,
def _transform_listener(self, listener, feature_compatibility,
loadbalancer, client_ca_filename=None,
client_crl=None, pool_tls_certs=None):
"""Transforms a listener into an object that will
@ -265,13 +255,12 @@ class JinjaTemplater(object):
ret_value['connection_limit'] = listener.connection_limit
else:
ret_value['connection_limit'] = constants.HAPROXY_MAX_MAXCONN
if listener.tls_certificate_id:
ret_value['default_tls_path'] = '%s.pem' % (
os.path.join(self.base_crt_dir,
listener.id,
tls_cert.id))
if listener.sni_containers:
ret_value['crt_dir'] = os.path.join(self.base_crt_dir, listener.id)
ret_value['crt_list_filename'] = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
listener.id, '{}.pem'.format(listener.id))
if listener.client_ca_tls_certificate_id:
ret_value['client_ca_tls_path'] = '%s' % (
os.path.join(self.base_crt_dir, listener.id,

View File

@ -27,17 +27,12 @@ peers {{ "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
{% macro bind_macro(constants, listener, lb_vip_address) %}
{% if listener.default_tls_path %}
{% set def_crt_opt = ("ssl crt %s"|format(
listener.default_tls_path)|trim()) %}
{% if listener.crt_list_filename is defined %}
{% set def_crt_opt = ("ssl crt-list %s"|format(
listener.crt_list_filename)|trim()) %}
{% else %}
{% set def_crt_opt = "" %}
{% endif %}
{% if listener.crt_dir %}
{% set crt_dir_opt = "crt %s"|format(listener.crt_dir)|trim() %}
{% else %}
{% set crt_dir_opt = "" %}
{% endif %}
{% if listener.client_ca_tls_path and listener.client_auth %}
{% set client_ca_opt = "ca-file %s verify %s"|format(listener.client_ca_tls_path, listener.client_auth)|trim() %}
{% else %}
@ -49,7 +44,7 @@ peers {{ "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
{% set ca_crl_opt = "" %}
{% endif %}
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
"%s %s %s %s"|format(def_crt_opt, crt_dir_opt, client_ca_opt, ca_crl_opt)|trim() }}
"%s %s %s"|format(def_crt_opt, client_ca_opt, ca_crl_opt)|trim() }}
{% endmacro %}

View File

@ -203,44 +203,33 @@ class TestUtil(base.TestCase):
self.assertIsNone(result)
def test_parse_haproxy_config(self):
# template_tls
tls_tupe = {'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
certificate='imaCert1', private_key='imaPrivateKey1',
primary_cn='FakeCN')}
self.CONF.config(group="haproxy_amphora",
base_cert_dir='/fake_cert_dir')
FAKE_CRT_LIST_FILENAME = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
'sample_loadbalancer_id_1/sample_listener_id_1.pem')
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True, sni=True)],
tls_tupe)
proto='TERMINATED_HTTPS', tls=True, sni=True)])
path = util.config_path(LISTENER_ID1)
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
res = util.parse_haproxy_file(LISTENER_ID1)
listener_dict = res[1]['sample_listener_id_1']
# NOTE: parse_haproxy_file makes mode TERMINATED_HTTPS even though
# the haproxy.cfg needs mode HTTP
self.assertEqual('TERMINATED_HTTPS', listener_dict['mode'])
self.assertEqual('/var/lib/octavia/sample_loadbalancer_id_1.sock',
res[0])
self.assertEqual(
'/var/lib/octavia/certs/sample_loadbalancer_id_1/'
'tls_container_id.pem crt /var/lib/octavia/certs/'
'sample_loadbalancer_id_1',
listener_dict['ssl_crt'])
self.assertEqual(FAKE_CRT_LIST_FILENAME, listener_dict['ssl_crt'])
# render_template_tls_no_sni
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True)],
tls_certs={'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
certificate='ImAalsdkfjCert',
private_key='ImAsdlfksdjPrivateKey',
primary_cn="FakeCN")})
proto='TERMINATED_HTTPS', tls=True)])
self.useFixture(test_utils.OpenFixture(path, rendered_obj))
res = util.parse_haproxy_file(LISTENER_ID1)
@ -248,9 +237,7 @@ class TestUtil(base.TestCase):
self.assertEqual('TERMINATED_HTTPS', listener_dict['mode'])
self.assertEqual(BASE_AMP_PATH + '/sample_loadbalancer_id_1.sock',
res[0])
self.assertEqual(
BASE_CRT_PATH + '/sample_loadbalancer_id_1/tls_container_id.pem',
listener_dict['ssl_crt'])
self.assertEqual(FAKE_CRT_LIST_FILENAME, listener_dict['ssl_crt'])
# render_template_http
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(

View File

@ -275,7 +275,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
'sni_certs': sconts
}
self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [
exc.NotFound, 'Fake_MD5', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
exc.NotFound, 'Fake_MD5', 'aaaaa', 'aaaaaaaa']
self.driver._process_tls_certificates(
sample_listener, self.amp, sample_listener.load_balancer.id)
gcm_calls = [
@ -309,7 +309,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls(
ucp_calls, any_order=True)
self.assertEqual(
3, self.driver.clients[API_VERSION].upload_cert_pem.call_count)
4, self.driver.clients[API_VERSION].upload_cert_pem.call_count)
@mock.patch('oslo_context.context.RequestContext')
@mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'

View File

@ -275,7 +275,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
'sni_certs': sconts
}
self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [
exc.NotFound, 'Fake_MD5', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
exc.NotFound, 'Fake_MD5', 'aaaaa', 'aaaaa']
self.driver._process_tls_certificates(
sample_listener, self.amp, sample_listener.load_balancer.id)
gcm_calls = [
@ -309,7 +309,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls(
ucp_calls, any_order=True)
self.assertEqual(
3, self.driver.clients[API_VERSION].upload_cert_pem.call_count)
4, self.driver.clients[API_VERSION].upload_cert_pem.call_count)
@mock.patch('oslo_context.context.RequestContext')
@mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'

View File

@ -16,11 +16,16 @@
import copy
import os
from oslo_config import cfg
from oslo_config import fixture as oslo_fixture
from octavia.common import constants
from octavia.common.jinja.haproxy.combined_listeners import jinja_cfg
from octavia.tests.unit import base
from octavia.tests.unit.common.sample_configs import sample_configs_combined
CONF = cfg.CONF
class TestHaproxyCfg(base.TestCase):
def setUp(self):
@ -34,20 +39,24 @@ class TestHaproxyCfg(base.TestCase):
self.assertEqual('haproxy.cfg.j2', template.name)
def test_render_template_tls(self):
conf = oslo_fixture.Config(cfg.CONF)
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
FAKE_CRT_LIST_FILENAME = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
'sample_loadbalancer_id_1/sample_listener_id_1.pem')
fe = ("frontend sample_listener_id_1\n"
" maxconn {maxconn}\n"
" redirect scheme https if !{{ ssl_fc }}\n"
" bind 10.0.0.2:443 "
"ssl crt /var/lib/octavia/certs/"
"sample_loadbalancer_id_1/tls_container_id.pem "
"crt /var/lib/octavia/certs/sample_loadbalancer_id_1 "
"ssl crt-list {crt_list} "
"ca-file /var/lib/octavia/certs/sample_loadbalancer_id_1/"
"client_ca.pem verify required crl-file /var/lib/octavia/"
"certs/sample_loadbalancer_id_1/SHA_ID.pem\n"
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_MAX_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -66,34 +75,32 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2 cookie "
"sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
tls_tupe = {'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
certificate='imaCert1', private_key='imaPrivateKey1',
primary_cn='FakeCN')}
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True, sni=True,
client_ca_cert=True, client_crl_cert=True)],
tls_tupe, client_ca_filename='client_ca.pem',
client_crl='SHA_ID.pem')
client_ca_filename='client_ca.pem', client_crl='SHA_ID.pem')
self.assertEqual(
sample_configs_combined.sample_base_expected_config(
frontend=fe, backend=be),
rendered_obj)
def test_render_template_tls_no_sni(self):
conf = oslo_fixture.Config(cfg.CONF)
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
FAKE_CRT_LIST_FILENAME = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
'sample_loadbalancer_id_1/sample_listener_id_1.pem')
fe = ("frontend sample_listener_id_1\n"
" maxconn {maxconn}\n"
" redirect scheme https if !{{ ssl_fc }}\n"
" bind 10.0.0.2:443 "
"ssl crt /var/lib/octavia/certs/"
"sample_loadbalancer_id_1/tls_container_id.pem\n"
" bind 10.0.0.2:443 ssl crt-list {crt_list}\n"
" mode http\n"
" default_backend sample_pool_id_1:sample_listener_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_MAX_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -115,13 +122,7 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_combined.sample_amphora_tuple(),
[sample_configs_combined.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True)],
tls_certs={'cont_id_1':
sample_configs_combined.sample_tls_container_tuple(
id='tls_container_id',
certificate='ImAalsdkfjCert',
private_key='ImAsdlfksdjPrivateKey',
primary_cn="FakeCN")})
proto='TERMINATED_HTTPS', tls=True)])
self.assertEqual(
sample_configs_combined.sample_base_expected_config(
frontend=fe, backend=be),
@ -922,13 +923,13 @@ class TestHaproxyCfg(base.TestCase):
def test_transform_listener(self):
in_listener = sample_configs_combined.sample_listener_tuple()
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
ret = self.jinja_cfg._transform_listener(in_listener, {},
in_listener.load_balancer)
self.assertEqual(sample_configs_combined.RET_LISTENER, ret)
def test_transform_listener_with_l7(self):
in_listener = sample_configs_combined.sample_listener_tuple(l7=True)
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
ret = self.jinja_cfg._transform_listener(in_listener, {},
in_listener.load_balancer)
self.assertEqual(sample_configs_combined.RET_LISTENER_L7, ret)
@ -936,7 +937,7 @@ class TestHaproxyCfg(base.TestCase):
in_amphora = sample_configs_combined.sample_amphora_tuple()
in_listener = sample_configs_combined.sample_listener_tuple()
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listener.load_balancer, [in_listener], None, {})
in_amphora, in_listener.load_balancer, [in_listener], {})
self.assertEqual(sample_configs_combined.RET_LB, ret)
def test_transform_amphora(self):
@ -948,7 +949,7 @@ class TestHaproxyCfg(base.TestCase):
in_amphora = sample_configs_combined.sample_amphora_tuple()
in_listener = sample_configs_combined.sample_listener_tuple(l7=True)
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listener.load_balancer, [in_listener], None, {})
in_amphora, in_listener.load_balancer, [in_listener], {})
self.assertEqual(sample_configs_combined.RET_LB_L7, ret)
def test_transform_l7policy(self):
@ -1066,7 +1067,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_amphora,
[sample_proxy_listener],
tls_certs=None,
haproxy_versions=("1", "8", "1"))
self.assertEqual(
sample_configs_combined.sample_base_expected_config(backend=be),
@ -1094,7 +1094,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_amphora,
[sample_proxy_listener],
tls_certs=None,
haproxy_versions=("1", "5", "18"))
self.assertEqual(
sample_configs_combined.sample_base_expected_config(backend=be),
@ -1176,7 +1175,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_configs_combined.sample_amphora_tuple(),
[sample_listener],
tls_certs=None,
haproxy_versions=("1", "5", "18"))
self.assertEqual(
sample_configs_combined.sample_base_expected_config(

View File

@ -16,11 +16,16 @@
import copy
import os
from oslo_config import cfg
from oslo_config import fixture as oslo_fixture
from octavia.common import constants
from octavia.common.jinja.haproxy.split_listeners import jinja_cfg
from octavia.tests.unit import base
from octavia.tests.unit.common.sample_configs import sample_configs_split
CONF = cfg.CONF
class TestHaproxyCfg(base.TestCase):
def setUp(self):
@ -34,20 +39,24 @@ class TestHaproxyCfg(base.TestCase):
self.assertEqual('haproxy.cfg.j2', template.name)
def test_render_template_tls(self):
conf = oslo_fixture.Config(cfg.CONF)
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
FAKE_CRT_LIST_FILENAME = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
'sample_listener_id_1/sample_listener_id_1.pem')
fe = ("frontend sample_listener_id_1\n"
" maxconn {maxconn}\n"
" redirect scheme https if !{{ ssl_fc }}\n"
" bind 10.0.0.2:443 "
"ssl crt /var/lib/octavia/certs/"
"sample_listener_id_1/tls_container_id.pem "
"crt /var/lib/octavia/certs/sample_listener_id_1 "
"ssl crt-list {crt_list} "
"ca-file /var/lib/octavia/certs/sample_listener_id_1/"
"client_ca.pem verify required crl-file /var/lib/octavia/"
"certs/sample_listener_id_1/SHA_ID.pem\n"
" mode http\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_MAX_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -66,16 +75,12 @@ class TestHaproxyCfg(base.TestCase):
"weight 13 check inter 30s fall 3 rise 2 cookie "
"sample_member_id_2\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
tls_tupe = sample_configs_split.sample_tls_container_tuple(
id='tls_container_id',
certificate='imaCert1', private_key='imaPrivateKey1',
primary_cn='FakeCN')
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_split.sample_amphora_tuple(),
sample_configs_split.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True, sni=True,
client_ca_cert=True, client_crl_cert=True),
tls_tupe, client_ca_filename='client_ca.pem',
client_ca_filename='client_ca.pem',
client_crl='SHA_ID.pem')
self.assertEqual(
sample_configs_split.sample_base_expected_config(
@ -83,16 +88,21 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj)
def test_render_template_tls_no_sni(self):
conf = oslo_fixture.Config(cfg.CONF)
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
FAKE_CRT_LIST_FILENAME = os.path.join(
CONF.haproxy_amphora.base_cert_dir,
'sample_listener_id_1/sample_listener_id_1.pem')
fe = ("frontend sample_listener_id_1\n"
" maxconn {maxconn}\n"
" redirect scheme https if !{{ ssl_fc }}\n"
" bind 10.0.0.2:443 "
"ssl crt /var/lib/octavia/certs/"
"sample_listener_id_1/tls_container_id.pem\n"
"ssl crt-list {crt_list}\n"
" mode http\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)
maxconn=constants.HAPROXY_MAX_MAXCONN,
crt_list=FAKE_CRT_LIST_FILENAME)
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -114,12 +124,7 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
sample_configs_split.sample_amphora_tuple(),
sample_configs_split.sample_listener_tuple(
proto='TERMINATED_HTTPS', tls=True),
tls_cert=sample_configs_split.sample_tls_container_tuple(
id='tls_container_id',
certificate='ImAalsdkfjCert',
private_key='ImAsdlfksdjPrivateKey',
primary_cn="FakeCN"))
proto='TERMINATED_HTTPS', tls=True))
self.assertEqual(
sample_configs_split.sample_base_expected_config(
frontend=fe, backend=be),
@ -913,13 +918,13 @@ class TestHaproxyCfg(base.TestCase):
def test_transform_listener(self):
in_listener = sample_configs_split.sample_listener_tuple()
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
ret = self.jinja_cfg._transform_listener(in_listener, {},
in_listener.load_balancer)
self.assertEqual(sample_configs_split.RET_LISTENER, ret)
def test_transform_listener_with_l7(self):
in_listener = sample_configs_split.sample_listener_tuple(l7=True)
ret = self.jinja_cfg._transform_listener(in_listener, None, {},
ret = self.jinja_cfg._transform_listener(in_listener, {},
in_listener.load_balancer)
self.assertEqual(sample_configs_split.RET_LISTENER_L7, ret)
@ -927,7 +932,7 @@ class TestHaproxyCfg(base.TestCase):
in_amphora = sample_configs_split.sample_amphora_tuple()
in_listener = sample_configs_split.sample_listener_tuple()
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listener.load_balancer, in_listener, None, {})
in_amphora, in_listener.load_balancer, in_listener, {})
self.assertEqual(sample_configs_split.RET_LB, ret)
def test_transform_amphora(self):
@ -939,7 +944,7 @@ class TestHaproxyCfg(base.TestCase):
in_amphora = sample_configs_split.sample_amphora_tuple()
in_listener = sample_configs_split.sample_listener_tuple(l7=True)
ret = self.jinja_cfg._transform_loadbalancer(
in_amphora, in_listener.load_balancer, in_listener, None, {})
in_amphora, in_listener.load_balancer, in_listener, {})
self.assertEqual(sample_configs_split.RET_LB_L7, ret)
def test_transform_l7policy(self):
@ -1052,7 +1057,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_configs_split.sample_amphora_tuple(),
sample_configs_split.sample_listener_tuple(be_proto='PROXY'),
tls_cert=None,
haproxy_versions=("1", "8", "1"))
self.assertEqual(
sample_configs_split.sample_base_expected_config(backend=be),
@ -1078,7 +1082,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_configs_split.sample_amphora_tuple(),
sample_configs_split.sample_listener_tuple(be_proto='PROXY'),
tls_cert=None,
haproxy_versions=("1", "5", "18"))
self.assertEqual(
sample_configs_split.sample_base_expected_config(backend=be),
@ -1159,7 +1162,6 @@ class TestHaproxyCfg(base.TestCase):
rendered_obj = j_cfg.build_config(
sample_configs_split.sample_amphora_tuple(),
sample_listener,
tls_cert=None,
haproxy_versions=("1", "5", "18"))
self.assertEqual(
sample_configs_split.sample_base_expected_config(

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fixes an issue where load balancers with more than one TLS enabled
listener, one or more SNI enabled, may load certificates from
other TLS enabled listeners for SNI use.