Add TLS version configuration for pools
Add field tls_versions to pools for restricing TLS versions used. This is a colon-separated string of versions to be used. Available values (as defined in octavia-lib): SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 Add default_pool_tls_versions in octavia.conf Note: TLSv1.3 connections will use haproxy's default ciphers instead of the listener's tls_ciphers field Change-Id: I480b7fb9756d98ba9dbcdfd1d4b193ce6868e291 Story: 2006733 Task: 37173 Depends-On: Ic33d9b9a256490ae1b048cdfd2475d6340509fdb
This commit is contained in:
parent
6aad5d8b9f
commit
9a6da86481
@ -1 +1 @@
|
|||||||
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"pool":{"lb_algorithm":"ROUND_ROBIN","protocol":"HTTP","description":"Super Round Robin Pool","admin_state_up":true,"session_persistence":{"cookie_name":"ChocolateChip","type":"APP_COOKIE"},"listener_id":"023f2e34-7806-443b-bfae-16c324569a3d","name":"super-pool","tags":["test_tag"],"tls_container_ref":"http://198.51.100.10:9311/v1/containers/4073846f-1d5e-42e1-a4cf-a7046419d0e6","ca_tls_container_ref":"http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb","crl_container_ref":"http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b","tls_enabled":true,"tls_ciphers":"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"}}' http://198.51.100.10:9876/v2/lbaas/pools
|
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"pool":{"lb_algorithm":"ROUND_ROBIN","protocol":"HTTP","description":"Super Round Robin Pool","admin_state_up":true,"session_persistence":{"cookie_name":"ChocolateChip","type":"APP_COOKIE"},"listener_id":"023f2e34-7806-443b-bfae-16c324569a3d","name":"super-pool","tags":["test_tag"],"tls_container_ref":"http://198.51.100.10:9311/v1/containers/4073846f-1d5e-42e1-a4cf-a7046419d0e6","ca_tls_container_ref":"http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb","crl_container_ref":"http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b","tls_enabled":true,"tls_ciphers":"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256", "tls_versions": ["TLSv1.2", "TLSv1.3"]}}' http://198.51.100.10:9876/v2/lbaas/pools
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
||||||
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
||||||
"tls_enabled": true,
|
"tls_enabled": true,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
||||||
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
||||||
"tls_enabled": true,
|
"tls_enabled": true,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
||||||
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
||||||
"tls_enabled": false,
|
"tls_enabled": false,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"pool":{"lb_algorithm":"LEAST_CONNECTIONS","session_persistence":{"type":"SOURCE_IP"},"description":"second description","name":"second_name","tags":["updated_tag"],"tls_container_ref":"http://198.51.100.10:9311/v1/containers/c1cd501d-3cf9-4873-a11b-a74bebcde929","ca_tls_container_ref":null,"crl_container_ref":null,"tls_enabled":false,"tls_ciphers":"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"}}' http://198.51.100.10:9876/v2/lbaas/pools/4029d267-3983-4224-a3d0-afb3fe16a2cd
|
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"pool":{"lb_algorithm":"LEAST_CONNECTIONS","session_persistence":{"type":"SOURCE_IP"},"description":"second description","name":"second_name","tags":["updated_tag"],"tls_container_ref":"http://198.51.100.10:9311/v1/containers/c1cd501d-3cf9-4873-a11b-a74bebcde929","ca_tls_container_ref":null,"crl_container_ref":null,"tls_enabled":false,"tls_ciphers":"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256", "tls_versions": ["TLSv1.2", "TLSv1.3"]}}' http://198.51.100.10:9876/v2/lbaas/pools/4029d267-3983-4224-a3d0-afb3fe16a2cd
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"ca_tls_container_ref": null,
|
"ca_tls_container_ref": null,
|
||||||
"crl_container_ref": null,
|
"crl_container_ref": null,
|
||||||
"tls_enabled": false,
|
"tls_enabled": false,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"ca_tls_container_ref": null,
|
"ca_tls_container_ref": null,
|
||||||
"crl_container_ref": null,
|
"crl_container_ref": null,
|
||||||
"tls_enabled": false,
|
"tls_enabled": false,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
"ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/5f0d5540-fae6-4646-85d6-8a84883807fb",
|
||||||
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
"crl_container_ref": "http://198.51.100.10:9311/v1/containers/6faf0a01-6892-454c-aaac-650282820c0b",
|
||||||
"tls_enabled": true,
|
"tls_enabled": true,
|
||||||
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"
|
"tls_ciphers": "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256",
|
||||||
|
"tls_versions": ["TLSv1.2", "TLSv1.3"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ Response Parameters
|
|||||||
- tls_ciphers: tls_ciphers
|
- tls_ciphers: tls_ciphers
|
||||||
- tls_container_ref: tls_container_ref
|
- tls_container_ref: tls_container_ref
|
||||||
- tls_enabled: tls_enabled
|
- tls_enabled: tls_enabled
|
||||||
|
- tls_versions: tls_versions
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -182,6 +183,7 @@ Request
|
|||||||
- tls_enabled: tls_enabled-optional
|
- tls_enabled: tls_enabled-optional
|
||||||
- tls_ciphers: tls_ciphers-optional
|
- tls_ciphers: tls_ciphers-optional
|
||||||
- tls_container_ref: tls_container_ref-optional
|
- tls_container_ref: tls_container_ref-optional
|
||||||
|
- tls_versions: tls_versions-optional
|
||||||
|
|
||||||
.. _session_persistence:
|
.. _session_persistence:
|
||||||
|
|
||||||
@ -264,6 +266,7 @@ Response Parameters
|
|||||||
- tls_enabled: tls_enabled
|
- tls_enabled: tls_enabled
|
||||||
- tls_ciphers: tls_ciphers
|
- tls_ciphers: tls_ciphers
|
||||||
- tls_container_ref: tls_container_ref
|
- tls_container_ref: tls_container_ref
|
||||||
|
- tls_versions: tls_versions
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -336,6 +339,7 @@ Response Parameters
|
|||||||
- tls_enabled: tls_enabled
|
- tls_enabled: tls_enabled
|
||||||
- tls_ciphers: tls_ciphers
|
- tls_ciphers: tls_ciphers
|
||||||
- tls_container_ref: tls_container_ref
|
- tls_container_ref: tls_container_ref
|
||||||
|
- tls_versions: tls_versions
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
@ -389,6 +393,7 @@ Request
|
|||||||
- tls_enabled: tls_enabled-optional
|
- tls_enabled: tls_enabled-optional
|
||||||
- tls_ciphers: tls_ciphers-optional
|
- tls_ciphers: tls_ciphers-optional
|
||||||
- tls_container_ref: tls_container_ref-optional
|
- tls_container_ref: tls_container_ref-optional
|
||||||
|
- tls_versions: tls_versions-optional
|
||||||
|
|
||||||
Request Example
|
Request Example
|
||||||
---------------
|
---------------
|
||||||
@ -428,6 +433,7 @@ Response Parameters
|
|||||||
- tls_enabled: tls_enabled
|
- tls_enabled: tls_enabled
|
||||||
- tls_ciphers: tls_ciphers
|
- tls_ciphers: tls_ciphers
|
||||||
- tls_container_ref: tls_container_ref
|
- tls_container_ref: tls_container_ref
|
||||||
|
- tls_versions: tls_versions
|
||||||
- updated_at: updated_at
|
- updated_at: updated_at
|
||||||
|
|
||||||
Response Example
|
Response Example
|
||||||
|
@ -76,6 +76,9 @@
|
|||||||
# listeners. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
# listeners. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
||||||
# default_listener_tls_versions = TLSv1.2, TLSv1.3
|
# default_listener_tls_versions = TLSv1.2, TLSv1.3
|
||||||
|
|
||||||
|
# List of default TLS versions to be used on new TLS-enabled
|
||||||
|
# pools. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
|
||||||
|
# default_pool_tls_versions = TLSv1.2, TLSv1.3
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# This line MUST be changed to actually run the plugin.
|
# This line MUST be changed to actually run the plugin.
|
||||||
|
@ -116,6 +116,9 @@ class RootController(object):
|
|||||||
self._add_a_version(versions, 'v2.16', 'v2', 'SUPPORTED',
|
self._add_a_version(versions, 'v2.16', 'v2', 'SUPPORTED',
|
||||||
'2020-03-15T00:00:00Z', host_url)
|
'2020-03-15T00:00:00Z', host_url)
|
||||||
# Listener TLS versions
|
# Listener TLS versions
|
||||||
self._add_a_version(versions, 'v2.17', 'v2', 'CURRENT',
|
self._add_a_version(versions, 'v2.17', 'v2', 'SUPPORTED',
|
||||||
'2020-04-29T00:00:00Z', host_url)
|
'2020-04-29T00:00:00Z', host_url)
|
||||||
|
# Pool TLS versions
|
||||||
|
self._add_a_version(versions, 'v2.18', 'v2', 'CURRENT',
|
||||||
|
'2020-04-29T01:00:00Z', host_url)
|
||||||
return {'versions': versions}
|
return {'versions': versions}
|
||||||
|
@ -131,6 +131,10 @@ 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']:
|
||||||
|
validate.check_tls_version_list(pool_dict['tls_versions'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.repositories.create_pool_on_load_balancer(
|
return self.repositories.create_pool_on_load_balancer(
|
||||||
lock_session, pool_dict,
|
lock_session, pool_dict,
|
||||||
@ -395,6 +399,10 @@ 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:
|
||||||
|
validate.check_tls_version_list(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)
|
||||||
def put(self, id, pool_):
|
def put(self, id, pool_):
|
||||||
|
@ -84,6 +84,7 @@ class PoolResponse(BasePoolType):
|
|||||||
crl_container_ref = wtypes.wsattr(wtypes.StringType())
|
crl_container_ref = wtypes.wsattr(wtypes.StringType())
|
||||||
tls_enabled = wtypes.wsattr(bool)
|
tls_enabled = wtypes.wsattr(bool)
|
||||||
tls_ciphers = wtypes.StringType()
|
tls_ciphers = wtypes.StringType()
|
||||||
|
tls_versions = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType()))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data_model(cls, data_model, children=False):
|
def from_data_model(cls, data_model, children=False):
|
||||||
@ -115,6 +116,8 @@ class PoolResponse(BasePoolType):
|
|||||||
pool.members = [
|
pool.members = [
|
||||||
member_model.from_data_model(i) for i in data_model.members]
|
member_model.from_data_model(i) for i in data_model.members]
|
||||||
|
|
||||||
|
pool.tls_versions = data_model.tls_versions
|
||||||
|
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
|
||||||
@ -160,6 +163,8 @@ class PoolPOST(BasePoolType):
|
|||||||
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||||
tls_enabled = wtypes.wsattr(bool, default=False)
|
tls_enabled = wtypes.wsattr(bool, default=False)
|
||||||
tls_ciphers = wtypes.StringType(max_length=2048)
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
tls_versions = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(
|
||||||
|
max_length=32)))
|
||||||
|
|
||||||
|
|
||||||
class PoolRootPOST(types.BaseType):
|
class PoolRootPOST(types.BaseType):
|
||||||
@ -180,6 +185,8 @@ class PoolPUT(BasePoolType):
|
|||||||
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||||
tls_enabled = wtypes.wsattr(bool)
|
tls_enabled = wtypes.wsattr(bool)
|
||||||
tls_ciphers = wtypes.StringType(max_length=2048)
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
tls_versions = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(
|
||||||
|
max_length=32)))
|
||||||
|
|
||||||
|
|
||||||
class PoolRootPut(types.BaseType):
|
class PoolRootPut(types.BaseType):
|
||||||
@ -203,6 +210,8 @@ class PoolSingleCreate(BasePoolType):
|
|||||||
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
crl_container_ref = wtypes.wsattr(wtypes.StringType(max_length=255))
|
||||||
tls_enabled = wtypes.wsattr(bool, default=False)
|
tls_enabled = wtypes.wsattr(bool, default=False)
|
||||||
tls_ciphers = wtypes.StringType(max_length=2048)
|
tls_ciphers = wtypes.StringType(max_length=2048)
|
||||||
|
tls_versions = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(
|
||||||
|
max_length=32)))
|
||||||
|
|
||||||
|
|
||||||
class PoolStatusResponse(BasePoolType):
|
class PoolStatusResponse(BasePoolType):
|
||||||
|
@ -119,7 +119,11 @@ api_opts = [
|
|||||||
cfg.ListOpt('default_listener_tls_versions',
|
cfg.ListOpt('default_listener_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 '
|
||||||
'listeners.'))
|
'listeners.')),
|
||||||
|
cfg.ListOpt('default_pool_tls_versions',
|
||||||
|
default=constants.TLS_VERSIONS_OWASP_SUITE_B,
|
||||||
|
help=_('List of TLS versions to use for new TLS-enabled '
|
||||||
|
'pools.'))
|
||||||
]
|
]
|
||||||
|
|
||||||
# Options only used by the amphora agent
|
# Options only used by the amphora agent
|
||||||
|
@ -278,7 +278,7 @@ class Pool(BaseDataModel):
|
|||||||
created_at=None, updated_at=None, provisioning_status=None,
|
created_at=None, updated_at=None, provisioning_status=None,
|
||||||
tags=None, tls_certificate_id=None,
|
tags=None, tls_certificate_id=None,
|
||||||
ca_tls_certificate_id=None, crl_container_id=None,
|
ca_tls_certificate_id=None, crl_container_id=None,
|
||||||
tls_enabled=None, tls_ciphers=None):
|
tls_enabled=None, tls_ciphers=None, tls_versions=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -303,6 +303,7 @@ class Pool(BaseDataModel):
|
|||||||
self.crl_container_id = crl_container_id
|
self.crl_container_id = crl_container_id
|
||||||
self.tls_enabled = tls_enabled
|
self.tls_enabled = tls_enabled
|
||||||
self.tls_ciphers = tls_ciphers
|
self.tls_ciphers = tls_ciphers
|
||||||
|
self.tls_versions = tls_versions
|
||||||
|
|
||||||
def update(self, update_dict):
|
def update(self, update_dict):
|
||||||
for key, value in update_dict.items():
|
for key, value in update_dict.items():
|
||||||
|
@ -353,8 +353,11 @@ class JinjaTemplater(object):
|
|||||||
if (pool.tls_certificate_id and pool_tls_certs and
|
if (pool.tls_certificate_id and pool_tls_certs and
|
||||||
pool_tls_certs.get('client_cert')):
|
pool_tls_certs.get('client_cert')):
|
||||||
ret_value['client_cert'] = pool_tls_certs.get('client_cert')
|
ret_value['client_cert'] = pool_tls_certs.get('client_cert')
|
||||||
if pool.tls_enabled is True and pool.tls_ciphers is not None:
|
if pool.tls_enabled is True:
|
||||||
|
if pool.tls_ciphers is not None:
|
||||||
ret_value['tls_ciphers'] = pool.tls_ciphers
|
ret_value['tls_ciphers'] = pool.tls_ciphers
|
||||||
|
if pool.tls_versions is not None:
|
||||||
|
ret_value['tls_versions'] = pool.tls_versions
|
||||||
if (pool.ca_tls_certificate_id and pool_tls_certs and
|
if (pool.ca_tls_certificate_id and pool_tls_certs and
|
||||||
pool_tls_certs.get('ca_cert')):
|
pool_tls_certs.get('ca_cert')):
|
||||||
ret_value['ca_cert'] = pool_tls_certs.get('ca_cert')
|
ret_value['ca_cert'] = pool_tls_certs.get('ca_cert')
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
{% for listener in loadbalancer.listeners if listener.enabled %}
|
{% for listener in loadbalancer.listeners if listener.enabled %}
|
||||||
{{- frontend_macro(constants, lib_consts, listener, loadbalancer.vip_address) }}
|
{{- frontend_macro(constants, lib_consts, listener, loadbalancer.vip_address) }}
|
||||||
{% for pool in listener.pools if pool.enabled %}
|
{% for pool in listener.pools if pool.enabled %}
|
||||||
{{- backend_macro(constants, listener, pool, loadbalancer) }}
|
{{- backend_macro(constants, lib_consts, listener, pool, loadbalancer) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -180,7 +180,7 @@ frontend {{ listener.id }}
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
{% macro member_macro(constants, pool, member) %}
|
{% macro member_macro(constants, lib_consts, pool, member) %}
|
||||||
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
||||||
{% if member.monitor_address %}
|
{% if member.monitor_address %}
|
||||||
{% set monitor_addr_opt = " addr %s"|format(member.monitor_address) %}
|
{% set monitor_addr_opt = " addr %s"|format(member.monitor_address) %}
|
||||||
@ -254,15 +254,33 @@ frontend {{ listener.id }}
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% set ciphers_opt = "" %}
|
{% set ciphers_opt = "" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ "server %s %s:%d weight %s%s%s%s%s%s%s%s%s%s%s%s%s"|e|format(
|
{% set tls_versions_opt = "" %}
|
||||||
|
{% if pool.tls_versions is defined %}
|
||||||
|
{% if lib_consts.SSL_VERSION_3 not in pool.tls_versions %}
|
||||||
|
{% set tls_versions_opt = tls_versions_opt + " no-sslv3" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if lib_consts.TLS_VERSION_1 not in pool.tls_versions %}
|
||||||
|
{% set tls_versions_opt = tls_versions_opt + " no-tlsv10" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if lib_consts.TLS_VERSION_1_1 not in pool.tls_versions %}
|
||||||
|
{% set tls_versions_opt = tls_versions_opt + " no-tlsv11" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if lib_consts.TLS_VERSION_1_2 not in pool.tls_versions %}
|
||||||
|
{% set tls_versions_opt = tls_versions_opt + " no-tlsv12" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if lib_consts.TLS_VERSION_1_3 not in pool.tls_versions %}
|
||||||
|
{% set tls_versions_opt = tls_versions_opt + " no-tlsv13" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{{ "server %s %s:%d weight %s%s%s%s%s%s%s%s%s%s%s%s%s%s"|e|format(
|
||||||
member.id, member.address, member.protocol_port, member.weight,
|
member.id, member.address, member.protocol_port, member.weight,
|
||||||
hm_opt, persistence_opt, proxy_protocol_opt, member_backup_opt,
|
hm_opt, persistence_opt, proxy_protocol_opt, member_backup_opt,
|
||||||
member_enabled_opt, def_opt_prefix, def_crt_opt, ca_opt, crl_opt,
|
member_enabled_opt, def_opt_prefix, def_crt_opt, ca_opt, crl_opt,
|
||||||
def_verify_opt, def_sni_opt, ciphers_opt)|trim() }}
|
def_verify_opt, def_sni_opt, ciphers_opt, tls_versions_opt)|trim() }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
{% macro backend_macro(constants, listener, pool, loadbalancer) %}
|
{% macro backend_macro(constants, lib_consts, listener, pool, loadbalancer) %}
|
||||||
backend {{ pool.id }}:{{ listener.id }}
|
backend {{ pool.id }}:{{ listener.id }}
|
||||||
{% if pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() %}
|
{% if pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() %}
|
||||||
mode {{ listener.protocol_mode }}
|
mode {{ listener.protocol_mode }}
|
||||||
@ -390,6 +408,6 @@ backend {{ pool.id }}:{{ listener.id }}
|
|||||||
timeout connect {{ listener.timeout_member_connect }}
|
timeout connect {{ listener.timeout_member_connect }}
|
||||||
timeout server {{ listener.timeout_member_data }}
|
timeout server {{ listener.timeout_member_data }}
|
||||||
{% for member in pool.members %}
|
{% for member in pool.members %}
|
||||||
{{- member_macro(constants, pool, member) -}}
|
{{- member_macro(constants, lib_consts, pool, member) -}}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% 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 pool tls versions column
|
||||||
|
|
||||||
|
Revision ID: d3c8a090f3de
|
||||||
|
Revises: e5493ae5f9a7
|
||||||
|
Create Date: 2020-04-21 13:17:10.861932
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'd3c8a090f3de'
|
||||||
|
down_revision = 'e5493ae5f9a7'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column(
|
||||||
|
'pool',
|
||||||
|
sa.Column('tls_versions', sa.String(512), nullable=True)
|
||||||
|
)
|
@ -338,6 +338,7 @@ class Pool(base_models.BASE, base_models.IdMixin, base_models.ProjectMixin,
|
|||||||
crl_container_id = sa.Column(sa.String(255), nullable=True)
|
crl_container_id = sa.Column(sa.String(255), nullable=True)
|
||||||
tls_enabled = sa.Column(sa.Boolean, default=False, nullable=False)
|
tls_enabled = sa.Column(sa.Boolean, default=False, nullable=False)
|
||||||
tls_ciphers = sa.Column(sa.String(2048), nullable=True)
|
tls_ciphers = sa.Column(sa.String(2048), nullable=True)
|
||||||
|
tls_versions = sa.Column(ScalarListType(), nullable=True)
|
||||||
|
|
||||||
# This property should be a unique list of any listeners that reference
|
# This property should be a unique list of any listeners that reference
|
||||||
# this pool as its default_pool and any listeners referenced by enabled
|
# this pool as its default_pool and any listeners referenced by enabled
|
||||||
|
@ -174,8 +174,12 @@ def create_pool(pool_dict, lb_id=None):
|
|||||||
prepped_members = []
|
prepped_members = []
|
||||||
for member_dict in pool_dict.get('members'):
|
for member_dict in pool_dict.get('members'):
|
||||||
prepped_members.append(create_member(member_dict, pool_dict['id']))
|
prepped_members.append(create_member(member_dict, pool_dict['id']))
|
||||||
if pool_dict['tls_enabled'] is True and pool_dict['tls_ciphers'] is None:
|
if pool_dict['tls_enabled'] is True:
|
||||||
|
if pool_dict['tls_ciphers'] is None:
|
||||||
pool_dict['tls_ciphers'] = CONF.api_settings.default_pool_ciphers
|
pool_dict['tls_ciphers'] = CONF.api_settings.default_pool_ciphers
|
||||||
|
if pool_dict['tls_versions'] is None:
|
||||||
|
pool_dict['tls_versions'] = (
|
||||||
|
CONF.api_settings.default_pool_tls_versions)
|
||||||
pool_dict[constants.PROVISIONING_STATUS] = constants.PENDING_CREATE
|
pool_dict[constants.PROVISIONING_STATUS] = constants.PENDING_CREATE
|
||||||
pool_dict[constants.OPERATING_STATUS] = constants.OFFLINE
|
pool_dict[constants.OPERATING_STATUS] = constants.OFFLINE
|
||||||
return pool_dict
|
return pool_dict
|
||||||
|
@ -248,7 +248,9 @@ class SampleDriverDataModels(object):
|
|||||||
constants.CA_TLS_CERTIFICATE_ID: self.pool_ca_container_ref,
|
constants.CA_TLS_CERTIFICATE_ID: self.pool_ca_container_ref,
|
||||||
constants.CRL_CONTAINER_ID: self.pool_crl_container_ref,
|
constants.CRL_CONTAINER_ID: self.pool_crl_container_ref,
|
||||||
lib_consts.TLS_ENABLED: True,
|
lib_consts.TLS_ENABLED: True,
|
||||||
lib_consts.TLS_CIPHERS: None}
|
lib_consts.TLS_CIPHERS: None,
|
||||||
|
lib_consts.TLS_VERSIONS: None
|
||||||
|
}
|
||||||
|
|
||||||
self.test_pool1_dict.update(self._common_test_dict)
|
self.test_pool1_dict.update(self._common_test_dict)
|
||||||
|
|
||||||
|
@ -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(18, len(version_ids))
|
self.assertEqual(19, 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)
|
||||||
@ -64,6 +64,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
|||||||
self.assertIn('v2.15', version_ids)
|
self.assertIn('v2.15', version_ids)
|
||||||
self.assertIn('v2.16', version_ids)
|
self.assertIn('v2.16', version_ids)
|
||||||
self.assertIn('v2.17', version_ids)
|
self.assertIn('v2.17', version_ids)
|
||||||
|
self.assertIn('v2.18', 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'}]
|
||||||
|
@ -185,7 +185,8 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
|
|||||||
'provisioning_status': constants.ACTIVE,
|
'provisioning_status': constants.ACTIVE,
|
||||||
'tags': ['test_tag'],
|
'tags': ['test_tag'],
|
||||||
'tls_certificate_id': uuidutils.generate_uuid(),
|
'tls_certificate_id': uuidutils.generate_uuid(),
|
||||||
'tls_enabled': False, 'tls_ciphers': None}
|
'tls_enabled': False, 'tls_ciphers': None,
|
||||||
|
'tls_versions': None}
|
||||||
pool_dm = self.repos.create_pool_on_load_balancer(
|
pool_dm = self.repos.create_pool_on_load_balancer(
|
||||||
self.session, pool, listener_id=self.listener.id)
|
self.session, pool, listener_id=self.listener.id)
|
||||||
pool_dm_dict = pool_dm.to_dict()
|
pool_dm_dict = pool_dm.to_dict()
|
||||||
@ -218,7 +219,8 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
|
|||||||
'tags': ['test_tag'],
|
'tags': ['test_tag'],
|
||||||
'tls_certificate_id': uuidutils.generate_uuid(),
|
'tls_certificate_id': uuidutils.generate_uuid(),
|
||||||
'tls_enabled': False,
|
'tls_enabled': False,
|
||||||
'tls_ciphers': None}
|
'tls_ciphers': None,
|
||||||
|
'tls_versions': None}
|
||||||
sp = {'type': constants.SESSION_PERSISTENCE_HTTP_COOKIE,
|
sp = {'type': constants.SESSION_PERSISTENCE_HTTP_COOKIE,
|
||||||
'cookie_name': 'cookie_monster',
|
'cookie_name': 'cookie_monster',
|
||||||
'pool_id': pool['id'],
|
'pool_id': pool['id'],
|
||||||
@ -262,7 +264,8 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
|
|||||||
'id': uuidutils.generate_uuid(),
|
'id': uuidutils.generate_uuid(),
|
||||||
'provisioning_status': constants.ACTIVE,
|
'provisioning_status': constants.ACTIVE,
|
||||||
'tags': ['test_tag'], 'tls_enabled': False,
|
'tags': ['test_tag'], 'tls_enabled': False,
|
||||||
'tls_ciphers': None}
|
'tls_ciphers': None,
|
||||||
|
'tls_versions': None}
|
||||||
pool_dm = self.repos.create_pool_on_load_balancer(
|
pool_dm = self.repos.create_pool_on_load_balancer(
|
||||||
self.session, pool, listener_id=self.listener.id)
|
self.session, pool, listener_id=self.listener.id)
|
||||||
update_pool = {'protocol': constants.PROTOCOL_TCP, 'name': 'up_pool'}
|
update_pool = {'protocol': constants.PROTOCOL_TCP, 'name': 'up_pool'}
|
||||||
@ -297,7 +300,8 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
|
|||||||
'provisioning_status': constants.ACTIVE,
|
'provisioning_status': constants.ACTIVE,
|
||||||
'tags': ['test_tag'],
|
'tags': ['test_tag'],
|
||||||
'tls_certificate_id': uuidutils.generate_uuid(),
|
'tls_certificate_id': uuidutils.generate_uuid(),
|
||||||
'tls_enabled': False, 'tls_ciphers': None}
|
'tls_enabled': False, 'tls_ciphers': None,
|
||||||
|
'tls_versions': None}
|
||||||
sp = {'type': constants.SESSION_PERSISTENCE_HTTP_COOKIE,
|
sp = {'type': constants.SESSION_PERSISTENCE_HTTP_COOKIE,
|
||||||
'cookie_name': 'cookie_monster',
|
'cookie_name': 'cookie_monster',
|
||||||
'pool_id': pool['id'],
|
'pool_id': pool['id'],
|
||||||
@ -401,7 +405,8 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
|
|||||||
'project_id': uuidutils.generate_uuid(),
|
'project_id': uuidutils.generate_uuid(),
|
||||||
'id': uuidutils.generate_uuid(),
|
'id': uuidutils.generate_uuid(),
|
||||||
'provisioning_status': constants.ACTIVE,
|
'provisioning_status': constants.ACTIVE,
|
||||||
'tls_enabled': False, 'tls_ciphers': None}
|
'tls_enabled': False, 'tls_ciphers': None,
|
||||||
|
'tls_versions': None}
|
||||||
pool_dm = self.repos.create_pool_on_load_balancer(
|
pool_dm = self.repos.create_pool_on_load_balancer(
|
||||||
self.session, pool, listener_id=self.listener.id)
|
self.session, pool, listener_id=self.listener.id)
|
||||||
update_pool = {'tls_certificate_id': uuidutils.generate_uuid()}
|
update_pool = {'tls_certificate_id': uuidutils.generate_uuid()}
|
||||||
|
@ -16,7 +16,6 @@ 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 utils
|
from octavia.api.drivers import utils
|
||||||
from octavia.common import constants
|
from octavia.common import constants
|
||||||
@ -126,10 +125,6 @@ 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
|
|
||||||
expect_pools = copy.deepcopy(self.sample_data.provider_pools,)
|
|
||||||
for pool in expect_pools:
|
|
||||||
delattr(pool, lib_constants.TLS_VERSIONS)
|
|
||||||
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,
|
||||||
@ -141,7 +136,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': expect_pools,
|
'pools': self.sample_data.provider_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,
|
||||||
@ -241,8 +236,6 @@ 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_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)
|
||||||
@ -276,8 +269,6 @@ 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_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']
|
||||||
@ -313,10 +304,7 @@ 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)
|
||||||
# TODO(johnsom) Remove when versions and ciphers are implemented
|
self.assertEqual(self.sample_data.provider_pool1, provider_pool)
|
||||||
expect_prov_pool = copy.deepcopy(self.sample_data.provider_pool1)
|
|
||||||
delattr(expect_prov_pool, lib_constants.TLS_VERSIONS)
|
|
||||||
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')
|
||||||
@ -331,10 +319,7 @@ 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)
|
||||||
# TODO(johnsom) Remove when versions and ciphers are implemented
|
self.assertEqual(self.sample_data.provider_pool1, provider_pool)
|
||||||
expect_prov_pool = copy.deepcopy(self.sample_data.provider_pool1)
|
|
||||||
delattr(expect_prov_pool, lib_constants.TLS_VERSIONS)
|
|
||||||
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')
|
||||||
@ -347,11 +332,7 @@ 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)
|
||||||
# TODO(johnsom) Remove when versions and ciphers are implemented
|
self.assertEqual(self.sample_data.provider_pools, provider_pools)
|
||||||
expect_prov_pools = copy.deepcopy(self.sample_data.provider_pools)
|
|
||||||
for prov_pool in expect_prov_pools:
|
|
||||||
delattr(prov_pool, lib_constants.TLS_VERSIONS)
|
|
||||||
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')
|
||||||
@ -367,8 +348,6 @@ 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)
|
|
||||||
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')
|
||||||
@ -400,8 +379,6 @@ 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)
|
|
||||||
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):
|
||||||
|
@ -993,7 +993,8 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
"{opts}\n\n").format(
|
"{opts}\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
||||||
" ciphers " + constants.CIPHERS_OWASP_SUITE_B)
|
" ciphers " + constants.CIPHERS_OWASP_SUITE_B +
|
||||||
|
" no-sslv3 no-tlsv10 no-tlsv11")
|
||||||
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(
|
||||||
@ -1007,6 +1008,43 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
sample_configs_combined.sample_base_expected_config(backend=be),
|
sample_configs_combined.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_pool_cert_no_versions(self):
|
||||||
|
cert_file_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
||||||
|
'sample_listener_id_1', 'fake path')
|
||||||
|
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 "
|
||||||
|
"{opts}\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 "
|
||||||
|
"{opts}\n\n").format(
|
||||||
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
||||||
|
" ciphers " + constants.CIPHERS_OWASP_SUITE_B)
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
pool_cert=True, tls_enabled=True,
|
||||||
|
backend_tls_ciphers=constants.CIPHERS_OWASP_SUITE_B,
|
||||||
|
backend_tls_versions=None)],
|
||||||
|
tls_certs={
|
||||||
|
'sample_pool_id_1':
|
||||||
|
{'client_cert': cert_file_path,
|
||||||
|
'ca_cert': None, 'crl': None}})
|
||||||
|
self.assertEqual(
|
||||||
|
sample_configs_combined.sample_base_expected_config(backend=be),
|
||||||
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_pool_cert_no_ciphers(self):
|
def test_render_template_pool_cert_no_ciphers(self):
|
||||||
cert_file_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
cert_file_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
||||||
'sample_listener_id_1', 'fake path')
|
'sample_listener_id_1', 'fake path')
|
||||||
@ -1028,7 +1066,8 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
|
"check inter 30s fall 3 rise 2 cookie sample_member_id_2 "
|
||||||
"{opts}\n\n").format(
|
"{opts}\n\n").format(
|
||||||
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path)
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
||||||
|
" no-sslv3 no-tlsv10 no-tlsv11")
|
||||||
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(
|
||||||
@ -1041,6 +1080,40 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
sample_configs_combined.sample_base_expected_config(backend=be),
|
sample_configs_combined.sample_base_expected_config(backend=be),
|
||||||
rendered_obj)
|
rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_pool_cert_no_ciphers_or_versions(self):
|
||||||
|
cert_file_path = os.path.join(self.jinja_cfg.base_crt_dir,
|
||||||
|
'sample_listener_id_1', 'fake path')
|
||||||
|
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 "
|
||||||
|
"{opts}\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 "
|
||||||
|
"{opts}\n\n").format(
|
||||||
|
maxconn=constants.HAPROXY_MAX_MAXCONN,
|
||||||
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path)
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs_combined.sample_amphora_tuple(),
|
||||||
|
[sample_configs_combined.sample_listener_tuple(
|
||||||
|
pool_cert=True, tls_enabled=True, backend_tls_versions=None)],
|
||||||
|
tls_certs={
|
||||||
|
'sample_pool_id_1':
|
||||||
|
{'client_cert': cert_file_path,
|
||||||
|
'ca_cert': None, 'crl': None}})
|
||||||
|
self.assertEqual(
|
||||||
|
sample_configs_combined.sample_base_expected_config(backend=be),
|
||||||
|
rendered_obj)
|
||||||
|
|
||||||
def test_render_template_with_full_pool_cert(self):
|
def test_render_template_with_full_pool_cert(self):
|
||||||
pool_client_cert = '/foo/cert.pem'
|
pool_client_cert = '/foo/cert.pem'
|
||||||
pool_ca_cert = '/foo/ca.pem'
|
pool_ca_cert = '/foo/ca.pem'
|
||||||
@ -1067,7 +1140,7 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
"ssl", "crt", pool_client_cert,
|
"ssl", "crt", pool_client_cert,
|
||||||
"ca-file %s" % pool_ca_cert,
|
"ca-file %s" % pool_ca_cert,
|
||||||
"crl-file %s" % pool_crl,
|
"crl-file %s" % pool_crl,
|
||||||
"verify required sni ssl_fc_sni"))
|
"verify required sni ssl_fc_sni no-sslv3 no-tlsv10 no-tlsv11"))
|
||||||
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(
|
||||||
|
@ -603,13 +603,17 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
provisioning_status=constants.ACTIVE,
|
provisioning_status=constants.ACTIVE,
|
||||||
tls_ciphers=constants.CIPHERS_OWASP_SUITE_B,
|
tls_ciphers=constants.CIPHERS_OWASP_SUITE_B,
|
||||||
backend_tls_ciphers=None,
|
backend_tls_ciphers=None,
|
||||||
tls_versions=constants.TLS_VERSIONS_OWASP_SUITE_B):
|
tls_versions=constants.TLS_VERSIONS_OWASP_SUITE_B,
|
||||||
|
backend_tls_versions=constants.
|
||||||
|
TLS_VERSIONS_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:
|
if proto != constants.PROTOCOL_TERMINATED_HTTPS:
|
||||||
tls_ciphers = None
|
tls_ciphers = None
|
||||||
tls_versions = None
|
tls_versions = None
|
||||||
|
if pool_cert is False:
|
||||||
|
backend_tls_versions = 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
|
||||||
@ -636,7 +640,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
||||||
hm_host_http_check=hm_host_http_check,
|
hm_host_http_check=hm_host_http_check,
|
||||||
listener_id='sample_listener_id_1',
|
listener_id='sample_listener_id_1',
|
||||||
tls_ciphers=backend_tls_ciphers),
|
tls_ciphers=backend_tls_ciphers,
|
||||||
|
tls_versions=backend_tls_versions),
|
||||||
sample_pool_tuple(
|
sample_pool_tuple(
|
||||||
proto=be_proto, monitor=monitor, persistence=persistence,
|
proto=be_proto, monitor=monitor, persistence=persistence,
|
||||||
persistence_type=persistence_type,
|
persistence_type=persistence_type,
|
||||||
@ -646,7 +651,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
||||||
hm_host_http_check=hm_host_http_check,
|
hm_host_http_check=hm_host_http_check,
|
||||||
listener_id='sample_listener_id_1',
|
listener_id='sample_listener_id_1',
|
||||||
tls_ciphers=backend_tls_ciphers)]
|
tls_ciphers=backend_tls_ciphers,
|
||||||
|
tls_versions=None)]
|
||||||
l7policies = [
|
l7policies = [
|
||||||
sample_l7policy_tuple('sample_l7policy_id_1', sample_policy=1),
|
sample_l7policy_tuple('sample_l7policy_id_1', sample_policy=1),
|
||||||
sample_l7policy_tuple('sample_l7policy_id_2', sample_policy=2),
|
sample_l7policy_tuple('sample_l7policy_id_2', sample_policy=2),
|
||||||
@ -670,7 +676,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
pool_crl=pool_crl, tls_enabled=tls_enabled,
|
||||||
hm_host_http_check=hm_host_http_check,
|
hm_host_http_check=hm_host_http_check,
|
||||||
listener_id='sample_listener_id_1',
|
listener_id='sample_listener_id_1',
|
||||||
tls_ciphers=backend_tls_ciphers)]
|
tls_ciphers=backend_tls_ciphers,
|
||||||
|
tls_versions=backend_tls_versions)]
|
||||||
l7policies = []
|
l7policies = []
|
||||||
listener = in_listener(
|
listener = in_listener(
|
||||||
id=id,
|
id=id,
|
||||||
@ -780,17 +787,19 @@ def sample_pool_tuple(listener_id=None, proto=None, monitor=True,
|
|||||||
pool_crl=False, tls_enabled=False,
|
pool_crl=False, tls_enabled=False,
|
||||||
hm_host_http_check=False,
|
hm_host_http_check=False,
|
||||||
provisioning_status=constants.ACTIVE,
|
provisioning_status=constants.ACTIVE,
|
||||||
tls_ciphers=constants.CIPHERS_OWASP_SUITE_B):
|
tls_ciphers=constants.CIPHERS_OWASP_SUITE_B,
|
||||||
|
tls_versions=constants.TLS_VERSIONS_OWASP_SUITE_B):
|
||||||
proto = 'HTTP' if proto is None else proto
|
proto = 'HTTP' if proto is None else proto
|
||||||
if not tls_enabled:
|
if not tls_enabled:
|
||||||
tls_ciphers = None
|
tls_ciphers = None
|
||||||
|
tls_versions = None
|
||||||
monitor_proto = proto if monitor_proto is None else monitor_proto
|
monitor_proto = proto if monitor_proto is None else monitor_proto
|
||||||
in_pool = collections.namedtuple(
|
in_pool = collections.namedtuple(
|
||||||
'pool', 'id, protocol, lb_algorithm, members, health_monitor, '
|
'pool', 'id, protocol, lb_algorithm, members, health_monitor, '
|
||||||
'session_persistence, enabled, operating_status, '
|
'session_persistence, enabled, operating_status, '
|
||||||
'tls_certificate_id, ca_tls_certificate_id, '
|
'tls_certificate_id, ca_tls_certificate_id, '
|
||||||
'crl_container_id, tls_enabled, tls_ciphers, '
|
'crl_container_id, tls_enabled, tls_ciphers, '
|
||||||
'provisioning_status, ' +
|
'tls_versions, provisioning_status, ' +
|
||||||
constants.HTTP_REUSE)
|
constants.HTTP_REUSE)
|
||||||
if (proto == constants.PROTOCOL_UDP and
|
if (proto == constants.PROTOCOL_UDP and
|
||||||
persistence_type == constants.SESSION_PERSISTENCE_SOURCE_IP):
|
persistence_type == constants.SESSION_PERSISTENCE_SOURCE_IP):
|
||||||
@ -838,6 +847,7 @@ def sample_pool_tuple(listener_id=None, proto=None, monitor=True,
|
|||||||
crl_container_id='pool_crl' if pool_crl else None,
|
crl_container_id='pool_crl' if pool_crl else None,
|
||||||
tls_enabled=tls_enabled,
|
tls_enabled=tls_enabled,
|
||||||
tls_ciphers=tls_ciphers,
|
tls_ciphers=tls_ciphers,
|
||||||
|
tls_versions=tls_versions,
|
||||||
provisioning_status=provisioning_status)
|
provisioning_status=provisioning_status)
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
TLS-enabled pools can now be configured to use only specified versions of
|
||||||
|
TLS. Default TLS versions for new pools can be set with
|
||||||
|
``default_pool_tls_versions`` in ``octavia.conf``. Existing pools
|
||||||
|
will continue to use the old defaults.
|
Loading…
Reference in New Issue
Block a user