Add TLS support in etcd3 and etcd3gw drivers
The etcd3 and etcd3gw drivers parse CA, key and cert options from the coordination URL, and pass them on to the backend clients. The etcd3gw driver implements the "etcd3+https" scheme. Change-Id: I78d8ca0583f883f7f746791f82fbcc116458ce2c
This commit is contained in:
parent
ba27954b06
commit
a598cce62b
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The etcd3 and etcd3gw drivers now support TLS, by adding the ability to
|
||||
specify ca_cert, cert_key and cert_cert files. For the etcd3gw driver,
|
||||
this is controlled by specifying "etcd3+https" in the coordination URL.
|
@ -30,6 +30,7 @@ tooz.backends =
|
||||
etcd = tooz.drivers.etcd:EtcdDriver
|
||||
etcd3 = tooz.drivers.etcd3:Etcd3Driver
|
||||
etcd3+http = tooz.drivers.etcd3gw:Etcd3Driver
|
||||
etcd3+https = tooz.drivers.etcd3gw:Etcd3Driver
|
||||
kazoo = tooz.drivers.zookeeper:KazooDriver
|
||||
zake = tooz.drivers.zake:ZakeDriver
|
||||
memcached = tooz.drivers.memcached:MemcachedDriver
|
||||
@ -47,7 +48,7 @@ consul =
|
||||
etcd =
|
||||
requests>=2.10.0 # Apache-2.0
|
||||
etcd3 =
|
||||
etcd3>=0.6.2 # Apache-2.0
|
||||
etcd3>=0.12.0 # Apache-2.0
|
||||
grpcio>=1.18.0
|
||||
etcd3gw =
|
||||
etcd3gw>=0.1.0 # Apache-2.0
|
||||
|
@ -9,3 +9,4 @@ coverage>=3.6 # Apache-2.0
|
||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||
pifpaf>=0.10.0 # Apache-2.0
|
||||
stestr>=2.0.0
|
||||
ddt>=1.2.1 # MIT
|
||||
|
@ -126,7 +126,9 @@ class Etcd3Driver(coordination.CoordinationDriverCachedRunWatchers,
|
||||
================== =======
|
||||
Name Default
|
||||
================== =======
|
||||
protocol http
|
||||
ca_cert None
|
||||
cert_key None
|
||||
cert_cert None
|
||||
timeout 30
|
||||
lock_timeout 30
|
||||
membership_timeout 30
|
||||
@ -147,8 +149,16 @@ class Etcd3Driver(coordination.CoordinationDriverCachedRunWatchers,
|
||||
host = parsed_url.hostname or self.DEFAULT_HOST
|
||||
port = parsed_url.port or self.DEFAULT_PORT
|
||||
options = utils.collapse(options)
|
||||
ca_cert = options.get('ca_cert')
|
||||
cert_key = options.get('cert_key')
|
||||
cert_cert = options.get('cert_cert')
|
||||
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
||||
self.client = etcd3.client(host=host, port=port, timeout=timeout)
|
||||
self.client = etcd3.client(host=host,
|
||||
port=port,
|
||||
ca_cert=ca_cert,
|
||||
cert_key=cert_key,
|
||||
cert_cert=cert_cert,
|
||||
timeout=timeout)
|
||||
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
||||
self.membership_timeout = int(options.get(
|
||||
'membership_timeout', timeout))
|
||||
|
@ -169,15 +169,18 @@ class Etcd3Driver(coordination.CoordinationDriverWithExecutor):
|
||||
|
||||
The Etcd driver connection URI should look like::
|
||||
|
||||
etcd3+http://[HOST[:PORT]][?OPTION1=VALUE1[&OPTION2=VALUE2[&...]]]
|
||||
etcd3+PROTOCOL://[HOST[:PORT]][?OPTION1=VALUE1[&OPTION2=VALUE2[&...]]]
|
||||
|
||||
If not specified, HOST defaults to localhost and PORT defaults to 2379.
|
||||
The PROTOCOL can be http or https. If not specified, HOST defaults to
|
||||
localhost and PORT defaults to 2379.
|
||||
Available options are:
|
||||
|
||||
================== =======
|
||||
Name Default
|
||||
================== =======
|
||||
protocol http
|
||||
ca_cert None
|
||||
cert_key None
|
||||
cert_cert None
|
||||
timeout 30
|
||||
lock_timeout 30
|
||||
membership_timeout 30
|
||||
@ -197,11 +200,21 @@ class Etcd3Driver(coordination.CoordinationDriverWithExecutor):
|
||||
|
||||
def __init__(self, member_id, parsed_url, options):
|
||||
super(Etcd3Driver, self).__init__(member_id, parsed_url, options)
|
||||
protocol = 'https' if parsed_url.scheme.endswith('https') else 'http'
|
||||
host = parsed_url.hostname or self.DEFAULT_HOST
|
||||
port = parsed_url.port or self.DEFAULT_PORT
|
||||
options = utils.collapse(options)
|
||||
ca_cert = options.get('ca_cert')
|
||||
cert_key = options.get('cert_key')
|
||||
cert_cert = options.get('cert_cert')
|
||||
timeout = int(options.get('timeout', self.DEFAULT_TIMEOUT))
|
||||
self.client = etcd3gw.client(host=host, port=port, timeout=timeout)
|
||||
self.client = etcd3gw.client(host=host,
|
||||
port=port,
|
||||
protocol=protocol,
|
||||
ca_cert=ca_cert,
|
||||
cert_key=cert_key,
|
||||
cert_cert=cert_cert,
|
||||
timeout=timeout)
|
||||
self.lock_timeout = int(options.get('lock_timeout', timeout))
|
||||
self.membership_timeout = int(options.get(
|
||||
'membership_timeout', timeout))
|
||||
|
63
tooz/tests/drivers/test_etcd3.py
Normal file
63
tooz/tests/drivers/test_etcd3.py
Normal file
@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2020 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import ddt
|
||||
from testtools import testcase
|
||||
from unittest import mock
|
||||
|
||||
import tooz.coordination
|
||||
import tooz.drivers.etcd3 as etcd3_driver
|
||||
import tooz.tests
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestEtcd3(testcase.TestCase):
|
||||
FAKE_MEMBER_ID = tooz.tests.get_random_uuid()
|
||||
|
||||
@ddt.data({'coord_url': 'etcd3://',
|
||||
'host': etcd3_driver.Etcd3Driver.DEFAULT_HOST,
|
||||
'port': etcd3_driver.Etcd3Driver.DEFAULT_PORT,
|
||||
'ca_cert': None,
|
||||
'cert_key': None,
|
||||
'cert_cert': None,
|
||||
'timeout': etcd3_driver.Etcd3Driver.DEFAULT_TIMEOUT},
|
||||
{'coord_url': ('etcd3://my_host:666?ca_cert=/my/ca_cert&'
|
||||
'cert_key=/my/cert_key&cert_cert=/my/cert_cert&'
|
||||
'timeout=42'),
|
||||
'host': 'my_host',
|
||||
'port': 666,
|
||||
'ca_cert': '/my/ca_cert',
|
||||
'cert_key': '/my/cert_key',
|
||||
'cert_cert': '/my/cert_cert',
|
||||
'timeout': 42})
|
||||
@ddt.unpack
|
||||
@mock.patch('etcd3.client')
|
||||
def test_etcd3_client_init(self,
|
||||
mock_etcd3_client,
|
||||
coord_url,
|
||||
host,
|
||||
port,
|
||||
ca_cert,
|
||||
cert_key,
|
||||
cert_cert,
|
||||
timeout):
|
||||
tooz.coordination.get_coordinator(coord_url, self.FAKE_MEMBER_ID)
|
||||
mock_etcd3_client.assert_called_with(host=host,
|
||||
port=port,
|
||||
ca_cert=ca_cert,
|
||||
cert_key=cert_key,
|
||||
cert_cert=cert_cert,
|
||||
timeout=timeout)
|
67
tooz/tests/drivers/test_etcd3gw.py
Normal file
67
tooz/tests/drivers/test_etcd3gw.py
Normal file
@ -0,0 +1,67 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2020 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import ddt
|
||||
from testtools import testcase
|
||||
from unittest import mock
|
||||
|
||||
import tooz.coordination
|
||||
import tooz.drivers.etcd3gw as etcd3gw_driver
|
||||
import tooz.tests
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestEtcd3Gw(testcase.TestCase):
|
||||
FAKE_MEMBER_ID = tooz.tests.get_random_uuid()
|
||||
|
||||
@ddt.data({'coord_url': 'etcd3+http://',
|
||||
'protocol': 'http',
|
||||
'host': etcd3gw_driver.Etcd3Driver.DEFAULT_HOST,
|
||||
'port': etcd3gw_driver.Etcd3Driver.DEFAULT_PORT,
|
||||
'ca_cert': None,
|
||||
'cert_key': None,
|
||||
'cert_cert': None,
|
||||
'timeout': etcd3gw_driver.Etcd3Driver.DEFAULT_TIMEOUT},
|
||||
{'coord_url': ('etcd3+https://my_host:666?ca_cert=/my/ca_cert&'
|
||||
'cert_key=/my/cert_key&cert_cert=/my/cert_cert&'
|
||||
'timeout=42'),
|
||||
'protocol': 'https',
|
||||
'host': 'my_host',
|
||||
'port': 666,
|
||||
'ca_cert': '/my/ca_cert',
|
||||
'cert_key': '/my/cert_key',
|
||||
'cert_cert': '/my/cert_cert',
|
||||
'timeout': 42})
|
||||
@ddt.unpack
|
||||
@mock.patch('etcd3gw.client')
|
||||
def test_etcd3gw_client_init(self,
|
||||
mock_etcd3gw_client,
|
||||
coord_url,
|
||||
protocol,
|
||||
host,
|
||||
port,
|
||||
ca_cert,
|
||||
cert_key,
|
||||
cert_cert,
|
||||
timeout):
|
||||
tooz.coordination.get_coordinator(coord_url, self.FAKE_MEMBER_ID)
|
||||
mock_etcd3gw_client.assert_called_with(host=host,
|
||||
port=port,
|
||||
protocol=protocol,
|
||||
ca_cert=ca_cert,
|
||||
cert_key=cert_key,
|
||||
cert_cert=cert_cert,
|
||||
timeout=timeout)
|
Loading…
x
Reference in New Issue
Block a user