Merge "L7rule support client certificate cases"

This commit is contained in:
Zuul 2019-02-26 11:07:35 +00:00 committed by Gerrit Code Review
commit 612b042e64
11 changed files with 504 additions and 4 deletions

View File

@ -770,14 +770,16 @@ l7rule-key-optional:
l7rule-type:
description: |
The L7 rule type. One of ``COOKIE``, ``FILE_TYPE``, ``HEADER``,
``HOST_NAME``, or ``PATH``.
``HOST_NAME``, ``PATH``, ``SSL_CONN_HAS_CERT``, ``SSL_VERIFY_RESULT``,
or ``SSL_DN_FIELD``.
in: body
required: true
type: string
l7rule-type-optional:
description: |
The L7 rule type. One of ``COOKIE``, ``FILE_TYPE``, ``HEADER``,
``HOST_NAME``, or ``PATH``.
``HOST_NAME``, ``PATH``, ``SSL_CONN_HAS_CERT``, ``SSL_VERIFY_RESULT``,
or ``SSL_DN_FIELD``.
in: body
required: false
type: string

View File

@ -354,3 +354,67 @@ sent to *static_pool_B*, which is why *policy2* needs to be evaluated before
openstack loadbalancer l7rule create --compare-type EQUAL_TO --key site_version --type COOKIE --value B policy2
openstack loadbalancer l7policy create --action REDIRECT_TO_POOL --redirect-pool pool_B --name policy3 --position 2 listener1
openstack loadbalancer l7rule create --compare-type EQUAL_TO --key site_version --type COOKIE --value B policy3
Redirect requests with an invalid TLS client authentication certificate
-----------------------------------------------------------------------
**Scenario description**:
* Listener *listener1* on load balancer *lb1* is configured for ``OPTIONAL``
client_authentication.
* Web clients that do not present a TLS client authentication certificate
should be redirected to a signup page at *http://www.example.com/signup*.
**Solution**:
1. Create the load balancer *lb1*.
2. Create a listener *listner1* of type ``TERMINATED_TLS`` with a
client_ca_tls_container_ref and client_authentication ``OPTIONAL``.
3. Create a L7 Policy *policy1* on *listener1* with action ``REDIRECT_TO_URL``
pointed at the URL *http://www.example.com/signup*.
4. Add an L7 Rule to *policy1* that does not match ``SSL_CONN_HAS_CERT``.
**CLI commands**:
.. code-block:: bash
openstack loadbalancer create --name lb1 --vip-subnet-id public-subnet
openstack loadbalancer listener create --name listener1 --protocol TERMINATED_HTTPS --client-authentication OPTIONAL --protocol-port 443 --default-tls-container-ref http://192.0.2.15:9311/v1/secrets/697c2a6d-ffbe-40b8-be5e-7629fd636bca --client-ca-tls-container-ref http://192.0.2.15:9311/v1/secrets/dba60b77-8dad-4171-8a96-f21e1ca5fb46 lb1
openstack loadbalancer l7policy create --action REDIRECT_TO_URL --redirect-url http://www.example.com/signup --name policy1 listener1
openstack loadbalancer l7rule create --type SSL_CONN_HAS_CERT --invert --compare-type EQUAL_TO --value True policy1
Send users from the finance department to pool2
-----------------------------------------------
**Scenario description**:
* Users from the finance department have client certificates with the OU field
of the distinguished name set to ``finance``.
* Only users with valid finance department client certificates should be able
to access ``pool2``. Others will be rejected.
**Solution**:
1. Create the load balancer *lb1*.
2. Create a listener *listner1* of type ``TERMINATED_TLS`` with a
client_ca_tls_container_ref and client_authentication ``MANDATORY``.
3. Create a pool *pool2* on load balancer *lb1*.
4. Create a L7 Policy *policy1* on *listener1* with action ``REDIRECT_TO_POOL``
pointed at *pool2*.
5. Add an L7 Rule to *policy1* that matches ``SSL_CONN_HAS_CERT``.
6. Add an L7 Rule to *policy1* that matches ``SSL_VERIFY_RESULT`` with a value
of 0.
7. Add an L7 Rule to *policy1* of type ``SSL_DN_FIELD`` that looks for
"finance" in the "OU" field of the client authentication distinguished name.
**CLI commands**:
.. code-block:: bash
openstack loadbalancer create --name lb1 --vip-subnet-id public-subnet
openstack loadbalancer listener create --name listener1 --protocol TERMINATED_HTTPS --client-authentication MANDATORY --protocol-port 443 --default-tls-container-ref http://192.0.2.15:9311/v1/secrets/697c2a6d-ffbe-40b8-be5e-7629fd636bca --client-ca-tls-container-ref http://192.0.2.15:9311/v1/secrets/dba60b77-8dad-4171-8a96-f21e1ca5fb46 lb1
openstack loadbalancer pool create --lb-algorithm ROUND_ROBIN --loadbalancer lb1 --name pool2 --protocol HTTP
openstack loadbalancer l7policy create --action REDIRECT_TO_POOL --redirect-pool pool2 --name policy1 listener1
openstack loadbalancer l7rule create --type SSL_CONN_HAS_CERT --compare-type EQUAL_TO --value True policy1
openstack loadbalancer l7rule create --type SSL_VERIFY_RESULT --compare-type EQUAL_TO --value 0 policy1
openstack loadbalancer l7rule create --type SSL_DN_FIELD --compare-type EQUAL_TO --key OU --value finance policy1

