Add minimum TLS version option in octavia.conf
Add new configuration option "minimum_tls_versions" to octavia.conf. Listeners, pools, or the default values for either will be blocked from using lower versions. Change-Id: Ifa0d695c2227772d6b37987a7857fe58ca660dc8 Story: 2006733 Task: 37171 Depends-On: I480b7fb9756d98ba9dbcdfd1d4b193ce6868e291
This commit is contained in:
parent
0321c28588
commit
270b973bf9
@ -80,6 +80,10 @@
|
|||||||
# pools. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
# pools. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
||||||
# default_pool_tls_versions = TLSv1.2, TLSv1.3
|
# default_pool_tls_versions = TLSv1.2, TLSv1.3
|
||||||
|
|
||||||
|
# Minimum TLS version to allow for listeners, pools, or the defaults for
|
||||||
|
# either. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
||||||
|
# minimum_tls_version =
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# This line MUST be changed to actually run the plugin.
|
# This line MUST be changed to actually run the plugin.
|
||||||
# Example:
|
# Example:
|
||||||
|
@ -288,9 +288,11 @@ class ListenersController(base.BaseController):
|
|||||||
vip_address = vip_db.ip_address
|
vip_address = vip_db.ip_address
|
||||||
self._validate_cidr_compatible_with_vip(vip_address, allowed_cidrs)
|
self._validate_cidr_compatible_with_vip(vip_address, allowed_cidrs)
|
||||||
|
|
||||||
# Validate TLS version list
|
|
||||||
if listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS:
|
if listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS:
|
||||||
|
# Validate TLS version list
|
||||||
validate.check_tls_version_list(listener_dict['tls_versions'])
|
validate.check_tls_version_list(listener_dict['tls_versions'])
|
||||||
|
# Validate TLS versions against minimum
|
||||||
|
validate.check_tls_version_min(listener_dict['tls_versions'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db_listener = self.repositories.listener.create(
|
db_listener = self.repositories.listener.create(
|
||||||
@ -498,9 +500,11 @@ class ListenersController(base.BaseController):
|
|||||||
'The following ciphers have been blacklisted by an '
|
'The following ciphers have been blacklisted by an '
|
||||||
'administrator: ' + ', '.join(rejected_ciphers)))
|
'administrator: ' + ', '.join(rejected_ciphers)))
|
||||||
|
|
||||||
# Validate TLS version list
|
|
||||||
if listener.tls_versions is not wtypes.Unset:
|
if listener.tls_versions is not wtypes.Unset:
|
||||||
|
# Validate TLS version list
|
||||||
validate.check_tls_version_list(listener.tls_versions)
|
validate.check_tls_version_list(listener.tls_versions)
|
||||||
|
# Validate TLS versions against minimum
|
||||||
|
validate.check_tls_version_min(listener.tls_versions)
|
||||||
|
|
||||||
def _set_default_on_none(self, listener):
|
def _set_default_on_none(self, listener):
|
||||||
"""Reset settings to their default values if None/null was passed in
|
"""Reset settings to their default values if None/null was passed in
|
||||||
|
@ -131,9 +131,11 @@ class PoolsController(base.BaseController):
|
|||||||
'The following ciphers have been blacklisted by an '
|
'The following ciphers have been blacklisted by an '
|
||||||
'administrator: ' + ', '.join(rejected_ciphers)))
|
'administrator: ' + ', '.join(rejected_ciphers)))
|
||||||
|
|
||||||
# Validate TLS version list
|
|
||||||
if pool_dict['tls_enabled']:
|
if pool_dict['tls_enabled']:
|
||||||
|
# Validate TLS version list
|
||||||
validate.check_tls_version_list(pool_dict['tls_versions'])
|
validate.check_tls_version_list(pool_dict['tls_versions'])
|
||||||
|
# Validate TLS versions against minimum
|
||||||
|
validate.check_tls_version_min(pool_dict['tls_versions'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.repositories.create_pool_on_load_balancer(
|
return self.repositories.create_pool_on_load_balancer(
|
||||||
@ -399,9 +401,11 @@ class PoolsController(base.BaseController):
|
|||||||
"The following ciphers have been blacklisted by an "
|
"The following ciphers have been blacklisted by an "
|
||||||
"administrator: " + ', '.join(rejected_ciphers)))
|
"administrator: " + ', '.join(rejected_ciphers)))
|
||||||
|
|
||||||
# Validate TLS version list
|
|
||||||
if pool.tls_versions is not wtypes.Unset:
|
if pool.tls_versions is not wtypes.Unset:
|
||||||
|
# Validate TLS version list
|
||||||
validate.check_tls_version_list(pool.tls_versions)
|
validate.check_tls_version_list(pool.tls_versions)
|
||||||
|
# Validate TLS version against minimum
|
||||||
|
validate.check_tls_version_min(pool.tls_versions)
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(pool_types.PoolRootResponse, wtypes.text,
|
@wsme_pecan.wsexpose(pool_types.PoolRootResponse, wtypes.text,
|
||||||
body=pool_types.PoolRootPut, status_code=200)
|
body=pool_types.PoolRootPut, status_code=200)
|
||||||
|
@ -123,7 +123,11 @@ api_opts = [
|
|||||||
cfg.ListOpt('default_pool_tls_versions',
|
cfg.ListOpt('default_pool_tls_versions',
|
||||||
default=constants.TLS_VERSIONS_OWASP_SUITE_B,
|
default=constants.TLS_VERSIONS_OWASP_SUITE_B,
|
||||||
help=_('List of TLS versions to use for new TLS-enabled '
|
help=_('List of TLS versions to use for new TLS-enabled '
|
||||||
'pools.'))
|
'pools.')),
|
||||||
|
cfg.StrOpt('minimum_tls_version',
|
||||||
|
default=None,
|
||||||
|
choices=constants.TLS_ALL_VERSIONS + [None],
|
||||||
|
help=_('Minimum allowed TLS version for listeners and pools.'))
|
||||||
]
|
]
|
||||||
|
|
||||||
# Options only used by the amphora agent
|
# Options only used by the amphora agent
|
||||||
@ -833,6 +837,7 @@ def init(args, **kwargs):
|
|||||||
version='%%prog %s' % version.version_info.release_string(),
|
version='%%prog %s' % version.version_info.release_string(),
|
||||||
**kwargs)
|
**kwargs)
|
||||||
handle_deprecation_compatibility()
|
handle_deprecation_compatibility()
|
||||||
|
validate.check_default_tls_versions_min_conflict()
|
||||||
setup_remote_debugger()
|
setup_remote_debugger()
|
||||||
validate.check_default_ciphers_blacklist_conflict()
|
validate.check_default_ciphers_blacklist_conflict()
|
||||||
|
|
||||||
|
@ -471,3 +471,40 @@ def check_tls_version_list(versions):
|
|||||||
if invalid_versions:
|
if invalid_versions:
|
||||||
raise exceptions.ValidationException(
|
raise exceptions.ValidationException(
|
||||||
detail=_('Invalid TLS versions: ' + ', '.join(invalid_versions)))
|
detail=_('Invalid TLS versions: ' + ', '.join(invalid_versions)))
|
||||||
|
|
||||||
|
|
||||||
|
def check_tls_version_min(versions, message=None):
|
||||||
|
"""Checks a TLS version string against the configured minimum."""
|
||||||
|
|
||||||
|
if not CONF.api_settings.minimum_tls_version:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not message:
|
||||||
|
message = _("Requested TLS versions are less than the minimum: ")
|
||||||
|
|
||||||
|
min_ver_index = constants.TLS_ALL_VERSIONS.index(
|
||||||
|
CONF.api_settings.minimum_tls_version)
|
||||||
|
|
||||||
|
rejected = []
|
||||||
|
for ver in versions:
|
||||||
|
if constants.TLS_ALL_VERSIONS.index(ver) < min_ver_index:
|
||||||
|
rejected.append(ver)
|
||||||
|
if rejected:
|
||||||
|
raise exceptions.ValidationException(detail=(
|
||||||
|
message + ', '.join(rejected) + " < " +
|
||||||
|
CONF.api_settings.minimum_tls_version))
|
||||||
|
|
||||||
|
|
||||||
|
def check_default_tls_versions_min_conflict():
|
||||||
|
if not CONF.api_settings.minimum_tls_version:
|
||||||
|
return
|
||||||
|
|
||||||
|
listener_message = _("Default listener TLS versions are less than the "
|
||||||
|
"minimum: ")
|
||||||
|
pool_message = _("Default pool TLS versions are less than the minimum: ")
|
||||||
|
|
||||||
|
check_tls_version_min(CONF.api_settings.default_listener_tls_versions,
|
||||||
|
message=listener_message)
|
||||||
|
|
||||||
|
check_tls_version_min(CONF.api_settings.default_pool_tls_versions,
|
||||||
|
message=pool_message)
|
||||||
|
@ -484,3 +484,31 @@ class TestValidations(base.TestCase):
|
|||||||
exceptions.ValidationException,
|
exceptions.ValidationException,
|
||||||
validate.check_tls_version_list,
|
validate.check_tls_version_list,
|
||||||
[])
|
[])
|
||||||
|
|
||||||
|
def test_check_tls_version_min(self):
|
||||||
|
self.conf.config(group="api_settings", minimum_tls_version='TLSv1.2')
|
||||||
|
|
||||||
|
# Test valid list
|
||||||
|
validate.check_tls_version_min(['TLSv1.2', 'TLSv1.3'])
|
||||||
|
|
||||||
|
# Test invalid list
|
||||||
|
self.assertRaises(exceptions.ValidationException,
|
||||||
|
validate.check_tls_version_min,
|
||||||
|
['TLSv1', 'TLSv1.1', 'TLSv1.2'])
|
||||||
|
|
||||||
|
def test_check_default_tls_versions_min_conflict(self):
|
||||||
|
self.conf.config(group="api_settings", minimum_tls_version='TLSv1.2')
|
||||||
|
|
||||||
|
# Test conflict in listener default
|
||||||
|
self.conf.config(group="api_settings", default_listener_tls_versions=[
|
||||||
|
'SSLv3', 'TLSv1.2'])
|
||||||
|
self.assertRaises(exceptions.ValidationException,
|
||||||
|
validate.check_default_tls_versions_min_conflict)
|
||||||
|
|
||||||
|
# Test conflict in pool default
|
||||||
|
self.conf.config(group="api_settings", default_listener_tls_versions=[
|
||||||
|
'TLSv1.2'])
|
||||||
|
self.conf.config(group="api_settings", default_pool_tls_versions=[
|
||||||
|
'TLSv1', 'TLSv1.3'])
|
||||||
|
self.assertRaises(exceptions.ValidationException,
|
||||||
|
validate.check_default_tls_versions_min_conflict)
|
||||||
|
6
releasenotes/notes/min-tls-version-8e2856fb055ece2c.yaml
Normal file
6
releasenotes/notes/min-tls-version-8e2856fb055ece2c.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added ``minimum_tls_version`` to ``octavia.conf``. Listeners, pools, and
|
||||||
|
the defaults for either will be blocked from using any lower TLS versions.
|
||||||
|
By default, there is no minumum version.
|
Loading…
Reference in New Issue
Block a user