diff --git a/fuel_ccp_entrypoint/start_script.py b/fuel_ccp_entrypoint/start_script.py index b854190..856982b 100644 --- a/fuel_ccp_entrypoint/start_script.py +++ b/fuel_ccp_entrypoint/start_script.py @@ -24,6 +24,7 @@ import six VARIABLES = {} GLOBALS_PATH = '/etc/ccp/globals/globals.json' META_FILE = "/etc/ccp/meta/meta.json" +CACERT = "/etc/ccp/tls/ca.pem" WORKFLOW_PATH_TEMPLATE = '/etc/ccp/role/%s.json' FILES_DIR = '/etc/ccp/files' EXPORTS_DIR = '/etc/ccp/exports' @@ -291,24 +292,39 @@ def create_files(files): @retry def get_etcd_client(): + if VARIABLES["security"]["tls"]["enabled"]: + LOG.debug("TLS is enabled for etcd, using encrypted connectivity") + scheme = "https" + ca_cert = CACERT + else: + scheme = "http" + ca_cert = None + etcd_machines = [] # if it's etcd container use local address because container is not # accessible via service due failed readiness check if VARIABLES["role_name"] in ["etcd", "etcd-leader-elector", "etcd-watcher"]: + if VARIABLES["security"]["tls"]["enabled"]: + # If it's etcd container, connectivity goes over IP address, thus + # TLS connection will fail. Need to reuse non-TLS + # https://github.com/coreos/etcd/issues/4311 + scheme = "http" + ca_cert = None + etcd_address = '127.0.0.1' + else: + etcd_address = VARIABLES["network_topology"]["private"]["address"] etcd_machines.append( - (VARIABLES["network_topology"]["private"]["address"], - VARIABLES["etcd"]["client_port"]['cont'])) + (etcd_address, VARIABLES["etcd"]["client_port"]['cont'])) else: etcd_machines.append( (address('etcd'), VARIABLES["etcd"]["client_port"]['cont']) ) - etcd_machines_str = " ".join(["%s:%d" % (h, p) for h, p in etcd_machines]) LOG.debug("Using the following etcd urls: \"%s\"", etcd_machines_str) return etcd.Client(host=tuple(etcd_machines), allow_reconnect=True, - read_timeout=2) + read_timeout=2, protocol=scheme, ca_cert=ca_cert) def check_dependence(dep, etcd_client): diff --git a/fuel_ccp_entrypoint/tests/test_fuel_ccp_entrypoint.py b/fuel_ccp_entrypoint/tests/test_fuel_ccp_entrypoint.py index 51d8f63..f236b94 100644 --- a/fuel_ccp_entrypoint/tests/test_fuel_ccp_entrypoint.py +++ b/fuel_ccp_entrypoint/tests/test_fuel_ccp_entrypoint.py @@ -142,6 +142,11 @@ class TestGetETCDClient(base.TestCase): "private": { "address": "192.0.2.1" } + }, + "security": { + "tls": { + "enabled": False + } } } with mock.patch("etcd.Client") as m_etcd: @@ -152,7 +157,9 @@ class TestGetETCDClient(base.TestCase): m_etcd.assert_called_once_with( host=(("192.0.2.1", 10042),), allow_reconnect=True, - read_timeout=2) + read_timeout=2, + protocol='http', + ca_cert=None) def test_get_etcd_client(self): start_script.VARIABLES = { @@ -166,6 +173,11 @@ class TestGetETCDClient(base.TestCase): "connection_attempts": 3, "connection_delay": 0, }, + "security": { + "tls": { + "enabled": False + } + } } with mock.patch("etcd.Client") as m_etcd: expected_value = object() @@ -175,7 +187,39 @@ class TestGetETCDClient(base.TestCase): m_etcd.assert_called_once_with( host=(('etcd.ccp.svc.cluster.local', 1234),), allow_reconnect=True, - read_timeout=2) + read_timeout=2, + protocol='http', + ca_cert=None) + + def test_get_secured_etcd_client(self): + start_script.VARIABLES = { + "role_name": "banana", + "namespace": "ccp", + "cluster_domain": 'cluster.local', + "etcd": { + "client_port": { + "cont": 1234 + }, + "connection_attempts": 3, + "connection_delay": 0, + }, + "security": { + "tls": { + "enabled": True + } + } + } + with mock.patch("etcd.Client") as m_etcd: + expected_value = object() + m_etcd.return_value = expected_value + etcd_client = start_script.get_etcd_client() + self.assertIs(expected_value, etcd_client) + m_etcd.assert_called_once_with( + host=(('etcd.ccp.svc.cluster.local', 1234),), + allow_reconnect=True, + read_timeout=2, + protocol='https', + ca_cert='/etc/ccp/tls/ca.pem') def test_get_etcd_client_wrong(self): start_script.VARIABLES = {