View File

@ -86,6 +86,15 @@ L7 rules have the following types:
compares it against the value parameter in the rule.
* ``COOKIE``: The rule looks for a cookie named by the key parameter and
compares it against the value parameter in the rule.
* ``SSL_CONN_HAS_CERT``: The rule will match if the client has presented a
certificate for TLS client authentication. This does not imply the
certificate is valid.
* ``SSL_VERIFY_RESULT``: This rule will match the TLS client authentication
certificate validation result. A value of '0' means the certificate was
successfully validated. A value greater than '0' means the certificate
failed validation. This value follows the `openssl-verify result codes <https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h#L99>`_.
* ``SSL_DN_FIELD``: The rule looks for a Distinguished Name feild defined in
the key parameter and compares it against the value parameter in the rule.
Comparison types
________________
@ -183,3 +192,4 @@ Useful links
* `Octavia API Reference <https://developer.openstack.org/api-ref/load-balancer/>`_
* `LBaaS Layer 7 rules <https://github.com/openstack/neutron-specs/blob/master/specs/mitaka/lbaas-l7-rules.rst>`_
* `Using ACLs and fetching samples <http://cbonte.github.io/haproxy-dconv/1.6/configuration.html#7>`_
* `OpenSSL openssl-verify command <https://www.openssl.org/docs/manmaster/man1/openssl-verify.html>`_

View File

@ -143,9 +143,15 @@ L7RULE_TYPE_PATH = 'PATH'
L7RULE_TYPE_FILE_TYPE = 'FILE_TYPE'
L7RULE_TYPE_HEADER = 'HEADER'
L7RULE_TYPE_COOKIE = 'COOKIE'
L7RULE_TYPE_SSL_CONN_HAS_CERT = 'SSL_CONN_HAS_CERT'
L7RULE_TYPE_SSL_VERIFY_RESULT = 'SSL_VERIFY_RESULT'
L7RULE_TYPE_SSL_DN_FIELD = 'SSL_DN_FIELD'
SUPPORTED_L7RULE_TYPES = (L7RULE_TYPE_HOST_NAME, L7RULE_TYPE_PATH,
L7RULE_TYPE_FILE_TYPE, L7RULE_TYPE_HEADER,
L7RULE_TYPE_COOKIE)
L7RULE_TYPE_COOKIE, L7RULE_TYPE_SSL_CONN_HAS_CERT,
L7RULE_TYPE_SSL_VERIFY_RESULT,
L7RULE_TYPE_SSL_DN_FIELD)
DISTINGUISHED_NAME_FIELD_REGEX = '^([a-zA-Z][A-Za-z0-9-]*)$'
L7RULE_COMPARE_TYPE_REGEX = 'REGEX'
L7RULE_COMPARE_TYPE_STARTS_WITH = 'STARTS_WITH'

