Browse Source

Merge "Add TLS cipher blacklist to octavia.conf"

changes/39/660239/69
Zuul 2 years ago committed by Gerrit Code Review
parent
commit
bcef33a3ff
  1. 4
      etc/octavia.conf
  2. 19
      octavia/api/v2/controllers/listener.py
  3. 18
      octavia/api/v2/controllers/pool.py
  4. 5
      octavia/common/config.py
  5. 26
      octavia/common/validate.py
  6. 10
      octavia/tests/unit/common/test_validations.py
  7. 6
      releasenotes/notes/tls-cipher-blacklist-b5a23ca38149f3b8.yaml

4
etc/octavia.conf

@ -68,6 +68,10 @@
# see https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html
# default_pool_ciphers = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256
# Colon-separated list of disallowed ciphers. Ciphers specified here will not be
# allowed on listeners, pools, or the default values for either.
# tls_cipher_blacklist =
[database]
# This line MUST be changed to actually run the plugin.
# Example:

19
octavia/api/v2/controllers/listener.py

@ -33,6 +33,7 @@ from octavia.common import data_models
from octavia.common import exceptions
from octavia.common import stats
from octavia.common import utils as common_utils
from octavia.common import validate
from octavia.db import api as db_api
from octavia.db import prepare as db_prepare
from octavia.i18n import _
@ -223,6 +224,15 @@ class ListenersController(base.BaseController):
"A client authentication CA reference is required to "
"specify a client authentication revocation list."))
# Check TLS cipher blacklist
if 'tls_ciphers' in listener_dict and listener_dict['tls_ciphers']:
rejected_ciphers = validate.check_cipher_blacklist(
listener_dict['tls_ciphers'])
if rejected_ciphers:
raise exceptions.ValidationException(detail=_(
'The following ciphers have been blacklisted by an '
'administrator: ' + ', '.join(rejected_ciphers)))
# Validate the TLS containers
sni_containers = listener_dict.pop('sni_containers', [])
tls_refs = [sni['tls_container_id'] for sni in sni_containers]
@ -475,6 +485,15 @@ class ListenersController(base.BaseController):
self._validate_cidr_compatible_with_vip(
vip_address, listener.allowed_cidrs)
# Check TLS cipher blacklist
if listener.tls_ciphers:
rejected_ciphers = validate.check_cipher_blacklist(
listener.tls_ciphers)
if rejected_ciphers:
raise exceptions.ValidationException(detail=_(
'The following ciphers have been blacklisted by an '
'administrator: ' + ', '.join(rejected_ciphers)))
def _set_default_on_none(self, listener):
"""Reset settings to their default values if None/null was passed in

18
octavia/api/v2/controllers/pool.py

@ -122,6 +122,15 @@ class PoolsController(base.BaseController):
pool_dict.get('ca_tls_certificate_id'),
pool_dict.get('crl_container_id', None))
# Check TLS cipher blacklist
if 'tls_ciphers' in pool_dict and pool_dict['tls_ciphers']:
rejected_ciphers = validate.check_cipher_blacklist(
pool_dict['tls_ciphers'])
if rejected_ciphers:
raise exceptions.ValidationException(detail=_(
'The following ciphers have been blacklisted by an '
'administrator: ' + ', '.join(rejected_ciphers)))
try:
return self.repositories.create_pool_on_load_balancer(
lock_session, pool_dict,
@ -377,6 +386,15 @@ class PoolsController(base.BaseController):
if ca_ref:
self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)
# Check TLS cipher blacklist
if pool.tls_ciphers:
rejected_ciphers = validate.check_cipher_blacklist(
pool.tls_ciphers)
if rejected_ciphers:
raise exceptions.ValidationException(detail=_(
"The following ciphers have been blacklisted by an "
"administrator: " + ', '.join(rejected_ciphers)))
@wsme_pecan.wsexpose(pool_types.PoolRootResponse, wtypes.text,
body=pool_types.PoolRootPut, status_code=200)
def put(self, id, pool_):

5
octavia/common/config.py

@ -31,6 +31,7 @@ import oslo_messaging as messaging
from octavia.certificates.common import local
from octavia.common import constants
from octavia.common import utils
from octavia.common import validate
from octavia.i18n import _
from octavia import version
@ -112,6 +113,9 @@ api_opts = [
default=constants.CIPHERS_OWASP_SUITE_B,
help=_("Default OpenSSL cipher string (colon-separated) for "
"new TLS-enabled pools.")),
cfg.StrOpt('tls_cipher_blacklist', default='',
help=_("Colon separated list of OpenSSL ciphers. "
"Usage of these ciphers will be blocked."))
]
# Options only used by the amphora agent
@ -822,6 +826,7 @@ def init(args, **kwargs):
**kwargs)
handle_deprecation_compatibility()
setup_remote_debugger()
validate.check_default_ciphers_blacklist_conflict()
def setup_logging(conf):

26
octavia/common/validate.py

@ -433,3 +433,29 @@ def is_flavor_spares_compatible(flavor):
if flavor.get(constants.COMPUTE_FLAVOR, None):
return False
return True
def check_cipher_blacklist(cipherstring):
ciphers = cipherstring.split(':')
blacklist = CONF.api_settings.tls_cipher_blacklist.split(':')
rejected = []
for cipher in ciphers:
if cipher in blacklist:
rejected.append(cipher)
return rejected
def check_default_ciphers_blacklist_conflict():
listener_rejected = check_cipher_blacklist(
CONF.api_settings.default_listener_ciphers)
if listener_rejected:
raise exceptions.ValidationException(
detail=_('Default listener ciphers conflict with blacklist. '
'Conflicting ciphers: ' + ', '.join(listener_rejected)))
pool_rejected = check_cipher_blacklist(
CONF.api_settings.default_pool_ciphers)
if pool_rejected:
raise exceptions.ValidationException(
detail=_('Default pool ciphers conflict with blacklist. '
'Conflicting ciphers: ' + ', '.join(pool_rejected)))

10
octavia/tests/unit/common/test_validations.py

@ -460,3 +460,13 @@ class TestValidations(base.TestCase):
self.assertTrue(validate.is_flavor_spares_compatible(compat_flavor))
self.assertFalse(
validate.is_flavor_spares_compatible(not_compat_flavor))
def test_check_default_ciphers_blacklist_conflict(self):
self.conf.config(group='api_settings',
tls_cipher_blacklist='PSK-AES128-CBC-SHA')
self.conf.config(group='api_settings',
default_listener_ciphers='ECDHE-ECDSA-AES256-SHA:'
'PSK-AES128-CBC-SHA:TLS_AES_256_GCM_SHA384')
self.assertRaises(exceptions.ValidationException,
validate.check_default_ciphers_blacklist_conflict)

6
releasenotes/notes/tls-cipher-blacklist-b5a23ca38149f3b8.yaml

@ -0,0 +1,6 @@
---
features:
- |
Added ``tls_cipher_blacklist`` to ``octavia.conf``. Listeners, pools, and
the default values for either will be blocked from using any of these ciphers.
By default, no ciphers are blacklisted.
Loading…
Cancel
Save