Add crl-file option for certification
Add crl-file in Listener side. Story: 2002165 Co-Authored-By: Michael Johnson <johnsomor@gmail.com> Change-Id: I9e2ec06719fbbfd19482c2b8d39220e7e4ed81e3
This commit is contained in:
parent
7a8eb3ce22
commit
20509e2337
@ -282,6 +282,24 @@ client_ca_tls_container_ref-optional:
|
|||||||
min_version: 2.8
|
min_version: 2.8
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
client_crl_container_ref:
|
||||||
|
description: |
|
||||||
|
The URI of the `key manager service
|
||||||
|
<https://docs.openstack.org/castellan/latest/>`__ secret containing a
|
||||||
|
PEM format CA revocation list file for ``TERMINATED_TLS`` listeners.
|
||||||
|
in: body
|
||||||
|
min_version: 2.8
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
client_crl_container_ref-optional:
|
||||||
|
description: |
|
||||||
|
The URI of the `key manager service
|
||||||
|
<https://docs.openstack.org/castellan/latest/>`__ secret containing a
|
||||||
|
PEM format CA revocation list file for ``TERMINATED_TLS`` listeners.
|
||||||
|
in: body
|
||||||
|
min_version: 2.8
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
compute-flavor:
|
compute-flavor:
|
||||||
description: |
|
description: |
|
||||||
The ID of the compute flavor used for the amphora.
|
The ID of the compute flavor used for the amphora.
|
||||||
|
@ -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"}}' 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"}}' http://198.51.100.10:9876/v2/lbaas/listeners
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"timeout_tcp_inspect": 0,
|
"timeout_tcp_inspect": 0,
|
||||||
"tags": ["test_tag"],
|
"tags": ["test_tag"],
|
||||||
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
||||||
"client_authentication": "MANDATORY"
|
"client_authentication": "MANDATORY",
|
||||||
|
"client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"timeout_tcp_inspect": 0,
|
"timeout_tcp_inspect": 0,
|
||||||
"tags": ["test_tag"],
|
"tags": ["test_tag"],
|
||||||
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
||||||
"client_authentication": "MANDATORY"
|
"client_authentication": "MANDATORY",
|
||||||
|
"client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"timeout_tcp_inspect": 0,
|
"timeout_tcp_inspect": 0,
|
||||||
"tags": ["test_tag"],
|
"tags": ["test_tag"],
|
||||||
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
||||||
"client_authentication": "MANDATORY"
|
"client_authentication": "MANDATORY",
|
||||||
|
"client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"timeout_tcp_inspect": 5,
|
"timeout_tcp_inspect": 5,
|
||||||
"tags": ["updated_tag"],
|
"tags": ["updated_tag"],
|
||||||
"client_ca_tls_container_ref": null,
|
"client_ca_tls_container_ref": null,
|
||||||
"client_authentication": "NONE"
|
"client_authentication": "NONE",
|
||||||
|
"client_crl_container_ref": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
"timeout_tcp_inspect": 0,
|
"timeout_tcp_inspect": 0,
|
||||||
"tags": ["test_tag"],
|
"tags": ["test_tag"],
|
||||||
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
"client_ca_tls_container_ref": "http://198.51.100.10:9311/v1/containers/35649991-49f3-4625-81ce-2465fe8932e5",
|
||||||
"client_authentication": "NONE"
|
"client_authentication": "NONE",
|
||||||
|
"client_crl_container_ref": "http://198.51.100.10:9311/v1/containers/e222b065-b93b-4e2a-9a02-804b7a118c3c"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ Response Parameters
|
|||||||
- admin_state_up: admin_state_up
|
- admin_state_up: admin_state_up
|
||||||
- client_authentication: client_authentication
|
- client_authentication: client_authentication
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
||||||
|
- client_crl_container_ref: client_crl_container_ref
|
||||||
- connection_limit: connection_limit
|
- connection_limit: connection_limit
|
||||||
- created_at: created_at
|
- created_at: created_at
|
||||||
- default_pool_id: default_pool_id
|
- default_pool_id: default_pool_id
|
||||||
@ -140,6 +141,7 @@ Request
|
|||||||
- admin_state_up: admin_state_up-default-optional
|
- admin_state_up: admin_state_up-default-optional
|
||||||
- client_authentication: client_authentication-optional
|
- client_authentication: client_authentication-optional
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref-optional
|
- client_ca_tls_container_ref: client_ca_tls_container_ref-optional
|
||||||
|
- client_crl_container_ref: client_crl_container_ref-optional
|
||||||
- connection_limit: connection_limit-optional
|
- connection_limit: connection_limit-optional
|
||||||
- default_pool: pool-optional
|
- default_pool: pool-optional
|
||||||
- default_pool_id: default_pool_id-optional
|
- default_pool_id: default_pool_id-optional
|
||||||
@ -210,6 +212,7 @@ Response Parameters
|
|||||||
- admin_state_up: admin_state_up
|
- admin_state_up: admin_state_up
|
||||||
- client_authentication: client_authentication
|
- client_authentication: client_authentication
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
||||||
|
- client_crl_container_ref: client_crl_container_ref
|
||||||
- connection_limit: connection_limit
|
- connection_limit: connection_limit
|
||||||
- created_at: created_at
|
- created_at: created_at
|
||||||
- default_pool_id: default_pool_id
|
- default_pool_id: default_pool_id
|
||||||
@ -286,6 +289,7 @@ Response Parameters
|
|||||||
- admin_state_up: admin_state_up
|
- admin_state_up: admin_state_up
|
||||||
- client_authentication: client_authentication
|
- client_authentication: client_authentication
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
||||||
|
- client_crl_container_ref: client_crl_container_ref
|
||||||
- connection_limit: connection_limit
|
- connection_limit: connection_limit
|
||||||
- created_at: created_at
|
- created_at: created_at
|
||||||
- default_pool_id: default_pool_id
|
- default_pool_id: default_pool_id
|
||||||
@ -352,6 +356,7 @@ Request
|
|||||||
- admin_state_up: admin_state_up-default-optional
|
- admin_state_up: admin_state_up-default-optional
|
||||||
- client_authentication: client_authentication-optional
|
- client_authentication: client_authentication-optional
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref-optional
|
- client_ca_tls_container_ref: client_ca_tls_container_ref-optional
|
||||||
|
- client_crl_container_ref: client_crl_container_ref-optional
|
||||||
- connection_limit: connection_limit-optional
|
- connection_limit: connection_limit-optional
|
||||||
- default_pool_id: default_pool_id-optional
|
- default_pool_id: default_pool_id-optional
|
||||||
- default_tls_container_ref: default_tls_container_ref-optional
|
- default_tls_container_ref: default_tls_container_ref-optional
|
||||||
@ -386,6 +391,7 @@ Response Parameters
|
|||||||
- admin_state_up: admin_state_up
|
- admin_state_up: admin_state_up
|
||||||
- client_authentication: client_authentication
|
- client_authentication: client_authentication
|
||||||
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
- client_ca_tls_container_ref: client_ca_tls_container_ref
|
||||||
|
- client_crl_container_ref: client_crl_container_ref
|
||||||
- connection_limit: connection_limit
|
- connection_limit: connection_limit
|
||||||
- created_at: created_at
|
- created_at: created_at
|
||||||
- default_pool_id: default_pool_id
|
- default_pool_id: default_pool_id
|
||||||
|
@ -373,6 +373,11 @@ contain the following:
|
|||||||
| client_ca_tls_container_ref | string | The reference to the secrets |
|
| client_ca_tls_container_ref | string | The reference to the secrets |
|
||||||
| | | container. |
|
| | | container. |
|
||||||
+------------------------------+--------+-------------------------------------+
|
+------------------------------+--------+-------------------------------------+
|
||||||
|
| client_crl_container_data | string | A PEM encoded CRL file. |
|
||||||
|
+------------------------------+--------+-------------------------------------+
|
||||||
|
| client_crl_container_ref | string | The reference to the secrets |
|
||||||
|
| | | container. |
|
||||||
|
+------------------------------+--------+-------------------------------------+
|
||||||
| connection_limit | int | The max number of connections |
|
| connection_limit | int | The max number of connections |
|
||||||
| | | permitted for this listener. Default|
|
| | | permitted for this listener. Default|
|
||||||
| | | is -1, which is infinite |
|
| | | is -1, which is infinite |
|
||||||
|
@ -118,13 +118,16 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||||||
certs = self._process_tls_certificates(listener)
|
certs = self._process_tls_certificates(listener)
|
||||||
client_ca_filename = self._process_secret(
|
client_ca_filename = self._process_secret(
|
||||||
listener, listener.client_ca_tls_certificate_id)
|
listener, listener.client_ca_tls_certificate_id)
|
||||||
|
crl_filename = self._process_secret(
|
||||||
|
listener, listener.client_crl_container_id)
|
||||||
|
|
||||||
# Generate HaProxy configuration from listener object
|
# Generate HaProxy configuration from listener object
|
||||||
config = self.jinja.build_config(
|
config = self.jinja.build_config(
|
||||||
host_amphora=amp, listener=listener,
|
host_amphora=amp, listener=listener,
|
||||||
tls_cert=certs['tls_cert'],
|
tls_cert=certs['tls_cert'],
|
||||||
haproxy_versions=haproxy_versions,
|
haproxy_versions=haproxy_versions,
|
||||||
client_ca_filename=client_ca_filename)
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=crl_filename)
|
||||||
self.client.upload_config(amp, listener.id, config,
|
self.client.upload_config(amp, listener.id, config,
|
||||||
timeout_dict=timeout_dict)
|
timeout_dict=timeout_dict)
|
||||||
self.client.reload_listener(amp, listener.id,
|
self.client.reload_listener(amp, listener.id,
|
||||||
@ -156,6 +159,8 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||||||
certs = self._process_tls_certificates(listener)
|
certs = self._process_tls_certificates(listener)
|
||||||
client_ca_filename = self._process_secret(
|
client_ca_filename = self._process_secret(
|
||||||
listener, listener.client_ca_tls_certificate_id)
|
listener, listener.client_ca_tls_certificate_id)
|
||||||
|
crl_filename = self._process_secret(
|
||||||
|
listener, listener.client_crl_container_id)
|
||||||
|
|
||||||
for amp in listener.load_balancer.amphorae:
|
for amp in listener.load_balancer.amphorae:
|
||||||
if amp.status != consts.DELETED:
|
if amp.status != consts.DELETED:
|
||||||
@ -167,7 +172,8 @@ class HaproxyAmphoraLoadBalancerDriver(
|
|||||||
host_amphora=amp, listener=listener,
|
host_amphora=amp, listener=listener,
|
||||||
tls_cert=certs['tls_cert'],
|
tls_cert=certs['tls_cert'],
|
||||||
haproxy_versions=haproxy_versions,
|
haproxy_versions=haproxy_versions,
|
||||||
client_ca_filename=client_ca_filename)
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=crl_filename)
|
||||||
self.client.upload_config(amp, listener.id, config)
|
self.client.upload_config(amp, listener.id, config)
|
||||||
self.client.reload_listener(amp, listener.id)
|
self.client.reload_listener(amp, listener.id)
|
||||||
|
|
||||||
|
@ -135,7 +135,8 @@ class Listener(BaseDataModel):
|
|||||||
timeout_member_connect=Unset, timeout_member_data=Unset,
|
timeout_member_connect=Unset, timeout_member_data=Unset,
|
||||||
timeout_tcp_inspect=Unset, client_ca_tls_container_ref=Unset,
|
timeout_tcp_inspect=Unset, client_ca_tls_container_ref=Unset,
|
||||||
client_ca_tls_container_data=Unset,
|
client_ca_tls_container_data=Unset,
|
||||||
client_authentication=Unset):
|
client_authentication=Unset, client_crl_container_ref=Unset,
|
||||||
|
client_crl_container_data=Unset):
|
||||||
|
|
||||||
self.admin_state_up = admin_state_up
|
self.admin_state_up = admin_state_up
|
||||||
self.connection_limit = connection_limit
|
self.connection_limit = connection_limit
|
||||||
@ -160,6 +161,8 @@ class Listener(BaseDataModel):
|
|||||||
self.client_ca_tls_container_ref = client_ca_tls_container_ref
|
self.client_ca_tls_container_ref = client_ca_tls_container_ref
|
||||||
self.client_ca_tls_container_data = client_ca_tls_container_data
|
self.client_ca_tls_container_data = client_ca_tls_container_data
|
||||||
self.client_authentication = client_authentication
|
self.client_authentication = client_authentication
|
||||||
|
self.client_crl_container_ref = client_crl_container_ref
|
||||||
|
self.client_crl_container_data = client_crl_container_data
|
||||||
|
|
||||||
|
|
||||||
class Pool(BaseDataModel):
|
class Pool(BaseDataModel):
|
||||||
|
@ -184,7 +184,9 @@ def listener_dict_to_provider_dict(listener_dict):
|
|||||||
if 'client_ca_tls_certificate_id' in new_listener_dict:
|
if 'client_ca_tls_certificate_id' in new_listener_dict:
|
||||||
new_listener_dict['client_ca_tls_container_ref'] = (
|
new_listener_dict['client_ca_tls_container_ref'] = (
|
||||||
new_listener_dict.pop('client_ca_tls_certificate_id'))
|
new_listener_dict.pop('client_ca_tls_certificate_id'))
|
||||||
|
if 'client_crl_container_id' in new_listener_dict:
|
||||||
|
new_listener_dict['client_crl_container_ref'] = (
|
||||||
|
new_listener_dict.pop('client_crl_container_id'))
|
||||||
listener_obj = data_models.Listener(**listener_dict)
|
listener_obj = data_models.Listener(**listener_dict)
|
||||||
if (listener_obj.tls_certificate_id or listener_obj.sni_containers or
|
if (listener_obj.tls_certificate_id or listener_obj.sni_containers or
|
||||||
listener_obj.client_ca_tls_certificate_id):
|
listener_obj.client_ca_tls_certificate_id):
|
||||||
@ -220,6 +222,10 @@ def listener_dict_to_provider_dict(listener_dict):
|
|||||||
cert = _get_secret_data(cert_manager, listener_obj,
|
cert = _get_secret_data(cert_manager, listener_obj,
|
||||||
listener_obj.client_ca_tls_certificate_id)
|
listener_obj.client_ca_tls_certificate_id)
|
||||||
new_listener_dict['client_ca_tls_container_data'] = cert
|
new_listener_dict['client_ca_tls_container_data'] = cert
|
||||||
|
if listener_obj.client_crl_container_id:
|
||||||
|
crl_file = _get_secret_data(cert_manager, listener_obj,
|
||||||
|
listener_obj.client_crl_container_id)
|
||||||
|
new_listener_dict['client_crl_container_data'] = crl_file
|
||||||
|
|
||||||
# Remove the DB back references
|
# Remove the DB back references
|
||||||
if 'load_balancer' in new_listener_dict:
|
if 'load_balancer' in new_listener_dict:
|
||||||
|
@ -142,7 +142,7 @@ class ListenersController(base.BaseController):
|
|||||||
if bad_refs:
|
if bad_refs:
|
||||||
raise exceptions.CertificateRetrievalException(ref=bad_refs)
|
raise exceptions.CertificateRetrievalException(ref=bad_refs)
|
||||||
|
|
||||||
def _validate_client_ca_ref(self, client_ca_ref):
|
def _validate_client_ca_and_crl_refs(self, client_ca_ref, crl_ref):
|
||||||
context = pecan.request.context.get('octavia_context')
|
context = pecan.request.context.get('octavia_context')
|
||||||
bad_refs = []
|
bad_refs = []
|
||||||
try:
|
try:
|
||||||
@ -151,23 +151,51 @@ class ListenersController(base.BaseController):
|
|||||||
except Exception:
|
except Exception:
|
||||||
bad_refs.append(client_ca_ref)
|
bad_refs.append(client_ca_ref)
|
||||||
|
|
||||||
# This will be used in a later patch
|
pem_crl = None
|
||||||
|
if crl_ref:
|
||||||
|
try:
|
||||||
|
self.cert_manager.set_acls(context, crl_ref)
|
||||||
|
pem_crl = self.cert_manager.get_secret(context, crl_ref)
|
||||||
|
except Exception:
|
||||||
|
bad_refs.append(crl_ref)
|
||||||
if bad_refs:
|
if bad_refs:
|
||||||
raise exceptions.CertificateRetrievalException(ref=bad_refs)
|
raise exceptions.CertificateRetrievalException(ref=bad_refs)
|
||||||
|
|
||||||
|
ca_cert = None
|
||||||
try:
|
try:
|
||||||
# Test if it needs to be UTF-8 encoded
|
# Test if it needs to be UTF-8 encoded
|
||||||
try:
|
try:
|
||||||
ca_pem = ca_pem.encode('utf-8')
|
ca_pem = ca_pem.encode('utf-8')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
x509.load_pem_x509_certificate(ca_pem, default_backend())
|
ca_cert = x509.load_pem_x509_certificate(ca_pem, default_backend())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise exceptions.ValidationException(detail=_(
|
raise exceptions.ValidationException(detail=_(
|
||||||
"The client authentication CA certificate is invalid. "
|
"The client authentication CA certificate is invalid. "
|
||||||
"It must be a valid x509 PEM format certificate. "
|
"It must be a valid x509 PEM format certificate. "
|
||||||
"Error: %s") % str(e))
|
"Error: %s") % str(e))
|
||||||
|
|
||||||
|
# Validate the CRL is for the client CA
|
||||||
|
if pem_crl:
|
||||||
|
ca_pub_key = ca_cert.public_key()
|
||||||
|
crl = None
|
||||||
|
# Test if it needs to be UTF-8 encoded
|
||||||
|
try:
|
||||||
|
pem_crl = pem_crl.encode('utf-8')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
crl = x509.load_pem_x509_crl(pem_crl, default_backend())
|
||||||
|
except Exception as e:
|
||||||
|
raise exceptions.ValidationException(detail=_(
|
||||||
|
"The client authentication certificate revocation list "
|
||||||
|
"is invalid. It must be a valid x509 PEM format "
|
||||||
|
"certificate revocation list. Error: %s") % str(e))
|
||||||
|
if not crl.is_signature_valid(ca_pub_key):
|
||||||
|
raise exceptions.ValidationException(detail=_(
|
||||||
|
"The CRL specified is not valid for client certificate "
|
||||||
|
"authority reference supplied."))
|
||||||
|
|
||||||
def _has_tls_container_refs(self, listener_dict):
|
def _has_tls_container_refs(self, listener_dict):
|
||||||
return (listener_dict.get('tls_certificate_id') or
|
return (listener_dict.get('tls_certificate_id') or
|
||||||
listener_dict.get('client_ca_tls_container_id') or
|
listener_dict.get('client_ca_tls_container_id') or
|
||||||
@ -239,15 +267,27 @@ class ListenersController(base.BaseController):
|
|||||||
"container reference.") %
|
"container reference.") %
|
||||||
listener_dict.get('client_authentication'))
|
listener_dict.get('client_authentication'))
|
||||||
|
|
||||||
try:
|
# Make sure we have a client CA if they specify a CRL
|
||||||
|
if (listener_dict.get('client_crl_container_id') and
|
||||||
|
not listener_dict.get('client_ca_tls_certificate_id')):
|
||||||
|
raise exceptions.ValidationException(detail=_(
|
||||||
|
"A client authentication CA reference is required to "
|
||||||
|
"specify a client authentication revocation list."))
|
||||||
|
|
||||||
|
# Validate the TLS containers
|
||||||
sni_containers = listener_dict.pop('sni_containers', [])
|
sni_containers = listener_dict.pop('sni_containers', [])
|
||||||
tls_refs = [sni['tls_container_id'] for sni in sni_containers]
|
tls_refs = [sni['tls_container_id'] for sni in sni_containers]
|
||||||
if listener_dict.get('tls_certificate_id'):
|
if listener_dict.get('tls_certificate_id'):
|
||||||
tls_refs.append(listener_dict.get('tls_certificate_id'))
|
tls_refs.append(listener_dict.get('tls_certificate_id'))
|
||||||
self._validate_tls_refs(tls_refs)
|
self._validate_tls_refs(tls_refs)
|
||||||
|
|
||||||
|
# Validate the client CA cert and optional client CRL
|
||||||
if listener_dict.get('client_ca_tls_certificate_id'):
|
if listener_dict.get('client_ca_tls_certificate_id'):
|
||||||
self._validate_client_ca_ref(
|
self._validate_client_ca_and_crl_refs(
|
||||||
listener_dict.get('client_ca_tls_certificate_id'))
|
listener_dict.get('client_ca_tls_certificate_id'),
|
||||||
|
listener_dict.get('client_crl_container_id', None))
|
||||||
|
|
||||||
|
try:
|
||||||
db_listener = self.repositories.listener.create(
|
db_listener = self.repositories.listener.create(
|
||||||
lock_session, **listener_dict)
|
lock_session, **listener_dict)
|
||||||
if sni_containers:
|
if sni_containers:
|
||||||
@ -406,8 +446,28 @@ class ListenersController(base.BaseController):
|
|||||||
if listener.default_tls_container_ref:
|
if listener.default_tls_container_ref:
|
||||||
tls_refs.append(listener.default_tls_container_ref)
|
tls_refs.append(listener.default_tls_container_ref)
|
||||||
self._validate_tls_refs(tls_refs)
|
self._validate_tls_refs(tls_refs)
|
||||||
if listener.client_ca_tls_container_ref:
|
|
||||||
self._validate_client_ca_ref(listener.client_ca_tls_container_ref)
|
ca_ref = None
|
||||||
|
if (listener.client_ca_tls_container_ref and
|
||||||
|
listener.client_ca_tls_container_ref != wtypes.Unset):
|
||||||
|
ca_ref = listener.client_ca_tls_container_ref
|
||||||
|
elif db_listener.client_ca_tls_certificate_id:
|
||||||
|
ca_ref = db_listener.client_ca_tls_certificate_id
|
||||||
|
|
||||||
|
crl_ref = None
|
||||||
|
if (listener.client_crl_container_ref and
|
||||||
|
listener.client_crl_container_ref != wtypes.Unset):
|
||||||
|
crl_ref = listener.client_crl_container_ref
|
||||||
|
elif db_listener.client_crl_container_id:
|
||||||
|
crl_ref = db_listener.client_crl_container_id
|
||||||
|
|
||||||
|
if crl_ref and not ca_ref:
|
||||||
|
raise exceptions.ValidationException(detail=_(
|
||||||
|
"A client authentication CA reference is required to "
|
||||||
|
"specify a client authentication revocation list."))
|
||||||
|
|
||||||
|
if ca_ref or crl_ref:
|
||||||
|
self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(listener_types.ListenerRootResponse, wtypes.text,
|
@wsme_pecan.wsexpose(listener_types.ListenerRootResponse, wtypes.text,
|
||||||
body=listener_types.ListenerRootPUT, status_code=200)
|
body=listener_types.ListenerRootPUT, status_code=200)
|
||||||
|
@ -28,7 +28,8 @@ class BaseListenerType(types.BaseType):
|
|||||||
_type_to_model_map = {
|
_type_to_model_map = {
|
||||||
'admin_state_up': 'enabled',
|
'admin_state_up': 'enabled',
|
||||||
'default_tls_container_ref': 'tls_certificate_id',
|
'default_tls_container_ref': 'tls_certificate_id',
|
||||||
'client_ca_tls_container_ref': 'client_ca_tls_certificate_id'}
|
'client_ca_tls_container_ref': 'client_ca_tls_certificate_id',
|
||||||
|
'client_crl_container_ref': 'client_crl_container_id'}
|
||||||
_child_map = {}
|
_child_map = {}
|
||||||
|
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ class ListenerResponse(BaseListenerType):
|
|||||||
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType()))
|
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType()))
|
||||||
client_ca_tls_container_ref = wtypes.StringType()
|
client_ca_tls_container_ref = wtypes.StringType()
|
||||||
client_authentication = wtypes.wsattr(wtypes.StringType())
|
client_authentication = wtypes.wsattr(wtypes.StringType())
|
||||||
|
client_crl_container_ref = wtypes.wsattr(wtypes.StringType())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data_model(cls, data_model, children=False):
|
def from_data_model(cls, data_model, children=False):
|
||||||
@ -142,6 +144,7 @@ class ListenerPOST(BaseListenerType):
|
|||||||
client_authentication = wtypes.wsattr(
|
client_authentication = wtypes.wsattr(
|
||||||
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES),
|
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES),
|
||||||
default=constants.CLIENT_AUTH_NONE)
|
default=constants.CLIENT_AUTH_NONE)
|
||||||
|
client_crl_container_ref = wtypes.StringType(max_length=255)
|
||||||
|
|
||||||
|
|
||||||
class ListenerRootPOST(types.BaseType):
|
class ListenerRootPOST(types.BaseType):
|
||||||
@ -177,6 +180,7 @@ class ListenerPUT(BaseListenerType):
|
|||||||
client_ca_tls_container_ref = wtypes.StringType(max_length=255)
|
client_ca_tls_container_ref = wtypes.StringType(max_length=255)
|
||||||
client_authentication = wtypes.wsattr(
|
client_authentication = wtypes.wsattr(
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
class ListenerRootPUT(types.BaseType):
|
class ListenerRootPUT(types.BaseType):
|
||||||
@ -224,6 +228,7 @@ class ListenerSingleCreate(BaseListenerType):
|
|||||||
client_authentication = wtypes.wsattr(
|
client_authentication = wtypes.wsattr(
|
||||||
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES),
|
wtypes.Enum(str, *constants.SUPPORTED_CLIENT_AUTH_MODES),
|
||||||
default=constants.CLIENT_AUTH_NONE)
|
default=constants.CLIENT_AUTH_NONE)
|
||||||
|
client_crl_container_ref = wtypes.StringType(max_length=255)
|
||||||
|
|
||||||
|
|
||||||
class ListenerStatusResponse(BaseListenerType):
|
class ListenerStatusResponse(BaseListenerType):
|
||||||
|
@ -369,7 +369,7 @@ class Listener(BaseDataModel):
|
|||||||
timeout_client_data=None, timeout_member_connect=None,
|
timeout_client_data=None, timeout_member_connect=None,
|
||||||
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_authentication=None, client_crl_container_id=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -400,6 +400,7 @@ class Listener(BaseDataModel):
|
|||||||
self.tags = tags
|
self.tags = tags
|
||||||
self.client_ca_tls_certificate_id = client_ca_tls_certificate_id
|
self.client_ca_tls_certificate_id = client_ca_tls_certificate_id
|
||||||
self.client_authentication = client_authentication
|
self.client_authentication = client_authentication
|
||||||
|
self.client_crl_container_id = client_crl_container_id
|
||||||
|
|
||||||
def update(self, update_dict):
|
def update(self, update_dict):
|
||||||
for key, value in update_dict.items():
|
for key, value in update_dict.items():
|
||||||
|
@ -83,7 +83,7 @@ class JinjaTemplater(object):
|
|||||||
|
|
||||||
def build_config(self, host_amphora, listener, tls_cert,
|
def build_config(self, host_amphora, listener, tls_cert,
|
||||||
haproxy_versions, socket_path=None,
|
haproxy_versions, socket_path=None,
|
||||||
client_ca_filename=None):
|
client_ca_filename=None, client_crl=None):
|
||||||
"""Convert a logical configuration to the HAProxy version
|
"""Convert a logical configuration to the HAProxy version
|
||||||
|
|
||||||
:param host_amphora: The Amphora this configuration is hosted on
|
:param host_amphora: The Amphora this configuration is hosted on
|
||||||
@ -105,7 +105,7 @@ class JinjaTemplater(object):
|
|||||||
return self.render_loadbalancer_obj(
|
return self.render_loadbalancer_obj(
|
||||||
host_amphora, listener, tls_cert=tls_cert, socket_path=socket_path,
|
host_amphora, listener, tls_cert=tls_cert, socket_path=socket_path,
|
||||||
feature_compatibility=feature_compatibility,
|
feature_compatibility=feature_compatibility,
|
||||||
client_ca_filename=client_ca_filename)
|
client_ca_filename=client_ca_filename, client_crl=client_crl)
|
||||||
|
|
||||||
def _get_template(self):
|
def _get_template(self):
|
||||||
"""Returns the specified Jinja configuration template."""
|
"""Returns the specified Jinja configuration template."""
|
||||||
@ -124,7 +124,7 @@ class JinjaTemplater(object):
|
|||||||
def render_loadbalancer_obj(self, host_amphora, listener,
|
def render_loadbalancer_obj(self, host_amphora, listener,
|
||||||
tls_cert=None, socket_path=None,
|
tls_cert=None, socket_path=None,
|
||||||
feature_compatibility=None,
|
feature_compatibility=None,
|
||||||
client_ca_filename=None):
|
client_ca_filename=None, client_crl=None):
|
||||||
"""Renders a templated configuration from a load balancer object
|
"""Renders a templated configuration from a load balancer object
|
||||||
|
|
||||||
:param host_amphora: The Amphora this configuration is hosted on
|
:param host_amphora: The Amphora this configuration is hosted on
|
||||||
@ -141,7 +141,8 @@ class JinjaTemplater(object):
|
|||||||
listener,
|
listener,
|
||||||
tls_cert,
|
tls_cert,
|
||||||
feature_compatibility,
|
feature_compatibility,
|
||||||
client_ca_filename=client_ca_filename)
|
client_ca_filename=client_ca_filename,
|
||||||
|
client_crl=client_crl)
|
||||||
if not socket_path:
|
if not socket_path:
|
||||||
socket_path = '%s/%s.sock' % (self.base_amp_path, listener.id)
|
socket_path = '%s/%s.sock' % (self.base_amp_path, listener.id)
|
||||||
return self._get_template().render(
|
return self._get_template().render(
|
||||||
@ -154,14 +155,14 @@ class JinjaTemplater(object):
|
|||||||
|
|
||||||
def _transform_loadbalancer(self, host_amphora, loadbalancer, listener,
|
def _transform_loadbalancer(self, host_amphora, loadbalancer, listener,
|
||||||
tls_cert, feature_compatibility,
|
tls_cert, feature_compatibility,
|
||||||
client_ca_filename=None):
|
client_ca_filename=None, client_crl=None):
|
||||||
"""Transforms a load balancer into an object that will
|
"""Transforms a load balancer into an object that will
|
||||||
|
|
||||||
be processed by the templating system
|
be processed by the templating system
|
||||||
"""
|
"""
|
||||||
t_listener = self._transform_listener(
|
t_listener = self._transform_listener(
|
||||||
listener, tls_cert, feature_compatibility,
|
listener, tls_cert, feature_compatibility,
|
||||||
client_ca_filename=client_ca_filename)
|
client_ca_filename=client_ca_filename, client_crl=client_crl)
|
||||||
ret_value = {
|
ret_value = {
|
||||||
'id': loadbalancer.id,
|
'id': loadbalancer.id,
|
||||||
'vip_address': loadbalancer.vip.ip_address,
|
'vip_address': loadbalancer.vip.ip_address,
|
||||||
@ -201,7 +202,7 @@ class JinjaTemplater(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _transform_listener(self, listener, tls_cert, feature_compatibility,
|
def _transform_listener(self, listener, tls_cert, feature_compatibility,
|
||||||
client_ca_filename=None):
|
client_ca_filename=None, client_crl=None):
|
||||||
"""Transforms a listener into an object that will
|
"""Transforms a listener into an object that will
|
||||||
|
|
||||||
be processed by the templating system
|
be processed by the templating system
|
||||||
@ -245,6 +246,9 @@ class JinjaTemplater(object):
|
|||||||
client_ca_filename))
|
client_ca_filename))
|
||||||
ret_value['client_auth'] = CLIENT_AUTH_MAP.get(
|
ret_value['client_auth'] = CLIENT_AUTH_MAP.get(
|
||||||
listener.client_authentication)
|
listener.client_authentication)
|
||||||
|
if listener.client_crl_container_id:
|
||||||
|
ret_value['client_crl_path'] = '%s' % (
|
||||||
|
os.path.join(self.base_crt_dir, listener.id, client_crl))
|
||||||
|
|
||||||
if listener.default_pool:
|
if listener.default_pool:
|
||||||
ret_value['default_pool'] = self._transform_pool(
|
ret_value['default_pool'] = self._transform_pool(
|
||||||
|
@ -43,8 +43,13 @@ peers {{ "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
|
|||||||
{% else %}
|
{% else %}
|
||||||
{% set client_ca_opt = "" %}
|
{% set client_ca_opt = "" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if listener.client_crl_path and listener.client_ca_tls_path %}
|
||||||
|
{% set ca_crl_opt = "crl-file %s"|format(listener.client_crl_path)|trim() %}
|
||||||
|
{% else %}
|
||||||
|
{% set ca_crl_opt = "" %}
|
||||||
|
{% endif %}
|
||||||
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
|
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
|
||||||
"%s %s %s"|format(def_crt_opt, crt_dir_opt, client_ca_opt)|trim() }}
|
"%s %s %s %s"|format(def_crt_opt, crt_dir_opt, client_ca_opt, ca_crl_opt)|trim() }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
# Copyright 2018 Huawei
|
||||||
|
#
|
||||||
|
# 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 certificate revoke revocation list field
|
||||||
|
|
||||||
|
Revision ID: ffad172e98c1
|
||||||
|
Revises: f21ae3f21adc
|
||||||
|
Create Date: 2018-10-01 20:47:52.405865
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ffad172e98c1'
|
||||||
|
down_revision = 'f21ae3f21adc'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column(u'listener',
|
||||||
|
sa.Column(u'client_crl_container_id', sa.String(255),
|
||||||
|
nullable=True))
|
@ -505,6 +505,7 @@ class Listener(base_models.BASE, base_models.IdMixin,
|
|||||||
sa.ForeignKey("client_authentication_mode.name",
|
sa.ForeignKey("client_authentication_mode.name",
|
||||||
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)
|
||||||
|
|
||||||
_tags = orm.relationship(
|
_tags = orm.relationship(
|
||||||
'Tags',
|
'Tags',
|
||||||
|
@ -555,7 +555,8 @@ class TestListener(base.BaseAPITest):
|
|||||||
|
|
||||||
# TODO(johnsom) Fix this when there is a noop certificate manager
|
# TODO(johnsom) Fix this when there is a noop certificate manager
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_create(self, mock_cert_data, response_status=201, **optionals):
|
def test_create(self, mock_cert_data,
|
||||||
|
response_status=201, **optionals):
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
@ -767,6 +768,18 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.assertIn(
|
self.assertIn(
|
||||||
'be provided with a client CA container reference.', fault)
|
'be provided with a client CA container reference.', fault)
|
||||||
|
|
||||||
|
def test_create_crl_without_ca_cert(self):
|
||||||
|
optionals = {
|
||||||
|
'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
|
||||||
|
'client_ca_tls_container_ref': None,
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()
|
||||||
|
}
|
||||||
|
resp = self.test_create(response_status=400, **optionals).json
|
||||||
|
fault = resp.get('faultstring')
|
||||||
|
self.assertIn(
|
||||||
|
'A client authentication CA reference is required to specify a '
|
||||||
|
'client authentication revocation list.', fault)
|
||||||
|
|
||||||
def test_create_with_default_pool_id(self):
|
def test_create_with_default_pool_id(self):
|
||||||
lb_listener = {'name': 'listener1',
|
lb_listener = {'name': 'listener1',
|
||||||
'default_pool_id': self.pool_id,
|
'default_pool_id': self.pool_id,
|
||||||
@ -973,13 +986,69 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.assertEqual(optionals['client_authentication'],
|
self.assertEqual(optionals['client_authentication'],
|
||||||
listener_api.get('client_authentication'))
|
listener_api.get('client_authentication'))
|
||||||
|
|
||||||
def test_create_with_ca_cert_negative_cases(self):
|
def test_create_with_ca_cert_and_crl(self):
|
||||||
# create just with option, no client_ca_tls_container_ref specified.
|
# Load up sample certs to test the validation
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
|
||||||
|
|
||||||
optionals = {
|
optionals = {
|
||||||
'client_authentication': constants.CLIENT_AUTH_MANDATORY
|
'client_ca_tls_container_ref': uuidutils.generate_uuid(),
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()
|
||||||
}
|
}
|
||||||
|
listener_api = self.test_create(**optionals)
|
||||||
|
self.assertEqual(optionals['client_ca_tls_container_ref'],
|
||||||
|
listener_api.get('client_ca_tls_container_ref'))
|
||||||
|
self.assertEqual(constants.CLIENT_AUTH_NONE,
|
||||||
|
listener_api.get('client_authentication'))
|
||||||
|
self.assertEqual(optionals['client_crl_container_ref'],
|
||||||
|
listener_api.get('client_crl_container_ref'))
|
||||||
|
|
||||||
|
# TODO(johnsom) Fix this when there is a noop certificate manager
|
||||||
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_create_with_crl_mismatch_ca_cert(self, mock_cert_data):
|
||||||
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
|
mock_cert_data.return_value = {'tls_cert': cert1,
|
||||||
|
'sni_certs': [cert2, cert3]}
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CERT, sample_certs.X509_CA_CRL]
|
||||||
|
|
||||||
sni1 = uuidutils.generate_uuid()
|
sni1 = uuidutils.generate_uuid()
|
||||||
sni2 = uuidutils.generate_uuid()
|
sni2 = uuidutils.generate_uuid()
|
||||||
|
lb_listener = {
|
||||||
|
'name': 'listener1', 'default_pool_id': None,
|
||||||
|
'description': 'desc1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
|
||||||
|
'protocol_port': 80,
|
||||||
|
'default_tls_container_ref': uuidutils.generate_uuid(),
|
||||||
|
'sni_container_refs': [sni1, sni2],
|
||||||
|
'project_id': self.project_id,
|
||||||
|
'loadbalancer_id': self.lb_id,
|
||||||
|
'client_ca_tls_container_ref': uuidutils.generate_uuid(),
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()
|
||||||
|
}
|
||||||
|
body = self._build_body(lb_listener)
|
||||||
|
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
||||||
|
self.assertEqual(
|
||||||
|
"Validation failure: The CRL specified is not valid for client "
|
||||||
|
"certificate authority reference supplied.",
|
||||||
|
response['faultstring'])
|
||||||
|
|
||||||
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_create_with_ca_cert_negative_cases(self, mock_load_cert):
|
||||||
|
# create just with option or crl,
|
||||||
|
# no client_ca_tls_container_ref specified.
|
||||||
|
sni1 = uuidutils.generate_uuid()
|
||||||
|
sni2 = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
for opt in [{'client_authentication': constants.CLIENT_AUTH_MANDATORY,
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()},
|
||||||
|
{'client_authentication': constants.CLIENT_AUTH_OPTIONAL,
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()}]:
|
||||||
lb_listener = {
|
lb_listener = {
|
||||||
'name': 'listener1', 'default_pool_id': None,
|
'name': 'listener1', 'default_pool_id': None,
|
||||||
'description': 'desc1',
|
'description': 'desc1',
|
||||||
@ -990,13 +1059,13 @@ class TestListener(base.BaseAPITest):
|
|||||||
'sni_container_refs': [sni1, sni2],
|
'sni_container_refs': [sni1, sni2],
|
||||||
'project_id': self.project_id,
|
'project_id': self.project_id,
|
||||||
'loadbalancer_id': self.lb_id}
|
'loadbalancer_id': self.lb_id}
|
||||||
lb_listener.update(optionals)
|
lb_listener.update(opt)
|
||||||
body = self._build_body(lb_listener)
|
body = self._build_body(lb_listener)
|
||||||
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
"Validation failure: Client authentication setting %s "
|
"Validation failure: Client authentication setting %s "
|
||||||
"requires a client CA container reference." %
|
"requires a client CA container reference." %
|
||||||
constants.CLIENT_AUTH_MANDATORY, response['faultstring'])
|
opt['client_authentication'], response['faultstring'])
|
||||||
|
|
||||||
def test_create_with_bad_ca_cert_ref(self):
|
def test_create_with_bad_ca_cert_ref(self):
|
||||||
sni1 = uuidutils.generate_uuid()
|
sni1 = uuidutils.generate_uuid()
|
||||||
@ -1018,7 +1087,30 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.cert_manager_mock().get_secret.side_effect = [
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
Exception('bad ca cert')]
|
Exception('bad ca cert')]
|
||||||
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
||||||
self.assertIn(lb_listener['client_ca_tls_container_ref'],
|
self.assertEqual("Could not retrieve certificate: ['%s']" %
|
||||||
|
lb_listener['client_ca_tls_container_ref'],
|
||||||
|
response['faultstring'])
|
||||||
|
|
||||||
|
def test_create_with_unreachable_crl(self):
|
||||||
|
sni1 = uuidutils.generate_uuid()
|
||||||
|
sni2 = uuidutils.generate_uuid()
|
||||||
|
lb_listener = {
|
||||||
|
'name': 'listener1', 'default_pool_id': None,
|
||||||
|
'description': 'desc1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
|
||||||
|
'protocol_port': 80,
|
||||||
|
'default_tls_container_ref': uuidutils.generate_uuid(),
|
||||||
|
'sni_container_refs': [sni1, sni2],
|
||||||
|
'project_id': self.project_id,
|
||||||
|
'loadbalancer_id': self.lb_id,
|
||||||
|
'client_ca_tls_container_ref': uuidutils.generate_uuid(),
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()}
|
||||||
|
body = self._build_body(lb_listener)
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = Exception(
|
||||||
|
'bad CRL ref')
|
||||||
|
response = self.post(self.LISTENERS_PATH, body, status=400).json
|
||||||
|
self.assertIn(lb_listener['client_crl_container_ref'],
|
||||||
response['faultstring'])
|
response['faultstring'])
|
||||||
|
|
||||||
def test_create_with_bad_ca_cert(self):
|
def test_create_with_bad_ca_cert(self):
|
||||||
@ -1213,6 +1305,22 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.assertNotEqual(ori_listener['client_authentication'],
|
self.assertNotEqual(ori_listener['client_authentication'],
|
||||||
optionals['client_authentication'])
|
optionals['client_authentication'])
|
||||||
|
|
||||||
|
def test_update_with_crl(self):
|
||||||
|
# Load up sample certs to test the validation
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
|
||||||
|
|
||||||
|
optionals = {
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()
|
||||||
|
}
|
||||||
|
ori_listener, update_listener = self.test_update(**optionals)
|
||||||
|
self.assertEqual(optionals['client_crl_container_ref'],
|
||||||
|
update_listener.get('client_crl_container_ref'))
|
||||||
|
self.assertNotEqual(ori_listener['client_crl_container_ref'],
|
||||||
|
optionals['client_crl_container_ref'])
|
||||||
|
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_update_from_nonexist_ca_cert_to_new_ca_cert(self, mock_cert_data):
|
def test_update_from_nonexist_ca_cert_to_new_ca_cert(self, mock_cert_data):
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
@ -1244,7 +1352,7 @@ class TestListener(base.BaseAPITest):
|
|||||||
api_listener['client_authentication'])
|
api_listener['client_authentication'])
|
||||||
|
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_update_with_ca_cert_negative_cases(self, mock_cert_data):
|
def test_update_with_ca_cert_missing(self, mock_cert_data):
|
||||||
# update a listener, no ca cert exist
|
# update a listener, no ca cert exist
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
mock_cert_data.return_value = {'tls_cert': cert1}
|
mock_cert_data.return_value = {'tls_cert': cert1}
|
||||||
@ -1256,16 +1364,42 @@ class TestListener(base.BaseAPITest):
|
|||||||
default_tls_container_ref=tls_uuid,
|
default_tls_container_ref=tls_uuid,
|
||||||
default_pool_id=None).get(self.root_tag)
|
default_pool_id=None).get(self.root_tag)
|
||||||
self.set_lb_status(self.lb_id)
|
self.set_lb_status(self.lb_id)
|
||||||
lb_listener = {
|
for opt in [{'client_authentication': constants.CLIENT_AUTH_OPTIONAL,
|
||||||
'client_authentication': constants.CLIENT_AUTH_OPTIONAL}
|
'client_crl_container_ref': uuidutils.generate_uuid()},
|
||||||
body = self._build_body(lb_listener)
|
{'client_authentication': constants.CLIENT_AUTH_MANDATORY,
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()}]:
|
||||||
|
body = self._build_body(opt)
|
||||||
listener_path = self.LISTENER_PATH.format(
|
listener_path = self.LISTENER_PATH.format(
|
||||||
listener_id=listener['id'])
|
listener_id=listener['id'])
|
||||||
response = self.put(listener_path, body, status=400).json
|
response = self.put(listener_path, body, status=400).json
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
"Validation failure: Client authentication setting %s "
|
"Validation failure: Client authentication setting %s "
|
||||||
"requires a client CA container reference." %
|
"requires a client CA container reference." %
|
||||||
constants.CLIENT_AUTH_OPTIONAL, response['faultstring'])
|
opt['client_authentication'], response['faultstring'])
|
||||||
|
|
||||||
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_update_with_crl_but_ca_cert_missing(self, mock_cert_data):
|
||||||
|
# update a listener, no ca cert exist
|
||||||
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
|
mock_cert_data.return_value = {'tls_cert': cert1,
|
||||||
|
'client_ca_cert': None}
|
||||||
|
tls_uuid = uuidutils.generate_uuid()
|
||||||
|
listener = self.create_listener(
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
|
||||||
|
name='listener1', description='desc1',
|
||||||
|
admin_state_up=False, connection_limit=10,
|
||||||
|
default_tls_container_ref=tls_uuid,
|
||||||
|
default_pool_id=None).get(self.root_tag)
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
body = self._build_body(
|
||||||
|
{'client_crl_container_ref': uuidutils.generate_uuid()})
|
||||||
|
listener_path = self.LISTENER_PATH.format(
|
||||||
|
listener_id=listener['id'])
|
||||||
|
response = self.put(listener_path, body, status=400).json
|
||||||
|
self.assertEqual(
|
||||||
|
"Validation failure: A client authentication CA reference is "
|
||||||
|
"required to specify a client authentication revocation list.",
|
||||||
|
response['faultstring'])
|
||||||
|
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_update_unset_ca_cert(self, mock_cert_data):
|
def test_update_unset_ca_cert(self, mock_cert_data):
|
||||||
@ -1290,6 +1424,41 @@ class TestListener(base.BaseAPITest):
|
|||||||
api_listener = self.put(listener_path, body).json.get(self.root_tag)
|
api_listener = self.put(listener_path, body).json.get(self.root_tag)
|
||||||
self.assertIsNone(api_listener.get('client_ca_tls_container_ref'))
|
self.assertIsNone(api_listener.get('client_ca_tls_container_ref'))
|
||||||
self.assertIsNone(api_listener.get('client_auth_option'))
|
self.assertIsNone(api_listener.get('client_auth_option'))
|
||||||
|
self.assertIsNone(api_listener.get('client_crl_container_ref'))
|
||||||
|
|
||||||
|
@mock.patch(
|
||||||
|
'octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_update_unset_crl(self, mock_cert_data):
|
||||||
|
# Load up sample certs to test the validation
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
|
||||||
|
|
||||||
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
|
mock_cert_data.return_value = {'tls_cert': cert1}
|
||||||
|
listener = self.create_listener(
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
|
||||||
|
name='listener1', description='desc1',
|
||||||
|
admin_state_up=False, connection_limit=10,
|
||||||
|
default_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
default_pool_id=None,
|
||||||
|
client_ca_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
client_crl_container_ref=uuidutils.generate_uuid(),
|
||||||
|
client_authentication=constants.CLIENT_AUTH_MANDATORY).get(
|
||||||
|
self.root_tag)
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
lb_listener = {'client_crl_container_ref': None}
|
||||||
|
body = self._build_body(lb_listener)
|
||||||
|
listener_path = self.LISTENER_PATH.format(
|
||||||
|
listener_id=listener['id'])
|
||||||
|
api_listener = self.put(listener_path, body).json.get(self.root_tag)
|
||||||
|
self.assertEqual(listener.get('client_ca_tls_container_ref'),
|
||||||
|
api_listener.get('client_ca_tls_container_ref'))
|
||||||
|
self.assertEqual(listener.get('client_authentication'),
|
||||||
|
api_listener.get('client_authentication'))
|
||||||
|
self.assertIsNone(api_listener.get('client_crl_container_ref'))
|
||||||
|
|
||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_update_with_bad_ca_cert(self, mock_cert_data):
|
def test_update_with_bad_ca_cert(self, mock_cert_data):
|
||||||
@ -1310,6 +1479,8 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.set_lb_status(self.lb_id)
|
self.set_lb_status(self.lb_id)
|
||||||
self.cert_manager_mock().get_secret.side_effect = Exception(
|
self.cert_manager_mock().get_secret.side_effect = Exception(
|
||||||
'bad ca cert')
|
'bad ca cert')
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = Exception(
|
||||||
|
'bad secret')
|
||||||
lb_listener = {
|
lb_listener = {
|
||||||
'client_ca_tls_container_ref': uuidutils.generate_uuid()}
|
'client_ca_tls_container_ref': uuidutils.generate_uuid()}
|
||||||
body = self._build_body(lb_listener)
|
body = self._build_body(lb_listener)
|
||||||
@ -1319,6 +1490,72 @@ class TestListener(base.BaseAPITest):
|
|||||||
self.assertIn(lb_listener['client_ca_tls_container_ref'],
|
self.assertIn(lb_listener['client_ca_tls_container_ref'],
|
||||||
response['faultstring'])
|
response['faultstring'])
|
||||||
|
|
||||||
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_update_with_unreachable_crl(self, mock_cert_data):
|
||||||
|
# Load up sample certs to test the validation
|
||||||
|
tls_cert_mock = mock.MagicMock()
|
||||||
|
tls_cert_mock.get_certificate.return_value = sample_certs.X509_CA_CERT
|
||||||
|
self.cert_manager_mock().get_cert.return_value = tls_cert_mock
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, Exception('bad CRL ref')]
|
||||||
|
|
||||||
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
|
mock_cert_data.return_value = {'tls_cert': cert1}
|
||||||
|
listener = self.create_listener(
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
|
||||||
|
name='listener1', description='desc1',
|
||||||
|
admin_state_up=False, connection_limit=10,
|
||||||
|
default_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
default_pool_id=None,
|
||||||
|
client_ca_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
client_crl_container_ref=uuidutils.generate_uuid()).get(
|
||||||
|
self.root_tag)
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
lb_listener = {
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()}
|
||||||
|
body = self._build_body(lb_listener)
|
||||||
|
listener_path = self.LISTENER_PATH.format(
|
||||||
|
listener_id=listener['id'])
|
||||||
|
response = self.put(listener_path, body, status=400).json
|
||||||
|
self.assertIn(lb_listener['client_crl_container_ref'],
|
||||||
|
response['faultstring'])
|
||||||
|
|
||||||
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
|
def test_update_with_bad_crl(self, mock_cert_data):
|
||||||
|
# Load up sample certs to test the validation
|
||||||
|
tls_cert_mock = mock.MagicMock()
|
||||||
|
tls_cert_mock.get_certificate.return_value = sample_certs.X509_CA_CERT
|
||||||
|
self.cert_manager_mock().get_cert.return_value = tls_cert_mock
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
|
||||||
|
sample_certs.X509_CA_CERT, 'bad CRL']
|
||||||
|
|
||||||
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
|
mock_cert_data.return_value = {'tls_cert': cert1}
|
||||||
|
listener = self.create_listener(
|
||||||
|
constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
|
||||||
|
name='listener1', description='desc1',
|
||||||
|
admin_state_up=False, connection_limit=10,
|
||||||
|
default_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
default_pool_id=None,
|
||||||
|
client_ca_tls_container_ref=uuidutils.generate_uuid(),
|
||||||
|
client_crl_container_ref=uuidutils.generate_uuid()).get(
|
||||||
|
self.root_tag)
|
||||||
|
self.set_lb_status(self.lb_id)
|
||||||
|
lb_listener = {
|
||||||
|
'client_crl_container_ref': uuidutils.generate_uuid()}
|
||||||
|
body = self._build_body(lb_listener)
|
||||||
|
listener_path = self.LISTENER_PATH.format(
|
||||||
|
listener_id=listener['id'])
|
||||||
|
response = self.put(listener_path, body, status=400).json
|
||||||
|
self.assertIn("The client authentication certificate revocation list "
|
||||||
|
"is invalid. It must be a valid x509 PEM format "
|
||||||
|
"certificate revocation list.",
|
||||||
|
response['faultstring'])
|
||||||
|
|
||||||
def test_update_authorized(self):
|
def test_update_authorized(self):
|
||||||
listener = self.create_listener(
|
listener = self.create_listener(
|
||||||
constants.PROTOCOL_TCP, 80, self.lb_id,
|
constants.PROTOCOL_TCP, 80, self.lb_id,
|
||||||
@ -1586,6 +1823,8 @@ class TestListener(base.BaseAPITest):
|
|||||||
listener_id=api_listener['id'])
|
listener_id=api_listener['id'])
|
||||||
self.cert_manager_mock().get_cert.side_effect = [
|
self.cert_manager_mock().get_cert.side_effect = [
|
||||||
Exception("bad cert"), None, Exception("bad cert")]
|
Exception("bad cert"), None, Exception("bad cert")]
|
||||||
|
self.cert_manager_mock().get_secret.side_effect = [
|
||||||
|
Exception("bad secret"), Exception("bad secret")]
|
||||||
response = self.put(listener_path, body, status=400).json
|
response = self.put(listener_path, body, status=400).json
|
||||||
self.assertIn(tls_ref2, response['faultstring'])
|
self.assertIn(tls_ref2, response['faultstring'])
|
||||||
self.assertIn(sni1, response['faultstring'])
|
self.assertIn(sni1, response['faultstring'])
|
||||||
|
@ -2358,7 +2358,9 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
expected_client_ca_tls_container=None,
|
expected_client_ca_tls_container=None,
|
||||||
create_protocol=constants.PROTOCOL_HTTP,
|
create_protocol=constants.PROTOCOL_HTTP,
|
||||||
create_client_authentication=None,
|
create_client_authentication=None,
|
||||||
expected_client_authentication=constants.CLIENT_AUTH_NONE):
|
expected_client_authentication=constants.CLIENT_AUTH_NONE,
|
||||||
|
create_client_crl_container=None,
|
||||||
|
expected_client_crl_container=None):
|
||||||
create_listener = {
|
create_listener = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'protocol_port': protocol_port,
|
'protocol_port': protocol_port,
|
||||||
@ -2380,7 +2382,8 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
'timeout_tcp_inspect': constants.DEFAULT_TIMEOUT_TCP_INSPECT,
|
'timeout_tcp_inspect': constants.DEFAULT_TIMEOUT_TCP_INSPECT,
|
||||||
'tags': [],
|
'tags': [],
|
||||||
'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
|
||||||
}
|
}
|
||||||
if create_sni_containers:
|
if create_sni_containers:
|
||||||
create_listener['sni_container_refs'] = create_sni_containers
|
create_listener['sni_container_refs'] = create_sni_containers
|
||||||
@ -2402,6 +2405,9 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
if create_client_authentication:
|
if create_client_authentication:
|
||||||
create_listener['client_authentication'] = (
|
create_listener['client_authentication'] = (
|
||||||
create_client_authentication)
|
create_client_authentication)
|
||||||
|
if create_client_crl_container:
|
||||||
|
create_listener['client_crl_container_ref'] = (
|
||||||
|
create_client_crl_container)
|
||||||
if expected_sni_containers:
|
if expected_sni_containers:
|
||||||
expected_listener['sni_container_refs'] = expected_sni_containers
|
expected_listener['sni_container_refs'] = expected_sni_containers
|
||||||
if expected_l7policies:
|
if expected_l7policies:
|
||||||
@ -2416,6 +2422,9 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
if expected_client_authentication:
|
if expected_client_authentication:
|
||||||
expected_listener[
|
expected_listener[
|
||||||
'client_authentication'] = expected_client_authentication
|
'client_authentication'] = expected_client_authentication
|
||||||
|
if expected_client_crl_container:
|
||||||
|
expected_listener['client_crl_container_ref'] = (
|
||||||
|
expected_client_crl_container)
|
||||||
return create_listener, expected_listener
|
return create_listener, expected_listener
|
||||||
|
|
||||||
def _get_pool_bodies(self, name='pool1', create_members=None,
|
def _get_pool_bodies(self, name='pool1', create_members=None,
|
||||||
@ -2664,23 +2673,27 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
self._assert_graphs_equal(expected_lb, api_lb)
|
self._assert_graphs_equal(expected_lb, api_lb)
|
||||||
|
|
||||||
@mock.patch('cryptography.hazmat.backends.default_backend')
|
@mock.patch('cryptography.hazmat.backends.default_backend')
|
||||||
|
@mock.patch('cryptography.x509.load_pem_x509_crl')
|
||||||
@mock.patch('cryptography.x509.load_pem_x509_certificate')
|
@mock.patch('cryptography.x509.load_pem_x509_certificate')
|
||||||
@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')
|
||||||
def test_with_full_listener_certs(self, mock_cert_data, mock_get_secret,
|
def test_with_full_listener_certs(self, mock_cert_data, mock_get_secret,
|
||||||
mock_x509_cert, mock_backend):
|
mock_x509_cert, mock_x509_crl,
|
||||||
|
mock_backend):
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
|
mock_get_secret.side_effect = ['ca cert', 'X509 CRL FILE']
|
||||||
mock_cert_data.return_value = {'tls_cert': cert1,
|
mock_cert_data.return_value = {'tls_cert': cert1,
|
||||||
'sni_certs': [cert2, cert3]}
|
'sni_certs': [cert2, cert3]}
|
||||||
mock_get_secret.side_effect = ['ca cert']
|
|
||||||
cert_mock = mock.MagicMock()
|
cert_mock = mock.MagicMock()
|
||||||
mock_x509_cert.return_value = cert_mock
|
mock_x509_cert.return_value = cert_mock
|
||||||
create_client_ca_tls_container = uuidutils.generate_uuid()
|
create_client_ca_tls_container, create_client_crl_container = (
|
||||||
|
uuidutils.generate_uuid(), uuidutils.generate_uuid())
|
||||||
expected_client_ca_tls_container = create_client_ca_tls_container
|
expected_client_ca_tls_container = create_client_ca_tls_container
|
||||||
create_client_authentication = constants.CLIENT_AUTH_MANDATORY
|
create_client_authentication = constants.CLIENT_AUTH_MANDATORY
|
||||||
expected_client_authentication = constants.CLIENT_AUTH_MANDATORY
|
expected_client_authentication = constants.CLIENT_AUTH_MANDATORY
|
||||||
|
expected_client_crl_container = create_client_crl_container
|
||||||
create_sni_containers, expected_sni_containers = (
|
create_sni_containers, expected_sni_containers = (
|
||||||
self._get_sni_container_bodies())
|
self._get_sni_container_bodies())
|
||||||
create_listener, expected_listener = self._get_listener_bodies(
|
create_listener, expected_listener = self._get_listener_bodies(
|
||||||
@ -2690,7 +2703,9 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
|||||||
create_client_ca_tls_container=create_client_ca_tls_container,
|
create_client_ca_tls_container=create_client_ca_tls_container,
|
||||||
expected_client_ca_tls_container=expected_client_ca_tls_container,
|
expected_client_ca_tls_container=expected_client_ca_tls_container,
|
||||||
create_client_authentication=create_client_authentication,
|
create_client_authentication=create_client_authentication,
|
||||||
expected_client_authentication=expected_client_authentication)
|
expected_client_authentication=expected_client_authentication,
|
||||||
|
create_client_crl_container=create_client_crl_container,
|
||||||
|
expected_client_crl_container=expected_client_crl_container)
|
||||||
create_lb, expected_lb = self._get_lb_bodies(
|
create_lb, expected_lb = self._get_lb_bodies(
|
||||||
create_listeners=[create_listener],
|
create_listeners=[create_listener],
|
||||||
expected_listeners=[expected_listener])
|
expected_listeners=[expected_listener])
|
||||||
|
@ -66,7 +66,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||||||
|
|
||||||
# Build sample Listener and VIP configs
|
# Build sample Listener and VIP configs
|
||||||
self.sl = sample_configs.sample_listener_tuple(
|
self.sl = sample_configs.sample_listener_tuple(
|
||||||
tls=True, sni=True, client_ca_cert=True)
|
tls=True, sni=True, client_ca_cert=True, client_crl_cert=True)
|
||||||
self.sl_udp = sample_configs.sample_listener_tuple(
|
self.sl_udp = sample_configs.sample_listener_tuple(
|
||||||
proto=constants.PROTOCOL_UDP,
|
proto=constants.PROTOCOL_UDP,
|
||||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||||
@ -148,7 +148,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||||||
@mock.patch('octavia.common.tls_utils.cert_parser.get_host_names')
|
@mock.patch('octavia.common.tls_utils.cert_parser.get_host_names')
|
||||||
def test_update(self, mock_cert, mock_load_crt, mock_secret):
|
def test_update(self, mock_cert, mock_load_crt, mock_secret):
|
||||||
mock_cert.return_value = {'cn': sample_certs.X509_CERT_CN}
|
mock_cert.return_value = {'cn': sample_certs.X509_CERT_CN}
|
||||||
mock_secret.return_value = 'filename.pem'
|
mock_secret.side_effect = ['filename.pem', 'crl-filename.pem']
|
||||||
sconts = []
|
sconts = []
|
||||||
for sni_container in self.sl.sni_containers:
|
for sni_container in self.sl.sni_containers:
|
||||||
sconts.append(sni_container.tls_container)
|
sconts.append(sni_container.tls_container)
|
||||||
@ -168,7 +168,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||||||
self.driver.update(self.sl, self.sv)
|
self.driver.update(self.sl, self.sv)
|
||||||
|
|
||||||
# verify result
|
# verify result
|
||||||
# this is called 4 times
|
# this is called 5 times
|
||||||
gcm_calls = [
|
gcm_calls = [
|
||||||
mock.call(self.amp, self.sl.id,
|
mock.call(self.amp, self.sl.id,
|
||||||
self.sl.default_tls_container.id + '.pem',
|
self.sl.default_tls_container.id + '.pem',
|
||||||
@ -209,6 +209,11 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
|
|||||||
# start should be called once
|
# start should be called once
|
||||||
self.driver.client.reload_listener.assert_called_once_with(
|
self.driver.client.reload_listener.assert_called_once_with(
|
||||||
self.amp, self.sl.id)
|
self.amp, self.sl.id)
|
||||||
|
secret_calls = [
|
||||||
|
mock.call(self.sl, self.sl.client_ca_tls_certificate_id),
|
||||||
|
mock.call(self.sl, self.sl.client_crl_container_id)
|
||||||
|
]
|
||||||
|
mock_secret.assert_has_calls(secret_calls)
|
||||||
|
|
||||||
def test_udp_update(self):
|
def test_udp_update(self):
|
||||||
self.driver.udp_jinja.build_config.side_effect = ['fake_udp_config']
|
self.driver.udp_jinja.build_config.side_effect = ['fake_udp_config']
|
||||||
|
@ -38,6 +38,7 @@ class SampleDriverDataModels(object):
|
|||||||
self.sni_container_ref_1 = uuidutils.generate_uuid()
|
self.sni_container_ref_1 = uuidutils.generate_uuid()
|
||||||
self.sni_container_ref_2 = uuidutils.generate_uuid()
|
self.sni_container_ref_2 = uuidutils.generate_uuid()
|
||||||
self.client_ca_tls_certificate_ref = uuidutils.generate_uuid()
|
self.client_ca_tls_certificate_ref = uuidutils.generate_uuid()
|
||||||
|
self.client_crl_container_ref = uuidutils.generate_uuid()
|
||||||
|
|
||||||
self.pool1_id = uuidutils.generate_uuid()
|
self.pool1_id = uuidutils.generate_uuid()
|
||||||
self.pool2_id = uuidutils.generate_uuid()
|
self.pool2_id = uuidutils.generate_uuid()
|
||||||
@ -383,7 +384,8 @@ class SampleDriverDataModels(object):
|
|||||||
'timeout_member_data': 3000,
|
'timeout_member_data': 3000,
|
||||||
'timeout_tcp_inspect': 4000,
|
'timeout_tcp_inspect': 4000,
|
||||||
'client_ca_tls_certificate_id': self.client_ca_tls_certificate_ref,
|
'client_ca_tls_certificate_id': self.client_ca_tls_certificate_ref,
|
||||||
'client_authentication': constants.CLIENT_AUTH_NONE
|
'client_authentication': constants.CLIENT_AUTH_NONE,
|
||||||
|
'client_crl_container_id': self.client_crl_container_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
self.test_listener1_dict.update(self._common_test_dict)
|
self.test_listener1_dict.update(self._common_test_dict)
|
||||||
@ -397,6 +399,7 @@ class SampleDriverDataModels(object):
|
|||||||
del self.test_listener2_dict['l7policies']
|
del self.test_listener2_dict['l7policies']
|
||||||
del self.test_listener2_dict['sni_containers']
|
del self.test_listener2_dict['sni_containers']
|
||||||
del self.test_listener2_dict['client_ca_tls_certificate_id']
|
del self.test_listener2_dict['client_ca_tls_certificate_id']
|
||||||
|
del self.test_listener2_dict['client_crl_container_id']
|
||||||
|
|
||||||
self.test_listeners = [self.test_listener1_dict,
|
self.test_listeners = [self.test_listener1_dict,
|
||||||
self.test_listener2_dict]
|
self.test_listener2_dict]
|
||||||
@ -416,6 +419,7 @@ class SampleDriverDataModels(object):
|
|||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
ca_cert = 'ca cert'
|
ca_cert = 'ca cert'
|
||||||
|
crl_file_content = 'X509 CRL FILE'
|
||||||
|
|
||||||
self.provider_listener1_dict = {
|
self.provider_listener1_dict = {
|
||||||
'admin_state_up': True,
|
'admin_state_up': True,
|
||||||
@ -441,7 +445,9 @@ class SampleDriverDataModels(object):
|
|||||||
'timeout_tcp_inspect': 4000,
|
'timeout_tcp_inspect': 4000,
|
||||||
'client_ca_tls_container_ref': self.client_ca_tls_certificate_ref,
|
'client_ca_tls_container_ref': self.client_ca_tls_certificate_ref,
|
||||||
'client_ca_tls_container_data': ca_cert,
|
'client_ca_tls_container_data': ca_cert,
|
||||||
'client_authentication': constants.CLIENT_AUTH_NONE
|
'client_authentication': constants.CLIENT_AUTH_NONE,
|
||||||
|
'client_crl_container_ref': self.client_crl_container_ref,
|
||||||
|
'client_crl_container_data': crl_file_content
|
||||||
}
|
}
|
||||||
|
|
||||||
self.provider_listener2_dict = copy.deepcopy(
|
self.provider_listener2_dict = copy.deepcopy(
|
||||||
@ -456,6 +462,8 @@ class SampleDriverDataModels(object):
|
|||||||
del self.provider_listener2_dict['client_ca_tls_container_data']
|
del self.provider_listener2_dict['client_ca_tls_container_data']
|
||||||
self.provider_listener2_dict['client_authentication'] = (
|
self.provider_listener2_dict['client_authentication'] = (
|
||||||
constants.CLIENT_AUTH_NONE)
|
constants.CLIENT_AUTH_NONE)
|
||||||
|
self.provider_listener2_dict['client_crl_container_ref'] = None
|
||||||
|
del self.provider_listener2_dict['client_crl_container_data']
|
||||||
|
|
||||||
self.provider_listener1 = driver_dm.Listener(
|
self.provider_listener1 = driver_dm.Listener(
|
||||||
**self.provider_listener1_dict)
|
**self.provider_listener1_dict)
|
||||||
|
@ -90,7 +90,7 @@ class TestUtils(base.TestCase):
|
|||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
mock_secret.return_value = 'ca cert'
|
mock_secret.side_effect = ['ca cert', 'X509 CRL FILE']
|
||||||
mock_load_cert.return_value = {'tls_cert': cert1,
|
mock_load_cert.return_value = {'tls_cert': cert1,
|
||||||
'sni_certs': [cert2, cert3]}
|
'sni_certs': [cert2, cert3]}
|
||||||
test_lb_dict = {'name': 'lb1',
|
test_lb_dict = {'name': 'lb1',
|
||||||
@ -162,7 +162,7 @@ class TestUtils(base.TestCase):
|
|||||||
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
@mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
|
||||||
def test_db_listeners_to_provider_listeners(self, mock_load_cert,
|
def test_db_listeners_to_provider_listeners(self, mock_load_cert,
|
||||||
mock_secret):
|
mock_secret):
|
||||||
mock_secret.return_value = 'ca cert'
|
mock_secret.side_effect = ['ca cert', 'X509 CRL FILE']
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
@ -176,16 +176,24 @@ class TestUtils(base.TestCase):
|
|||||||
@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')
|
||||||
def test_listener_dict_to_provider_dict(self, mock_load_cert, mock_secret):
|
def test_listener_dict_to_provider_dict(self, mock_load_cert, mock_secret):
|
||||||
mock_secret.return_value = 'ca cert'
|
mock_secret.side_effect = ['ca cert', 'X509 CRL FILE']
|
||||||
cert1 = data_models.TLSContainer(certificate='cert 1')
|
cert1 = data_models.TLSContainer(certificate='cert 1')
|
||||||
cert2 = data_models.TLSContainer(certificate='cert 2')
|
cert2 = data_models.TLSContainer(certificate='cert 2')
|
||||||
cert3 = data_models.TLSContainer(certificate='cert 3')
|
cert3 = data_models.TLSContainer(certificate='cert 3')
|
||||||
mock_load_cert.return_value = {'tls_cert': cert1,
|
mock_load_cert.return_value = {'tls_cert': cert1,
|
||||||
'sni_certs': [cert2, cert3]}
|
'sni_certs': [cert2, cert3]}
|
||||||
|
# The reason to do this, as before the logic arrives the test func,
|
||||||
|
# there are two data sources, one is from db_dict, the other is from
|
||||||
|
# the api layer model_dict, actually, they are different and contain
|
||||||
|
# different fields. That's why the test_listener1_dict from sample data
|
||||||
|
# just contain the client_ca_tls_certificate_id for client certificate,
|
||||||
|
# not any other related fields. So we need to delete them.
|
||||||
|
expect_prov = copy.deepcopy(self.sample_data.provider_listener1_dict)
|
||||||
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)
|
||||||
self.assertEqual(self.sample_data.provider_listener1_dict,
|
expect_prov.pop('client_crl_container_ref')
|
||||||
provider_listener)
|
provider_listener.pop('client_crl_container_ref')
|
||||||
|
self.assertEqual(expect_prov, provider_listener)
|
||||||
|
|
||||||
@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')
|
||||||
|
@ -48,7 +48,6 @@ class TestBarbicanManager(base.TestCase):
|
|||||||
self.fake_secret = 'Fake secret'
|
self.fake_secret = 'Fake secret'
|
||||||
self.secret = secrets.Secret(api=mock.MagicMock(),
|
self.secret = secrets.Secret(api=mock.MagicMock(),
|
||||||
payload=self.fake_secret)
|
payload=self.fake_secret)
|
||||||
|
|
||||||
self.empty_secret = mock.Mock(spec=secrets.Secret)
|
self.empty_secret = mock.Mock(spec=secrets.Secret)
|
||||||
|
|
||||||
# Mock out the client
|
# Mock out the client
|
||||||
|
@ -40,7 +40,8 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
"sample_listener_id_1/tls_container_id.pem "
|
"sample_listener_id_1/tls_container_id.pem "
|
||||||
"crt /var/lib/octavia/certs/sample_listener_id_1 "
|
"crt /var/lib/octavia/certs/sample_listener_id_1 "
|
||||||
"ca-file /var/lib/octavia/certs/sample_listener_id_1/"
|
"ca-file /var/lib/octavia/certs/sample_listener_id_1/"
|
||||||
"client_ca.pem verify required\n"
|
"client_ca.pem verify required crl-file /var/lib/octavia/"
|
||||||
|
"certs/sample_listener_id_1/SHA_ID.pem\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" default_backend sample_pool_id_1\n"
|
" default_backend sample_pool_id_1\n"
|
||||||
" timeout client 50000\n\n").format(
|
" timeout client 50000\n\n").format(
|
||||||
@ -71,8 +72,10 @@ class TestHaproxyCfg(base.TestCase):
|
|||||||
sample_configs.sample_amphora_tuple(),
|
sample_configs.sample_amphora_tuple(),
|
||||||
sample_configs.sample_listener_tuple(proto='TERMINATED_HTTPS',
|
sample_configs.sample_listener_tuple(proto='TERMINATED_HTTPS',
|
||||||
tls=True, sni=True,
|
tls=True, sni=True,
|
||||||
client_ca_cert=True),
|
client_ca_cert=True,
|
||||||
tls_tupe, client_ca_filename='client_ca.pem')
|
client_crl_cert=True),
|
||||||
|
tls_tupe, client_ca_filename='client_ca.pem',
|
||||||
|
client_crl='SHA_ID.pem')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_configs.sample_base_expected_config(
|
sample_configs.sample_base_expected_config(
|
||||||
frontend=fe, backend=be),
|
frontend=fe, backend=be),
|
||||||
|
@ -856,3 +856,22 @@ pDEMmP7TJMJ3dG63RtAzQiGfRO18BIVOrRUfQpR32FkrYd9wCE02cnv0QZzY9NYt
|
|||||||
6hAlAa6Motve8UFewoO4pNknj3MBEN+64wDzHaP6VPysNJwrAlgaHfGDU6xJffAd
|
6hAlAa6Motve8UFewoO4pNknj3MBEN+64wDzHaP6VPysNJwrAlgaHfGDU6xJffAd
|
||||||
uCWDmw==
|
uCWDmw==
|
||||||
-----END CERTIFICATE-----"""
|
-----END CERTIFICATE-----"""
|
||||||
|
|
||||||
|
X509_CA_CRL = b"""-----BEGIN X509 CRL-----
|
||||||
|
MIIC7zCB2AIBATANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEPMA0GA1UE
|
||||||
|
CAwGT3JlZ29uMRIwEAYDVQQKDAlPcGVuU3RhY2sxEDAOBgNVBAsMB09jdGF2aWEx
|
||||||
|
FzAVBgNVBAMMDmNhLmV4YW1wbGUub3JnFw0xOTAyMTkwMjAxNTlaFw0xOTAzMjEw
|
||||||
|
MjAxNTlaMBUwEwICEAAXDTE5MDIxOTAyMDAyMlqgMDAuMB8GA1UdIwQYMBaAFN/4
|
||||||
|
bLQKWNMwoLzQ2du9NT33x7+DMAsGA1UdFAQEAgIQADANBgkqhkiG9w0BAQsFAAOC
|
||||||
|
AgEAcPtYSLEkJwvqaAfMGXwI2uTTKWURqtwfcBMYdVF1u2xsBsrKR6ogpBjzc1sX
|
||||||
|
A5WN9Tz5TXPVd38DTEGlCGLQ7wZ8wwYAR2sArHjw/zcsOJcFVTWtpX+2UAbpqis9
|
||||||
|
rBq7K6TF2m1fYb0RJg0AUbja/wfpghoEjfFx8FjIa8WAqqazyWR9vslm7kSoEgr+
|
||||||
|
MDV7agVK+h1n68hdLA9osUyPaAobus5FcVlXePPp5Ab8/vx1b2/Y+VXHaJXTZCin
|
||||||
|
FLQaxaH0PsMCKN/T52GPMRKa2Cc6IEaDFgE1ZlA8nP5t2tA7MFORI8dix6jIzBJD
|
||||||
|
W2CRf1Oxkrd3iqs1IljtlKHKMUTS67lfA9EwKlt8dR+KwH/WT23LSIoC9NnS3DP+
|
||||||
|
aT3t52soCpjXbfl8fgs62bome1/88BoNIa2T1Mj6F0aPvepLsFB/UrXWhADFj+DX
|
||||||
|
7WclP62BNBCTlUNvMF0eC9o7r5xeazo53KH1KI62qlFrz5MbRCG8g0JtTFqsMJld
|
||||||
|
phYuPfZekoNbsOIPDTiPFniuP2saOF4TSRCW4KnpgblRkds6c8X+1ExdlSo5GjNa
|
||||||
|
PftOKlYtE7T7Kw4CI9+O2H38IUOYjDt/c2twy954K4pKe4x9Ud8mImpS/oEzOsoz
|
||||||
|
/Mn++bjO55LdaAUKQ3wa8LZ5WFB+Gs6b2kmBfzGarWEiX64=
|
||||||
|
-----END X509 CRL-----"""
|
||||||
|
@ -512,7 +512,7 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
timeout_member_connect=5000,
|
timeout_member_connect=5000,
|
||||||
timeout_member_data=50000,
|
timeout_member_data=50000,
|
||||||
timeout_tcp_inspect=0,
|
timeout_tcp_inspect=0,
|
||||||
client_ca_cert=False):
|
client_ca_cert=False, client_crl_cert=False):
|
||||||
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 is 'TERMINATED_HTTPS' else proto
|
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
||||||
@ -527,8 +527,9 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
'sni_containers, load_balancer, peer_port, pools, '
|
'sni_containers, load_balancer, peer_port, pools, '
|
||||||
'l7policies, enabled, insert_headers, timeout_client_data,'
|
'l7policies, enabled, insert_headers, timeout_client_data,'
|
||||||
'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')
|
||||||
if l7:
|
if l7:
|
||||||
pools = [
|
pools = [
|
||||||
sample_pool_tuple(
|
sample_pool_tuple(
|
||||||
@ -614,7 +615,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
|||||||
) if client_ca_cert else '',
|
) if client_ca_cert else '',
|
||||||
client_authentication=(
|
client_authentication=(
|
||||||
constants.CLIENT_AUTH_MANDATORY if client_ca_cert else
|
constants.CLIENT_AUTH_MANDATORY if client_ca_cert else
|
||||||
constants.CLIENT_AUTH_NONE)
|
constants.CLIENT_AUTH_NONE),
|
||||||
|
client_crl_container_id='cont_id_crl' if client_crl_cert else '',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
You can now provide a certificate revocation list reference for listeners
|
||||||
|
using TLS client authentication.
|
||||||
|
security:
|
||||||
|
- |
|
||||||
|
Note that the amphora provider currently only supports the crl-file
|
||||||
|
provided to check for revocation. Remote revocation lists and/or OCSP
|
||||||
|
will not be used by the amphora provider.
|
Loading…
Reference in New Issue
Block a user