View File

@ -86,6 +86,14 @@ bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
acl {{ l7rule.id }} req.cook({{ l7rule.key }}) {{
l7rule_compare_type_macro(
constants, l7rule.compare_type) }} {{ l7rule.value }}
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_CONN_HAS_CERT %}
acl {{ l7rule.id }} ssl_c_used
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_VERIFY_RESULT %}
acl {{ l7rule.id }} ssl_c_verify eq {{ l7rule.value }}
{% elif l7rule.type == constants.L7RULE_TYPE_SSL_DN_FIELD %}
acl {{ l7rule.id }} ssl_c_s_dn({{ l7rule.key }}) {{
l7rule_compare_type_macro(
constants, l7rule.compare_type) }} {{ l7rule.value }}
{% endif %}
{% endmacro %}

View File

@ -26,6 +26,7 @@ import netaddr
from oslo_config import cfg
import rfc3986
import six
from wsme import types as wtypes
from octavia.common import constants
from octavia.common import exceptions
@ -161,11 +162,72 @@ def l7rule_data(l7rule):
raise exceptions.InvalidL7Rule(msg='invalid comparison type '
'for rule type')
elif l7rule.type in [constants.L7RULE_TYPE_SSL_CONN_HAS_CERT,
constants.L7RULE_TYPE_SSL_VERIFY_RESULT,
constants.L7RULE_TYPE_SSL_DN_FIELD]:
validate_l7rule_ssl_types(l7rule)
else:
raise exceptions.InvalidL7Rule(msg='invalid rule type')
return True
def validate_l7rule_ssl_types(l7rule):
if not l7rule.type or l7rule.type not in [
constants.L7RULE_TYPE_SSL_CONN_HAS_CERT,
constants.L7RULE_TYPE_SSL_VERIFY_RESULT,
constants.L7RULE_TYPE_SSL_DN_FIELD]:
return
rule_type = None if l7rule.type == wtypes.Unset else l7rule.type
req_key = None if l7rule.key == wtypes.Unset else l7rule.key
req_value = None if l7rule.value == wtypes.Unset else l7rule.value
compare_type = (None if l7rule.compare_type == wtypes.Unset else
l7rule.compare_type)
msg = None
if rule_type == constants.L7RULE_TYPE_SSL_CONN_HAS_CERT:
# key and value are not allowed
if req_key:
# log error or raise
msg = 'L7rule type {0} does not use the "key" field.'.format(
rule_type)
elif req_value.lower() != 'true':
msg = 'L7rule value {0} is not a boolean True string.'.format(
req_value)
elif compare_type != constants.L7RULE_COMPARE_TYPE_EQUAL_TO:
msg = 'L7rule type {0} only supports the {1} compare type.'.format(
rule_type, constants.L7RULE_COMPARE_TYPE_EQUAL_TO)
if rule_type == constants.L7RULE_TYPE_SSL_VERIFY_RESULT:
if req_key:
# log or raise req_key not used
msg = 'L7rule type {0} does not use the "key" field.'.format(
rule_type)
elif not req_value.isdigit() or int(req_value) < 0:
# log or raise req_value must be int
msg = 'L7rule type {0} needs a int value, which is >= 0'.format(
rule_type)
elif compare_type != constants.L7RULE_COMPARE_TYPE_EQUAL_TO:
msg = 'L7rule type {0} only supports the {1} compare type.'.format(
rule_type, constants.L7RULE_COMPARE_TYPE_EQUAL_TO)
if rule_type == constants.L7RULE_TYPE_SSL_DN_FIELD:
dn_regex = re.compile(constants.DISTINGUISHED_NAME_FIELD_REGEX)
if compare_type == constants.L7RULE_COMPARE_TYPE_REGEX:
regex(l7rule.value)
if not req_key or not req_value:
# log or raise key and value must be specified.
msg = 'L7rule type {0} needs to specify a key and a value.'.format(
rule_type)
# log or raise the key must be splited by '-'
elif not dn_regex.match(req_key):
msg = ('Invalid L7rule distinguished name field.')
if msg:
raise exceptions.InvalidL7Rule(msg=msg)
def sanitize_l7policy_api_args(l7policy, create=False):
"""Validate and make consistent L7Policy API arguments.

View File

@ -0,0 +1,44 @@
# 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.
#
"""Extend the l7rule type for support client certificate cases
Revision ID: 1afc932f1ca2
Revises: ffad172e98c1
Create Date: 2018-10-03 20:47:52.405865
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import sql
# revision identifiers, used by Alembic.
revision = '1afc932f1ca2'
down_revision = 'ffad172e98c1'
new_fields = ['SSL_CONN_HAS_CERT', 'SSL_VERIFY_RESULT', 'SSL_DN_FIELD']
def upgrade():
insert_table = sql.table(
u'l7rule_type',
sql.column(u'name', sa.String),
sql.column(u'description', sa.String)
)
cows = [{'name': field} for field in new_fields]
op.bulk_insert(insert_table, cows)

