Merge "Fix listeners with SNI certificates"
This commit is contained in:
commit
01a3ed55db
|
@ -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+)')
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue