Add ability to set TLS cipher list for listeners
Listeners will now be able to each be assigned their own OpenSSL cipher string with a new field: tls_ciphers. There is also a new configuration option, default_listener_ciphers, which specifies the cipher string to assign to new listeners when one is not explicitly specified. Change-Id: I77da6f14063877af0077f2c12df1aab5d5ead187 Depends-On: Id5f4c20abd40dd092558a711987953012d4ae67f Story: 2006627 Task: 36839
This commit is contained in:
parent
73fca169ab
commit
cd176e55c5
@ -1503,6 +1503,22 @@ timeout_tcp_inspect-optional:
|
|||||||
min_version: 2.1
|
min_version: 2.1
|
||||||
required: false
|
required: false
|
||||||
type: integer
|
type: integer
|
||||||
|
tls_ciphers:
|
||||||
|
description: |
|
||||||
|
List of ciphers in OpenSSL format (colon-separated).
|
||||||
|
See https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
|
||||||
|
in: body
|
||||||
|
min_version: 2.15
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
tls_ciphers-optional:
|
||||||
|
description: |
|
||||||
|
List of ciphers in OpenSSL format (colon-separated).
|
||||||
|
See https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
|
||||||
|
in: body
|
||||||
|
min_version: 2.15
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
tls_container_ref:
|
tls_container_ref:
|
||||||
description: |
|
description: |
|
||||||
The reference to the `key manager service
|
The reference to the `key manager service
|
||||||
|
@ -1 +1 @@
|
|||||||
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"protocol": "TERMINATED_HTTPS", "description": "A great TLS listener", "admin_state_up": true, "connection_limit": 200, "protocol_port": "443", "loadbalancer_id": "607226db-27ef-4d41-ae89-f2a800e9c2db", "name": "great_tls_listener", "insert_headers": {"X-Forwarded-For": "true", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 50000, "timeout_member_connect": 5000, "timeout_member_data": 50000, "timeout_tcp_inspect": 0, "tags": ["test_tag"], "client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5", "client_authentication": "MANDATORY", "client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c", "allowed_cidrs": ["192.0.2.0/24", "198.51.100.0/24"]}}' http://198.51.100.10:9876/v2/lbaas/listeners
|
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"protocol": "TERMINATED_HTTPS", "description": "A great TLS listener", "admin_state_up": true, "connection_limit": 200, "protocol_port": "443", "loadbalancer_id": "607226db-27ef-4d41-ae89-f2a800e9c2db", "name": "great_tls_listener", "insert_headers": {"X-Forwarded-For": "true", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 50000, "timeout_member_connect": 5000, "timeout_member_data": 50000, "timeout_tcp_inspect": 0, "tags": ["test_tag"], "client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5", "client_authentication": "MANDATORY", "client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c", "allowed_cidrs": ["192.0.2.0/24", "198.51.100.0/24"], "tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"}}' http://198.51.100.10:9876/v2/lbaas/listeners
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"description": "An updated great TLS listener", "admin_state_up": true, "connection_limit": 200, "name": "great_updated_tls_listener", "insert_headers": {"X-Forwarded-For": "false", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 100000, "timeout_member_connect": 1000, "timeout_member_data": 100000, "timeout_tcp_inspect": 5, "tags": ["updated_tag"], "client_ca_tls_container_ref": null, "allowed_cidrs": ["192.0.2.0/24", "198.51.100.0/24"]}}' http://198.51.100.10:9876/v2/lbaas/listeners/023f2e34-7806-443b-bfae-16c324569a3d
|
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"description": "An updated great TLS listener", "admin_state_up": true, "connection_limit": 200, "name": "great_updated_tls_listener", "insert_headers": {"X-Forwarded-For": "false", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 100000, "timeout_member_connect": 1000, "timeout_member_data": 100000, "timeout_tcp_inspect": 5, "tags": ["updated_tag"], "client_ca_tls_container_ref": null, "allowed_cidrs": ["192.0.2.0/24", "198.51.100.0/24"], "tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"}}' http://198.51.100.10:9876/v2/lbaas/listeners/023f2e34-7806-443b-bfae-16c324569a3d
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@
|
|||||||
"allowed_cidrs": [
|
"allowed_cidrs": [
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
"198.51.100.0/24"
|
"198.51.100.0/24"
|
||||||
]
|
],
|
||||||
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ Response Parameters
|
|||||||
- timeout_member_connect: timeout_member_connect
|
- timeout_member_connect: timeout_member_connect
|
||||||
- timeout_member_data: timeout_member_data
|
- timeout_member_data: timeout_member_data
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect
|
- timeout_tcp_inspect: timeout_tcp_inspect
|
||||||
|
- tls_ciphers: tls_ciphers
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -163,6 +164,7 @@ Request
|
|||||||
- timeout_member_connect: timeout_member_connect-optional
|
- timeout_member_connect: timeout_member_connect-optional
|
||||||
- timeout_member_data: timeout_member_data-optional
|
- timeout_member_data: timeout_member_data-optional
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect-optional
|
- timeout_tcp_inspect: timeout_tcp_inspect-optional
|
||||||
|
- tls_ciphers: tls_ciphers-optional
|
||||||
|
|
||||||
.. _header_insertions:
|
.. _header_insertions:
|
||||||
|
|
||||||
@ -287,6 +289,7 @@ Response Parameters
|
|||||||
- timeout_member_connect: timeout_member_connect
|
- timeout_member_connect: timeout_member_connect
|
||||||
- timeout_member_data: timeout_member_data
|
- timeout_member_data: timeout_member_data
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect
|
- timeout_tcp_inspect: timeout_tcp_inspect
|
||||||
|
- tls_ciphers: tls_ciphers
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -365,6 +368,7 @@ Response Parameters
|
|||||||
- timeout_member_connect: timeout_member_connect
|
- timeout_member_connect: timeout_member_connect
|
||||||
- timeout_member_data: timeout_member_data
|
- timeout_member_data: timeout_member_data
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect
|
- timeout_tcp_inspect: timeout_tcp_inspect
|
||||||
|
- tls_ciphers: tls_ciphers
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -424,6 +428,7 @@ Request
|
|||||||
- timeout_member_connect: timeout_member_connect-optional
|
- timeout_member_connect: timeout_member_connect-optional
|
||||||
- timeout_member_data: timeout_member_data-optional
|
- timeout_member_data: timeout_member_data-optional
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect-optional
|
- timeout_tcp_inspect: timeout_tcp_inspect-optional
|
||||||
|
- tls_ciphers: tls_ciphers-optional
|
||||||
|
|
||||||
Request Example
|
Request Example
|
||||||
---------------
|
---------------
|
||||||
@ -469,6 +474,7 @@ Response Parameters
|
|||||||
- timeout_member_connect: timeout_member_connect
|
- timeout_member_connect: timeout_member_connect
|
||||||
- timeout_member_data: timeout_member_data
|
- timeout_member_data: timeout_member_data
|
||||||
- timeout_tcp_inspect: timeout_tcp_inspect
|
- timeout_tcp_inspect: timeout_tcp_inspect
|
||||||
|
- tls_ciphers: tls_ciphers
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
|
@ -56,6 +56,12 @@
|
|||||||
# Boolean to enable/disable oslo middleware /healthcheck in the Octavia API
|
# Boolean to enable/disable oslo middleware /healthcheck in the Octavia API
|
||||||
# healthcheck_enabled = False
|
# healthcheck_enabled = False
|
||||||
|
|
||||||
|
# Default cipher string for new TLS-terminated listeners
|
||||||
|
# Cipher strings are in OpenSSL format, see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
|
||||||
|
# This example is the "Broad Compatibility" cipher string from OWASP,
|
||||||
|
# see https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html
|
||||||
|
# default_listener_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
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# This line MUST be changed to actually run the plugin.
|
# This line MUST be changed to actually run the plugin.
|
||||||
# Example:
|
# Example:
|
||||||
|
@ -73,7 +73,7 @@ munch==2.2.0
|
|||||||
netaddr==0.7.19
|
netaddr==0.7.19
|
||||||
netifaces==0.10.4
|
netifaces==0.10.4
|
||||||
networkx==1.11
|
networkx==1.11
|
||||||
octavia-lib==1.5.0
|
octavia-lib==2.0.0
|
||||||
openstacksdk==0.12.0
|
openstacksdk==0.12.0
|
||||||
os-client-config==1.29.0
|
os-client-config==1.29.0
|
||||||
os-service-types==1.2.0
|
os-service-types==1.2.0
|
||||||
|
@ -30,7 +30,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
FRONTEND_BACKEND_PATTERN = re.compile(r'\n(frontend|backend)\s+(\S+)\n')
|
FRONTEND_BACKEND_PATTERN = re.compile(r'\n(frontend|backend)\s+(\S+)\n')
|
||||||
LISTENER_MODE_PATTERN = re.compile(r'^\s+mode\s+(.*)$', re.MULTILINE)
|
LISTENER_MODE_PATTERN = re.compile(r'^\s+mode\s+(.*)$', re.MULTILINE)
|
||||||
TLS_CERT_PATTERN = re.compile(r'^\s+bind\s+\S+\s+ssl crt-list\s+(.*)$',
|
TLS_CERT_PATTERN = re.compile(r'^\s+bind\s+\S+\s+ssl crt-list\s+(\S*)',
|
||||||
re.MULTILINE)
|
re.MULTILINE)
|
||||||
STATS_SOCKET_PATTERN = re.compile(r'stats socket\s+(\S+)')
|
STATS_SOCKET_PATTERN = re.compile(r'stats socket\s+(\S+)')
|
||||||
|
|
||||||
|
@ -107,6 +107,10 @@ class RootController(object):
|
|||||||
self._add_a_version(versions, 'v2.13', 'v2', 'SUPPORTED',
|
self._add_a_version(versions, 'v2.13', 'v2', 'SUPPORTED',
|
||||||
'2019-09-13T00:00:00Z', host_url)
|
'2019-09-13T00:00:00Z', host_url)
|
||||||
# Availability Zones
|
# Availability Zones
|
||||||
self._add_a_version(versions, 'v2.14', 'v2', 'CURRENT',
|
self._add_a_version(versions, 'v2.14', 'v2', 'SUPPORTED',
|
||||||
'2019-11-10T00:00:00Z', host_url)
|
'2019-11-10T00:00:00Z', host_url)
|
||||||
|
|
||||||
|
# TLS version and cipher options
|
||||||
|
self._add_a_version(versions, 'v2.15', 'v2', 'CURRENT',
|
||||||
|
'2020-03-10T00:00:00Z', host_url)
|
||||||
return {'versions': versions}
|
return {'versions': versions}
|
||||||
|
@ -62,6 +62,7 @@ class ListenerResponse(BaseListenerType):
|
|||||||
client_authentication = wtypes.wsattr(wtypes.StringType())
|
client_authentication = wtypes.wsattr(wtypes.StringType())
|
||||||
client_crl_container_ref = wtypes.wsattr(wtypes.StringType())
|
client_crl_container_ref = wtypes.wsattr(wtypes.StringType())
|
||||||
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
||||||
|
tls_ciphers = wtypes.StringType()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data_model(cls, data_model, children=False):
|
def from_data_model(cls, data_model, children=False):
|
||||||
@ -150,6 +151,7 @@ class ListenerPOST(BaseListenerType):
|
|||||||
default=constants.CLIENT_AUTH_NONE)
|
default=constants.CLIENT_AUTH_NONE)
|
||||||
client_crl_container_ref = wtypes.StringType(max_length=255)
|
client_crl_container_ref = wtypes.StringType(max_length=255)
|
||||||
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
||||||
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
|
||||||
|
|
||||||
class ListenerRootPOST(types.BaseType):
|
class ListenerRootPOST(types.BaseType):
|
||||||
@ -187,6 +189,7 @@ class ListenerPUT(BaseListenerType):
|
|||||||
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES))
|
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES))
|
||||||
client_crl_container_ref = wtypes.StringType(max_length=255)
|
client_crl_container_ref = wtypes.StringType(max_length=255)
|
||||||
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
||||||
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
|
||||||
|
|
||||||
class ListenerRootPUT(types.BaseType):
|
class ListenerRootPUT(types.BaseType):
|
||||||
@ -237,6 +240,7 @@ class ListenerSingleCreate(BaseListenerType):
|
|||||||
default=constants.CLIENT_AUTH_NONE)
|
default=constants.CLIENT_AUTH_NONE)
|
||||||
client_crl_container_ref = wtypes.StringType(max_length=255)
|
client_crl_container_ref = wtypes.StringType(max_length=255)
|
||||||
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
allowed_cidrs = wtypes.wsattr([types.CidrType()])
|
||||||
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
|
||||||
|
|
||||||
class ListenerStatusResponse(BaseListenerType):
|
class ListenerStatusResponse(BaseListenerType):
|
||||||
|
@ -103,6 +103,10 @@ api_opts = [
|
|||||||
cfg.BoolOpt('healthcheck_enabled', default=False,
|
cfg.BoolOpt('healthcheck_enabled', default=False,
|
||||||
help=_("When True, the oslo middleware healthcheck endpoint "
|
help=_("When True, the oslo middleware healthcheck endpoint "
|
||||||
"is enabled in the Octavia API.")),
|
"is enabled in the Octavia API.")),
|
||||||
|
cfg.StrOpt('default_listener_ciphers',
|
||||||
|
default=constants.CIPHERS_OWASP_SUITE_B,
|
||||||
|
help=_("Default OpenSSL cipher string (colon-separated) for "
|
||||||
|
"new TLS-enabled listeners.")),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Options only used by the amphora agent
|
# Options only used by the amphora agent
|
||||||
|
@ -775,3 +775,12 @@ CINDER_ACTION_CREATE_VOLUME = 'create volume'
|
|||||||
|
|
||||||
# The nil UUID (used in octavia for deleted references) - RFC 4122
|
# The nil UUID (used in octavia for deleted references) - RFC 4122
|
||||||
NIL_UUID = '00000000-0000-0000-0000-000000000000'
|
NIL_UUID = '00000000-0000-0000-0000-000000000000'
|
||||||
|
|
||||||
|
# OpenSSL cipher strings
|
||||||
|
CIPHERS_OWASP_SUITE_B = ('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')
|
||||||
|
@ -384,7 +384,7 @@ class Listener(BaseDataModel):
|
|||||||
timeout_member_data=None, timeout_tcp_inspect=None,
|
timeout_member_data=None, timeout_tcp_inspect=None,
|
||||||
tags=None, client_ca_tls_certificate_id=None,
|
tags=None, client_ca_tls_certificate_id=None,
|
||||||
client_authentication=None, client_crl_container_id=None,
|
client_authentication=None, client_crl_container_id=None,
|
||||||
allowed_cidrs=None):
|
allowed_cidrs=None, tls_ciphers=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -417,6 +417,7 @@ class Listener(BaseDataModel):
|
|||||||
self.client_authentication = client_authentication
|
self.client_authentication = client_authentication
|
||||||
self.client_crl_container_id = client_crl_container_id
|
self.client_crl_container_id = client_crl_container_id
|
||||||
self.allowed_cidrs = allowed_cidrs or []
|
self.allowed_cidrs = allowed_cidrs or []
|
||||||
|
self.tls_ciphers = tls_ciphers
|
||||||
|
|
||||||
def update(self, update_dict):
|
def update(self, update_dict):
|
||||||
for key, value in update_dict.items():
|
for key, value in update_dict.items():
|
||||||
|
@ -282,6 +282,10 @@ class JinjaTemplater(object):
|
|||||||
os.path.join(self.base_crt_dir, loadbalancer.id,
|
os.path.join(self.base_crt_dir, loadbalancer.id,
|
||||||
tls_certs[listener.client_crl_container_id]))
|
tls_certs[listener.client_crl_container_id]))
|
||||||
|
|
||||||
|
if (listener.protocol == constants.PROTOCOL_TERMINATED_HTTPS and
|
||||||
|
listener.tls_ciphers is not None):
|
||||||
|
ret_value['tls_ciphers'] = listener.tls_ciphers
|
||||||
|
|
||||||
pools = []
|
pools = []
|
||||||
pool_gen = (pool for pool in listener.pools if
|
pool_gen = (pool for pool in listener.pools if
|
||||||
pool.provisioning_status != constants.PENDING_DELETE)
|
pool.provisioning_status != constants.PENDING_DELETE)
|
||||||
|
@ -43,8 +43,13 @@ peers {{ "%s_peers"|format(loadbalancer.id.replace("-", ""))|trim() }}
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% set ca_crl_opt = "" %}
|
{% set ca_crl_opt = "" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if listener.tls_ciphers is defined %}
|
||||||
|
{% set ciphers_opt = "ciphers %s"|format(listener.tls_ciphers)|trim() %}
|
||||||
|
{% else %}
|
||||||
|
{% set ciphers_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
|
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
|
||||||
"%s %s %s"|format(def_crt_opt, client_ca_opt, ca_crl_opt)|trim() }}
|
"%s %s %s %s"|format(def_crt_opt, client_ca_opt, ca_crl_opt, ciphers_opt)|trim() }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2020 Dawson Coleman
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""add listener ciphers column
|
||||||
|
|
||||||
|
Revision ID: 7c36b277bfb0
|
||||||
|
Revises: 8ac4ed24df3a
|
||||||
|
Create Date: 2020-03-11 02:23:49.097485
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '7c36b277bfb0'
|
||||||
|
down_revision = '8ac4ed24df3a'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column(
|
||||||
|
'listener',
|
||||||
|
sa.Column('tls_ciphers', sa.String(2048), nullable=True)
|
||||||
|
)
|
@ -520,6 +520,7 @@ class Listener(base_models.BASE, base_models.IdMixin,
|
|||||||
name="fk_listener_client_authentication_mode_name"),
|
name="fk_listener_client_authentication_mode_name"),
|
||||||
nullable=False, default=constants.CLIENT_AUTH_NONE)
|
nullable=False, default=constants.CLIENT_AUTH_NONE)
|
||||||
client_crl_container_id = sa.Column(sa.String(255), nullable=True)
|
client_crl_container_id = sa.Column(sa.String(255), nullable=True)
|
||||||
|
tls_ciphers = sa.Column(sa.String(2048), nullable=True)
|
||||||
|
|
||||||
_tags = orm.relationship(
|
_tags = orm.relationship(
|
||||||
'Tags',
|
'Tags',
|
||||||
|
@ -103,6 +103,12 @@ def create_listener(listener_dict, lb_id):
|
|||||||
|
|
||||||
if 'client_authentication' not in listener_dict:
|
if 'client_authentication' not in listener_dict:
|
||||||
listener_dict['client_authentication'] = constants.CLIENT_AUTH_NONE
|
listener_dict['client_authentication'] = constants.CLIENT_AUTH_NONE
|
||||||
|
|
||||||
|
if (listener_dict['protocol'] == constants.PROTOCOL_TERMINATED_HTTPS and
|
||||||
|
('tls_ciphers' not in listener_dict or
|
||||||
|
listener_dict['tls_ciphers'] is None)):
|
||||||
|
listener_dict['tls_ciphers'] = (
|
||||||
|
CONF.api_settings.default_listener_ciphers)
|
||||||
return listener_dict
|
return listener_dict
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,7 +294,9 @@ class SampleDriverDataModels(object):
|
|||||||
lib_consts.CA_TLS_CONTAINER_DATA: pool_ca_file_content,
|
lib_consts.CA_TLS_CONTAINER_DATA: pool_ca_file_content,
|
||||||
lib_consts.CRL_CONTAINER_REF: self.pool_crl_container_ref,
|
lib_consts.CRL_CONTAINER_REF: self.pool_crl_container_ref,
|
||||||
lib_consts.CRL_CONTAINER_DATA: pool_crl_file_content,
|
lib_consts.CRL_CONTAINER_DATA: pool_crl_file_content,
|
||||||
lib_consts.TLS_ENABLED: True
|
lib_consts.TLS_ENABLED: True,
|
||||||
|
lib_consts.TLS_CIPHERS: None,
|
||||||
|
lib_consts.TLS_VERSIONS: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.provider_pool2_dict = copy.deepcopy(self.provider_pool1_dict)
|
self.provider_pool2_dict = copy.deepcopy(self.provider_pool1_dict)
|
||||||
@ -463,7 +465,8 @@ class SampleDriverDataModels(object):
|
|||||||
self.client_ca_tls_certificate_ref,
|
self.client_ca_tls_certificate_ref,
|
||||||
lib_consts.CLIENT_AUTHENTICATION: constants.CLIENT_AUTH_NONE,
|
lib_consts.CLIENT_AUTHENTICATION: constants.CLIENT_AUTH_NONE,
|
||||||
constants.CLIENT_CRL_CONTAINER_ID: self.client_crl_container_ref,
|
constants.CLIENT_CRL_CONTAINER_ID: self.client_crl_container_ref,
|
||||||
lib_consts.ALLOWED_CIDRS: ['192.0.2.0/24', '198.51.100.0/24']
|
lib_consts.ALLOWED_CIDRS: ['192.0.2.0/24', '198.51.100.0/24'],
|
||||||
|
lib_consts.TLS_CIPHERS: constants.CIPHERS_OWASP_SUITE_B
|
||||||
}
|
}
|
||||||
|
|
||||||
self.test_listener1_dict.update(self._common_test_dict)
|
self.test_listener1_dict.update(self._common_test_dict)
|
||||||
@ -530,7 +533,9 @@ class SampleDriverDataModels(object):
|
|||||||
lib_consts.CLIENT_CA_TLS_CONTAINER_DATA: ca_cert,
|
lib_consts.CLIENT_CA_TLS_CONTAINER_DATA: ca_cert,
|
||||||
lib_consts.CLIENT_AUTHENTICATION: constants.CLIENT_AUTH_NONE,
|
lib_consts.CLIENT_AUTHENTICATION: constants.CLIENT_AUTH_NONE,
|
||||||
lib_consts.CLIENT_CRL_CONTAINER_REF: self.client_crl_container_ref,
|
lib_consts.CLIENT_CRL_CONTAINER_REF: self.client_crl_container_ref,
|
||||||
lib_consts.CLIENT_CRL_CONTAINER_DATA: crl_file_content
|
lib_consts.CLIENT_CRL_CONTAINER_DATA: crl_file_content,
|
||||||
|
lib_consts.TLS_CIPHERS: constants.CIPHERS_OWASP_SUITE_B,
|
||||||
|
lib_consts.TLS_VERSIONS: None
|
||||||
}
|
}
|
||||||
|
|
||||||
self.provider_listener2_dict = copy.deepcopy(
|
self.provider_listener2_dict = copy.deepcopy(
|
||||||
|
@ -45,7 +45,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
|||||||
def test_api_versions(self):
|
def test_api_versions(self):
|
||||||
versions = self._get_versions_with_config()
|
versions = self._get_versions_with_config()
|
||||||
version_ids = tuple(v.get('id') for v in versions)
|
version_ids = tuple(v.get('id') for v in versions)
|
||||||
self.assertEqual(15, len(version_ids))
|
self.assertEqual(16, len(version_ids))
|
||||||
self.assertIn('v2.0', version_ids)
|
self.assertIn('v2.0', version_ids)
|
||||||
self.assertIn('v2.1', version_ids)
|
self.assertIn('v2.1', version_ids)
|
||||||
self.assertIn('v2.2', version_ids)
|
self.assertIn('v2.2', version_ids)
|
||||||
@ -61,6 +61,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
|||||||
self.assertIn('v2.12', version_ids)
|
self.assertIn('v2.12', version_ids)
|
||||||
self.assertIn('v2.13', version_ids)
|
self.assertIn('v2.13', version_ids)
|
||||||
self.assertIn('v2.14', version_ids)
|
self.assertIn('v2.14', version_ids)
|
||||||
|
self.assertIn('v2.15', version_ids)
|
||||||
|
|
||||||
# Each version should have a 'self' 'href' to the API version URL
|
# Each version should have a 'self' 'href' to the API version URL
|
||||||
# [{u'rel': u'self', u'href': u'http://localhost/v2'}]
|
# [{u'rel': u'self', u'href': u'http://localhost/v2'}]
|
||||||
|
@ -2622,7 +2622,8 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
'client_ca_tls_container_ref': None,
|
'client_ca_tls_container_ref': None,
|
||||||
'client_authentication': constants.CLIENT_AUTH_NONE,
|
'client_authentication': constants.CLIENT_AUTH_NONE,
|
||||||
'client_crl_container_ref': None,
|
'client_crl_container_ref': None,
|
||||||
'allowed_cidrs': None
|
'allowed_cidrs': None,
|
||||||
|
'tls_ciphers': None
|
||||||
}
|
}
|
||||||
if create_sni_containers:
|
if create_sni_containers:
|
||||||
create_listener['sni_container_refs'] = create_sni_containers
|
create_listener['sni_container_refs'] = create_sni_containers
|
||||||
@ -2668,6 +2669,8 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
expected_client_crl_container)
|
expected_client_crl_container)
|
||||||
if expected_allowed_cidrs:
|
if expected_allowed_cidrs:
|
||||||
expected_listener['allowed_cidrs'] = expected_allowed_cidrs
|
expected_listener['allowed_cidrs'] = expected_allowed_cidrs
|
||||||
|
if create_protocol == constants.PROTOCOL_TERMINATED_HTTPS:
|
||||||
|
expected_listener['tls_ciphers'] = constants.CIPHERS_OWASP_SUITE_B
|
||||||
|
|
||||||
return create_listener, expected_listener
|
return create_listener, expected_listener
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from octavia_lib.api.drivers import data_models as driver_dm
|
from octavia_lib.api.drivers import data_models as driver_dm
|
||||||
from octavia_lib.api.drivers import exceptions as lib_exceptions
|
from octavia_lib.api.drivers import exceptions as lib_exceptions
|
||||||
|
from octavia_lib.common import constants as lib_constants
|
||||||
|
|
||||||
from octavia.api.drivers import exceptions as driver_exceptions
|
from octavia.api.drivers import exceptions as driver_exceptions
|
||||||
from octavia.api.drivers import utils
|
from octavia.api.drivers import utils
|
||||||
@ -139,6 +140,13 @@ class TestUtils(base.TestCase):
|
|||||||
'flavor_id': 'flavor_id',
|
'flavor_id': 'flavor_id',
|
||||||
'provider': 'noop_driver'}
|
'provider': 'noop_driver'}
|
||||||
ref_listeners = copy.deepcopy(self.sample_data.provider_listeners)
|
ref_listeners = copy.deepcopy(self.sample_data.provider_listeners)
|
||||||
|
# TODO(johnsom) Remove when versions implemented
|
||||||
|
for listener in ref_listeners:
|
||||||
|
delattr(listener, lib_constants.TLS_VERSIONS)
|
||||||
|
expect_pools = copy.deepcopy(self.sample_data.provider_pools,)
|
||||||
|
for pool in expect_pools:
|
||||||
|
delattr(pool, lib_constants.TLS_VERSIONS)
|
||||||
|
delattr(pool, lib_constants.TLS_CIPHERS)
|
||||||
ref_prov_lb_dict = {
|
ref_prov_lb_dict = {
|
||||||
'vip_address': self.sample_data.ip_address,
|
'vip_address': self.sample_data.ip_address,
|
||||||
'admin_state_up': True,
|
'admin_state_up': True,
|
||||||
@ -150,7 +158,7 @@ class TestUtils(base.TestCase):
|
|||||||
'vip_port_id': self.sample_data.port_id,
|
'vip_port_id': self.sample_data.port_id,
|
||||||
'vip_qos_policy_id': self.sample_data.qos_policy_id,
|
'vip_qos_policy_id': self.sample_data.qos_policy_id,
|
||||||
'vip_network_id': self.sample_data.network_id,
|
'vip_network_id': self.sample_data.network_id,
|
||||||
'pools': self.sample_data.provider_pools,
|
'pools': expect_pools,
|
||||||
'flavor': {'shaved_ice': 'cherry'},
|
'flavor': {'shaved_ice': 'cherry'},
|
||||||
'name': 'lb1'}
|
'name': 'lb1'}
|
||||||
vip = data_models.Vip(ip_address=self.sample_data.ip_address,
|
vip = data_models.Vip(ip_address=self.sample_data.ip_address,
|
||||||
@ -211,6 +219,9 @@ class TestUtils(base.TestCase):
|
|||||||
provider_listeners = utils.db_listeners_to_provider_listeners(
|
provider_listeners = utils.db_listeners_to_provider_listeners(
|
||||||
self.sample_data.test_db_listeners)
|
self.sample_data.test_db_listeners)
|
||||||
ref_listeners = copy.deepcopy(self.sample_data.provider_listeners)
|
ref_listeners = copy.deepcopy(self.sample_data.provider_listeners)
|
||||||
|
# TODO(johnsom) Remove when versions implemented
|
||||||
|
for listener in ref_listeners:
|
||||||
|
delattr(listener, lib_constants.TLS_VERSIONS)
|
||||||
self.assertEqual(ref_listeners, provider_listeners)
|
self.assertEqual(ref_listeners, provider_listeners)
|
||||||
|
|
||||||
@mock.patch('oslo_context.context.RequestContext', return_value=None)
|
@mock.patch('oslo_context.context.RequestContext', return_value=None)
|
||||||
@ -250,6 +261,10 @@ class TestUtils(base.TestCase):
|
|||||||
# not any other related fields. So we need to delete them.
|
# not any other related fields. So we need to delete them.
|
||||||
expect_prov = copy.deepcopy(self.sample_data.provider_listener1_dict)
|
expect_prov = copy.deepcopy(self.sample_data.provider_listener1_dict)
|
||||||
expect_pool_prov = copy.deepcopy(self.sample_data.provider_pool1_dict)
|
expect_pool_prov = copy.deepcopy(self.sample_data.provider_pool1_dict)
|
||||||
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_pool_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
|
expect_pool_prov.pop(lib_constants.TLS_CIPHERS)
|
||||||
|
expect_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
expect_prov['default_pool'] = expect_pool_prov
|
expect_prov['default_pool'] = expect_pool_prov
|
||||||
provider_listener = utils.listener_dict_to_provider_dict(
|
provider_listener = utils.listener_dict_to_provider_dict(
|
||||||
self.sample_data.test_listener1_dict)
|
self.sample_data.test_listener1_dict)
|
||||||
@ -283,6 +298,10 @@ class TestUtils(base.TestCase):
|
|||||||
expect_prov = copy.deepcopy(self.sample_data.provider_listener1_dict)
|
expect_prov = copy.deepcopy(self.sample_data.provider_listener1_dict)
|
||||||
expect_pool_prov = copy.deepcopy(self.sample_data.provider_pool1_dict)
|
expect_pool_prov = copy.deepcopy(self.sample_data.provider_pool1_dict)
|
||||||
del expect_pool_prov['tls_container_data']
|
del expect_pool_prov['tls_container_data']
|
||||||
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_pool_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
|
expect_pool_prov.pop(lib_constants.TLS_CIPHERS)
|
||||||
|
expect_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
expect_prov['default_pool'] = expect_pool_prov
|
expect_prov['default_pool'] = expect_pool_prov
|
||||||
del expect_prov['default_tls_container_data']
|
del expect_prov['default_tls_container_data']
|
||||||
del expect_prov['sni_container_data']
|
del expect_prov['sni_container_data']
|
||||||
@ -318,7 +337,11 @@ class TestUtils(base.TestCase):
|
|||||||
'X509 POOL CRL FILE']
|
'X509 POOL CRL FILE']
|
||||||
provider_pool = utils.db_pool_to_provider_pool(
|
provider_pool = utils.db_pool_to_provider_pool(
|
||||||
self.sample_data.db_pool1)
|
self.sample_data.db_pool1)
|
||||||
self.assertEqual(self.sample_data.provider_pool1, provider_pool)
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_prov_pool = copy.deepcopy(self.sample_data.provider_pool1)
|
||||||
|
delattr(expect_prov_pool, lib_constants.TLS_VERSIONS)
|
||||||
|
delattr(expect_prov_pool, lib_constants.TLS_CIPHERS)
|
||||||
|
self.assertEqual(expect_prov_pool, provider_pool)
|
||||||
|
|
||||||
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
@ -333,7 +356,11 @@ class TestUtils(base.TestCase):
|
|||||||
test_db_pool = self.sample_data.db_pool1
|
test_db_pool = self.sample_data.db_pool1
|
||||||
test_db_pool.members = [self.sample_data.db_member1]
|
test_db_pool.members = [self.sample_data.db_member1]
|
||||||
provider_pool = utils.db_pool_to_provider_pool(test_db_pool)
|
provider_pool = utils.db_pool_to_provider_pool(test_db_pool)
|
||||||
self.assertEqual(self.sample_data.provider_pool1, provider_pool)
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_prov_pool = copy.deepcopy(self.sample_data.provider_pool1)
|
||||||
|
delattr(expect_prov_pool, lib_constants.TLS_VERSIONS)
|
||||||
|
delattr(expect_prov_pool, lib_constants.TLS_CIPHERS)
|
||||||
|
self.assertEqual(expect_prov_pool, provider_pool)
|
||||||
|
|
||||||
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
@ -346,7 +373,12 @@ class TestUtils(base.TestCase):
|
|||||||
'X509 POOL CRL FILE']
|
'X509 POOL CRL FILE']
|
||||||
provider_pools = utils.db_pools_to_provider_pools(
|
provider_pools = utils.db_pools_to_provider_pools(
|
||||||
self.sample_data.test_db_pools)
|
self.sample_data.test_db_pools)
|
||||||
self.assertEqual(self.sample_data.provider_pools, provider_pools)
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_prov_pools = copy.deepcopy(self.sample_data.provider_pools)
|
||||||
|
for prov_pool in expect_prov_pools:
|
||||||
|
delattr(prov_pool, lib_constants.TLS_VERSIONS)
|
||||||
|
delattr(prov_pool, lib_constants.TLS_CIPHERS)
|
||||||
|
self.assertEqual(expect_prov_pools, provider_pools)
|
||||||
|
|
||||||
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
@ -362,6 +394,9 @@ class TestUtils(base.TestCase):
|
|||||||
provider_pool_dict = utils.pool_dict_to_provider_dict(
|
provider_pool_dict = utils.pool_dict_to_provider_dict(
|
||||||
self.sample_data.test_pool1_dict)
|
self.sample_data.test_pool1_dict)
|
||||||
provider_pool_dict.pop('crl_container_ref')
|
provider_pool_dict.pop('crl_container_ref')
|
||||||
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
|
expect_prov.pop(lib_constants.TLS_CIPHERS)
|
||||||
self.assertEqual(expect_prov, provider_pool_dict)
|
self.assertEqual(expect_prov, provider_pool_dict)
|
||||||
|
|
||||||
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
@mock.patch('octavia.api.drivers.utils._get_secret_data')
|
||||||
@ -393,6 +428,9 @@ class TestUtils(base.TestCase):
|
|||||||
provider_pool_dict = utils.pool_dict_to_provider_dict(
|
provider_pool_dict = utils.pool_dict_to_provider_dict(
|
||||||
self.sample_data.test_pool1_dict, for_delete=True)
|
self.sample_data.test_pool1_dict, for_delete=True)
|
||||||
provider_pool_dict.pop('crl_container_ref')
|
provider_pool_dict.pop('crl_container_ref')
|
||||||
|
# TODO(johnsom) Remove when versions and ciphers are implemented
|
||||||
|
expect_prov.pop(lib_constants.TLS_VERSIONS)
|
||||||
|
expect_prov.pop(lib_constants.TLS_CIPHERS)
|
||||||
self.assertEqual(expect_prov, provider_pool_dict)
|
self.assertEqual(expect_prov, provider_pool_dict)
|
||||||
|
|
||||||
def test_db_HM_to_provider_HM(self):
|
def test_db_HM_to_provider_HM(self):
|
||||||
|
@ -51,12 +51,13 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
"ssl crt-list {crt_list} "
|
"ssl crt-list {crt_list} "
|
||||||
"ca-file /var/lib/octavia/certs/sample_loadbalancer_id_1/"
|
"ca-file /var/lib/octavia/certs/sample_loadbalancer_id_1/"
|
||||||
"client_ca.pem verify required crl-file /var/lib/octavia/"
|
"client_ca.pem verify required crl-file /var/lib/octavia/"
|
||||||
"certs/sample_loadbalancer_id_1/SHA_ID.pem\n"
|
"certs/sample_loadbalancer_id_1/SHA_ID.pem ciphers {ciphers}\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" default_backend sample_pool_id_1:sample_listener_id_1\n"
|
" default_backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
" timeout client 50000\n").format(
|
" timeout client 50000\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
crt_list=FAKE_CRT_LIST_FILENAME)
|
crt_list=FAKE_CRT_LIST_FILENAME,
|
||||||
|
ciphers=constants.CIPHERS_OWASP_SUITE_B)
|
||||||
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
|
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" balance roundrobin\n"
|
" balance roundrobin\n"
|
||||||
@ -94,6 +95,56 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_tls_no_sni(self):
|
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-list {crt_list}"
|
||||||
|
" ciphers {ciphers}\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,
|
||||||
|
crt_list=FAKE_CRT_LIST_FILENAME,
|
||||||
|
ciphers=constants.CIPHERS_OWASP_SUITE_B)
|
||||||
|
be = ("backend sample_pool_id_1:sample_listener_id_1\n"
|
||||||
|
" mode http\n"
|
||||||
|
" balance roundrobin\n"
|
||||||
|
" cookie SRV insert indirect nocache\n"
|
||||||
|
" timeout check 31s\n"
|
||||||
|
" option httpchk GET /index.html HTTP/1.0\\r\\n\n"
|
||||||
|
" http-check expect rstatus 418\n"
|
||||||
|
" fullconn {maxconn}\n"
|
||||||
|
" option allbackups\n"
|
||||||
|
" timeout connect 5000\n"
|
||||||
|
" timeout server 50000\n"
|
||||||
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_1\n"
|
||||||
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_2\n\n").format(
|
||||||
|
maxconn=constants.HAPROXY_MAX_MAXCONN)
|
||||||
|
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")})
|
||||||
|
self.assertEqual(
|
||||||
|
sample_configs_combined.sample_base_expected_config(
|
||||||
|
frontend=fe, backend=be),
|
||||||
|
rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_tls_no_ciphers(self):
|
||||||
conf = oslo_fixture.Config(cfg.CONF)
|
conf = oslo_fixture.Config(cfg.CONF)
|
||||||
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
|
conf.config(group="haproxy_amphora", base_cert_dir='/fake_cert_dir')
|
||||||
FAKE_CRT_LIST_FILENAME = os.path.join(
|
FAKE_CRT_LIST_FILENAME = os.path.join(
|
||||||
@ -129,7 +180,7 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
sample_configs_combined.sample_amphora_tuple(),
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
[sample_configs_combined.sample_listener_tuple(
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
proto='TERMINATED_HTTPS', tls=True)],
|
proto='TERMINATED_HTTPS', tls=True, tls_ciphers=None)],
|
||||||
tls_certs={'cont_id_1':
|
tls_certs={'cont_id_1':
|
||||||
sample_configs_combined.sample_tls_container_tuple(
|
sample_configs_combined.sample_tls_container_tuple(
|
||||||
id='tls_container_id',
|
id='tls_container_id',
|
||||||
@ -1121,7 +1172,8 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
fe = ("frontend sample_listener_id_1\n"
|
fe = ("frontend sample_listener_id_1\n"
|
||||||
" maxconn 1000000\n"
|
" maxconn 1000000\n"
|
||||||
" redirect scheme https if !{ ssl_fc }\n"
|
" redirect scheme https if !{ ssl_fc }\n"
|
||||||
" bind 10.0.0.2:443\n"
|
" bind 10.0.0.2:443 ciphers " +
|
||||||
|
constants.CIPHERS_OWASP_SUITE_B + "\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" acl sample_l7rule_id_1 path -m beg /api\n"
|
" acl sample_l7rule_id_1 path -m beg /api\n"
|
||||||
" use_backend sample_pool_id_2:sample_listener_id_1"
|
" use_backend sample_pool_id_2:sample_listener_id_1"
|
||||||
|
@ -599,10 +599,13 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
pool_ca_cert=False, pool_crl=False,
|
pool_ca_cert=False, pool_crl=False,
|
||||||
tls_enabled=False, hm_host_http_check=False,
|
tls_enabled=False, hm_host_http_check=False,
|
||||||
id='sample_listener_id_1', recursive_nest=False,
|
id='sample_listener_id_1', recursive_nest=False,
|
||||||
provisioning_status=constants.ACTIVE):
|
provisioning_status=constants.ACTIVE,
|
||||||
|
tls_ciphers=constants.CIPHERS_OWASP_SUITE_B):
|
||||||
proto = 'HTTP' if proto is None else proto
|
proto = 'HTTP' if proto is None else proto
|
||||||
if be_proto is None:
|
if be_proto is None:
|
||||||
be_proto = 'HTTP' if proto == 'TERMINATED_HTTPS' else proto
|
be_proto = 'HTTP' if proto == 'TERMINATED_HTTPS' else proto
|
||||||
|
if proto != constants.PROTOCOL_TERMINATED_HTTPS:
|
||||||
|
tls_ciphers = None
|
||||||
topology = 'SINGLE' if topology is None else topology
|
topology = 'SINGLE' if topology is None else topology
|
||||||
port = '443' if proto in ['HTTPS', 'TERMINATED_HTTPS'] else '80'
|
port = '443' if proto in ['HTTPS', 'TERMINATED_HTTPS'] else '80'
|
||||||
peer_port = 1024 if peer_port is None else peer_port
|
peer_port = 1024 if peer_port is None else peer_port
|
||||||
@ -616,7 +619,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
'timeout_member_connect, timeout_member_data, '
|
'timeout_member_connect, timeout_member_data, '
|
||||||
'timeout_tcp_inspect, client_ca_tls_certificate_id, '
|
'timeout_tcp_inspect, client_ca_tls_certificate_id, '
|
||||||
'client_ca_tls_certificate, client_authentication, '
|
'client_ca_tls_certificate, client_authentication, '
|
||||||
'client_crl_container_id, provisioning_status')
|
'client_crl_container_id, provisioning_status, '
|
||||||
|
'tls_ciphers')
|
||||||
if l7:
|
if l7:
|
||||||
pools = [
|
pools = [
|
||||||
sample_pool_tuple(
|
sample_pool_tuple(
|
||||||
@ -727,6 +731,7 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
constants.CLIENT_AUTH_NONE),
|
constants.CLIENT_AUTH_NONE),
|
||||||
client_crl_container_id='cont_id_crl' if client_crl_cert else '',
|
client_crl_container_id='cont_id_crl' if client_crl_cert else '',
|
||||||
provisioning_status=provisioning_status,
|
provisioning_status=provisioning_status,
|
||||||
|
tls_ciphers=tls_ciphers
|
||||||
)
|
)
|
||||||
if recursive_nest:
|
if recursive_nest:
|
||||||
listener.load_balancer.listeners.append(listener)
|
listener.load_balancer.listeners.append(listener)
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
HTTPS-terminated listeners can now be individually configured with an OpenSSL cipher string.
|
||||||
|
The default cipher string for new listeners can be specified with ``default_tls_ciphers``
|
||||||
|
in ``octavia.conf``. The built-in default is OWASP's "Suite B" recommendation. (https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html)
|
||||||
|
Existing listeners will be unaffected.
|
@ -44,7 +44,7 @@ tenacity>=5.0.4 # Apache-2.0
|
|||||||
distro>=1.2.0 # Apache-2.0
|
distro>=1.2.0 # Apache-2.0
|
||||||
jsonschema>=2.6.0 # MIT
|
jsonschema>=2.6.0 # MIT
|
||||||
debtcollector>=1.19.0 # Apache-2.0
|
debtcollector>=1.19.0 # Apache-2.0
|
||||||
octavia-lib>=1.5.0 # Apache-2.0
|
octavia-lib>=2.0.0 # Apache-2.0
|
||||||
netaddr>=0.7.19 # BSD
|
netaddr>=0.7.19 # BSD
|
||||||
simplejson>=3.13.2 # MIT
|
simplejson>=3.13.2 # MIT
|
||||||
setproctitle>=1.1.10 # BSD
|
setproctitle>=1.1.10 # BSD
|
||||||
|
Loading…
Reference in New Issue
Block a user