View File

@ -682,6 +682,135 @@ class TestL7Rule(base.BaseAPITest):
self.assertIn('Provider \'bad_driver\' reports error: broken',
response.json.get('faultstring'))
def test_create_with_ssl_rule_types(self):
test_mapping = {
constants.L7RULE_TYPE_SSL_CONN_HAS_CERT: {
'value': 'tRuE',
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO},
constants.L7RULE_TYPE_SSL_VERIFY_RESULT: {
'value': '0',
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO},
constants.L7RULE_TYPE_SSL_DN_FIELD: {
'key': 'st-1', 'value': 'ST-FIELD1-PREFIX',
'compare_type': constants.L7RULE_COMPARE_TYPE_STARTS_WITH}
}
for l7rule_type, test_body in test_mapping.items():
self.set_lb_status(self.lb_id)
test_body.update({'type': l7rule_type})
api_l7rule = self.create_l7rule(
self.l7policy_id, l7rule_type,
test_body['compare_type'], test_body['value'],
key=test_body.get('key')).get(self.root_tag)
self.assertEqual(l7rule_type, api_l7rule.get('type'))
self.assertEqual(test_body['compare_type'],
api_l7rule.get('compare_type'))
self.assertEqual(test_body['value'], api_l7rule.get('value'))
if test_body.get('key'):
self.assertEqual(test_body['key'], api_l7rule.get('key'))
self.assertFalse(api_l7rule.get('invert'))
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=self.l7policy_id, l7rule_id=api_l7rule.get('id'),
lb_prov_status=constants.PENDING_UPDATE,
listener_prov_status=constants.PENDING_UPDATE,
l7policy_prov_status=constants.PENDING_UPDATE,
l7rule_prov_status=constants.PENDING_CREATE,
l7rule_op_status=constants.OFFLINE)
def _test_bad_cases_with_ssl_rule_types(self, is_create=True,
rule_id=None):
if is_create:
req_func = self.post
first_req_arg = self.l7rules_path
else:
req_func = self.put
first_req_arg = self.l7rule_path.format(l7rule_id=rule_id)
# test bad cases of L7RULE_TYPE_SSL_CONN_HAS_CERT
l7rule = {'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
'invert': False,
'type': constants.L7RULE_TYPE_SSL_CONN_HAS_CERT,
'value': 'true',
'admin_state_up': True,
'key': 'no-need-key'}
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn('L7rule type {0} does not use the "key" field.'.format(
constants.L7RULE_TYPE_SSL_CONN_HAS_CERT),
response.get('faultstring'))
l7rule.pop('key')
l7rule['value'] = 'not-true-string'
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule value {0} is not a boolean True string.'.format(
l7rule['value']), response.get('faultstring'))
l7rule['value'] = 'tRUe'
l7rule['compare_type'] = constants.L7RULE_COMPARE_TYPE_STARTS_WITH
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule type {0} only supports the {1} compare type.'.format(
constants.L7RULE_TYPE_SSL_CONN_HAS_CERT,
constants.L7RULE_COMPARE_TYPE_EQUAL_TO),
response.get('faultstring'))
# test bad cases of L7RULE_TYPE_SSL_VERIFY_RES
l7rule = {'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
'invert': False,
'type': constants.L7RULE_TYPE_SSL_VERIFY_RESULT,
'value': 'true',
'admin_state_up': True,
'key': 'no-need-key'}
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule type {0} does not use the "key" field.'.format(
l7rule['type']), response.get('faultstring'))
l7rule.pop('key')
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule type {0} needs a int value, which is >= 0'.format(
l7rule['type']), response.get('faultstring'))
l7rule['value'] = '0'
l7rule['compare_type'] = constants.L7RULE_COMPARE_TYPE_STARTS_WITH
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule type {0} only supports the {1} compare type.'.format(
l7rule['type'], constants.L7RULE_COMPARE_TYPE_EQUAL_TO),
response.get('faultstring'))
# test bad cases of L7RULE_TYPE_SSL_DN_FIELD
l7rule = {'compare_type': constants.L7RULE_COMPARE_TYPE_REGEX,
'invert': False,
'type': constants.L7RULE_TYPE_SSL_DN_FIELD,
'value': 'bad regex\\',
'admin_state_up': True}
# This case just test that fail to parse the regex from the value
req_func(first_req_arg, self._build_body(l7rule), status=400).json
l7rule['value'] = '^.test*$'
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn(
'L7rule type {0} needs to specify a key and a value.'.format(
l7rule['type']), response.get('faultstring'))
l7rule['key'] = 'NOT_SUPPORTED_DN_FIELD'
response = req_func(first_req_arg, self._build_body(l7rule),
status=400).json
self.assertIn('Invalid L7rule distinguished name field.',
response.get('faultstring'))
def test_create_bad_cases_with_ssl_rule_types(self):
self._test_bad_cases_with_ssl_rule_types()
def test_update(self):
api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_PATH,
@ -811,6 +940,53 @@ class TestL7Rule(base.BaseAPITest):
l7policy_id=self.l7policy_id, l7rule_id=api_l7rule.get('id'),
l7rule_prov_status=constants.ACTIVE)
def test_update_with_ssl_rule_types(self):
test_mapping = {
constants.L7RULE_TYPE_SSL_CONN_HAS_CERT: {
'value': 'tRuE',
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO},
constants.L7RULE_TYPE_SSL_VERIFY_RESULT: {
'value': '0',
'compare_type': constants.L7RULE_COMPARE_TYPE_EQUAL_TO},
constants.L7RULE_TYPE_SSL_DN_FIELD: {
'key': 'st-1', 'value': 'ST-FIELD1-PREFIX',
'compare_type': constants.L7RULE_COMPARE_TYPE_STARTS_WITH}
}
for l7rule_type, test_body in test_mapping.items():
self.set_lb_status(self.lb_id)
api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_PATH,
constants.L7RULE_COMPARE_TYPE_STARTS_WITH,
'/api').get(self.root_tag)
self.set_lb_status(self.lb_id)
test_body.update({'type': l7rule_type})
response = self.put(self.l7rule_path.format(
l7rule_id=api_l7rule.get('id')),
self._build_body(test_body)).json.get(self.root_tag)
self.assertEqual(l7rule_type, response.get('type'))
self.assertEqual(test_body['compare_type'],
response.get('compare_type'))
self.assertEqual(test_body['value'], response.get('value'))
if test_body.get('key'):
self.assertEqual(test_body['key'], response.get('key'))
self.assertFalse(response.get('invert'))
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=self.l7policy_id, l7rule_id=response.get('id'),
lb_prov_status=constants.PENDING_UPDATE,
listener_prov_status=constants.PENDING_UPDATE,
l7policy_prov_status=constants.PENDING_UPDATE,
l7rule_prov_status=constants.PENDING_UPDATE)
def test_update_bad_cases_with_ssl_rule_types(self):
api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_PATH,
constants.L7RULE_COMPARE_TYPE_STARTS_WITH,
'/api').get(self.root_tag)
self._test_bad_cases_with_ssl_rule_types(
is_create=False, rule_id=api_l7rule.get('id'))
def test_delete(self):
api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_PATH,

View File

@ -942,3 +942,85 @@ class TestHaproxyCfg(base.TestCase):
self.assertEqual(
sample_configs.sample_base_expected_config(backend=be),
rendered_obj)
def test_ssl_types_l7rules(self):
j_cfg = jinja_cfg.JinjaTemplater(
base_amp_path='/var/lib/octavia',
base_crt_dir='/var/lib/octavia/certs')
fe = ("frontend sample_listener_id_1\n"
" option httplog\n"
" maxconn 1000000\n"
" redirect scheme https if !{ ssl_fc }\n"
" bind 10.0.0.2:443\n"
" mode http\n"
" acl sample_l7rule_id_1 path -m beg /api\n"
" use_backend sample_pool_id_2 if sample_l7rule_id_1\n"
" acl sample_l7rule_id_2 req.hdr(Some-header) -m sub "
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect location http://www.example.com "
"if !sample_l7rule_id_2 sample_l7rule_id_3\n"
" acl sample_l7rule_id_4 path_end -m str jpg\n"
" acl sample_l7rule_id_5 req.hdr(host) -i -m end "
".example.com\n"
" http-request deny "
"if sample_l7rule_id_4 sample_l7rule_id_5\n"
" acl sample_l7rule_id_2 req.hdr(Some-header) -m sub "
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect prefix https://example.com "
"if !sample_l7rule_id_2 sample_l7rule_id_3\n"
" acl sample_l7rule_id_7 ssl_c_used\n"
" acl sample_l7rule_id_8 ssl_c_verify eq 1\n"
" acl sample_l7rule_id_9 ssl_c_s_dn(STREET) -m reg "
"^STREET.*NO\\\\.$\n"
" acl sample_l7rule_id_10 ssl_c_s_dn(OU-3) -m beg "
"Orgnization\\ Bala\n"
" acl sample_l7rule_id_11 path -m beg /api\n"
" redirect location http://www.ssl-type-l7rule-test.com "
"if sample_l7rule_id_7 !sample_l7rule_id_8 !sample_l7rule_id_9 "
"!sample_l7rule_id_10 sample_l7rule_id_11\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
" cookie SRV insert indirect nocache\n"
" timeout check 31s\n"
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 1000000\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 weight 13 check "
"inter 30s fall 3 rise 2 cookie sample_member_id_1\n"
" server sample_member_id_2 10.0.0.98:82 weight 13 check "
"inter 30s fall 3 rise 2 cookie sample_member_id_2\n\n"
"backend sample_pool_id_2\n"
" mode http\n"
" balance roundrobin\n"
" cookie SRV insert indirect nocache\n"
" timeout check 31s\n"
" option httpchk GET /healthmon.html\n"
" http-check expect rstatus 418\n"
" fullconn 1000000\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
sample_listener = sample_configs.sample_listener_tuple(
proto=constants.PROTOCOL_TERMINATED_HTTPS, l7=True,
ssl_type_l7=True)
rendered_obj = j_cfg.build_config(
sample_configs.sample_amphora_tuple(),
sample_listener,
tls_cert=None,
haproxy_versions=("1", "5", "18"))
self.assertEqual(
sample_configs.sample_base_expected_config(
frontend=fe, backend=be),
rendered_obj)

View File

@ -512,7 +512,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
timeout_member_connect=5000,
timeout_member_data=50000,
timeout_tcp_inspect=0,
client_ca_cert=False, client_crl_cert=False):
client_ca_cert=False, client_crl_cert=False,
ssl_type_l7=False):
proto = 'HTTP' if proto is None else proto
if be_proto is None:
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
@ -550,6 +551,9 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
sample_l7policy_tuple('sample_l7policy_id_5', sample_policy=5),
sample_l7policy_tuple('sample_l7policy_id_6', sample_policy=6),
sample_l7policy_tuple('sample_l7policy_id_7', sample_policy=7)]
if ssl_type_l7:
l7policies.append(sample_l7policy_tuple(
'sample_l7policy_id_8', sample_policy=8))
else:
pools = [
sample_pool_tuple(
@ -799,6 +803,14 @@ def sample_l7policy_tuple(id,
redirect_prefix = 'https://example.com'
l7rules = [sample_l7rule_tuple('sample_l7rule_id_2', sample_rule=2),
sample_l7rule_tuple('sample_l7rule_id_3', sample_rule=3)]
elif sample_policy == 8:
action = constants.L7POLICY_ACTION_REDIRECT_TO_URL
redirect_url = 'http://www.ssl-type-l7rule-test.com'
l7rules = [sample_l7rule_tuple('sample_l7rule_id_7', sample_rule=7),
sample_l7rule_tuple('sample_l7rule_id_8', sample_rule=8),
sample_l7rule_tuple('sample_l7rule_id_9', sample_rule=9),
sample_l7rule_tuple('sample_l7rule_id_10', sample_rule=10),
sample_l7rule_tuple('sample_l7rule_id_11', sample_rule=11)]
return in_l7policy(
id=id,
action=action,
@ -855,6 +867,34 @@ def sample_l7rule_tuple(id,
value = '.example.com'
invert = False
enabled = False
if sample_rule == 7:
type = constants.L7RULE_TYPE_SSL_CONN_HAS_CERT
compare_type = constants.L7RULE_COMPARE_TYPE_EQUAL_TO
key = None
value = 'tRuE'
invert = False
enabled = True
if sample_rule == 8:
type = constants.L7RULE_TYPE_SSL_VERIFY_RESULT
compare_type = constants.L7RULE_COMPARE_TYPE_EQUAL_TO
key = None
value = '1'
invert = True
enabled = True
if sample_rule == 9:
type = constants.L7RULE_TYPE_SSL_DN_FIELD
compare_type = constants.L7RULE_COMPARE_TYPE_REGEX
key = 'STREET'
value = '^STREET.*NO\.$'
invert = True
enabled = True
if sample_rule == 10:
type = constants.L7RULE_TYPE_SSL_DN_FIELD
compare_type = constants.L7RULE_COMPARE_TYPE_STARTS_WITH
key = 'OU-3'
value = 'Orgnization Bala'
invert = True
enabled = True
return in_l7rule(
id=id,
type=type,

View File

@ -0,0 +1,6 @@
---
features:
- |
Adds the ability to define L7 rules based on TLS client authentication
information. The new L7 rules are\: "L7RULE_TYPE_SSL_CONN_HAS_CERT",
"L7RULE_TYPE_VERIFY_RESULT", and "L7RULE_TYPE_DN_FIELD".