Add support for TLS-enabled etcd

This requires /etc/ccp/ca.pem to be present in a pod

Change-Id: I574d64082e77f49024f49aa7b30c4f2f6cc044ac
This commit is contained in:
Aleksandr Mogylchenko 2017-01-18 17:23:01 +01:00
parent ff6efca2c8
commit 2920bdd297
2 changed files with 36 additions and 6 deletions

View File

@ -24,6 +24,7 @@ import six
VARIABLES = {} VARIABLES = {}
GLOBALS_PATH = '/etc/ccp/globals/globals.json' GLOBALS_PATH = '/etc/ccp/globals/globals.json'
META_FILE = "/etc/ccp/meta/meta.json" META_FILE = "/etc/ccp/meta/meta.json"
CACERT = "/etc/ccp/ca.pem"
WORKFLOW_PATH_TEMPLATE = '/etc/ccp/role/%s.json' WORKFLOW_PATH_TEMPLATE = '/etc/ccp/role/%s.json'
FILES_DIR = '/etc/ccp/files' FILES_DIR = '/etc/ccp/files'
EXPORTS_DIR = '/etc/ccp/exports' EXPORTS_DIR = '/etc/ccp/exports'
@ -292,24 +293,39 @@ def create_files(files):
@retry @retry
def get_etcd_client(): 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 = [] etcd_machines = []
# if it's etcd container use local address because container is not # if it's etcd container use local address because container is not
# accessible via service due failed readiness check # accessible via service due failed readiness check
if VARIABLES["role_name"] in ["etcd", "etcd-leader-elector", if VARIABLES["role_name"] in ["etcd", "etcd-leader-elector",
"etcd-watcher"]: "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( etcd_machines.append(
(VARIABLES["network_topology"]["private"]["address"], (etcd_address, VARIABLES["etcd"]["client_port"]['cont']))
VARIABLES["etcd"]["client_port"]['cont']))
else: else:
etcd_machines.append( etcd_machines.append(
(address('etcd'), VARIABLES["etcd"]["client_port"]['cont']) (address('etcd'), VARIABLES["etcd"]["client_port"]['cont'])
) )
etcd_machines_str = " ".join(["%s:%d" % (h, p) for h, p in etcd_machines]) 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) LOG.debug("Using the following etcd urls: \"%s\"", etcd_machines_str)
return etcd.Client(host=tuple(etcd_machines), allow_reconnect=True, 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): def check_dependence(dep, etcd_client):

View File

@ -142,6 +142,11 @@ class TestGetETCDClient(base.TestCase):
"private": { "private": {
"address": "192.0.2.1" "address": "192.0.2.1"
} }
},
"security": {
"tls": {
"enabled": False
}
} }
} }
with mock.patch("etcd.Client") as m_etcd: with mock.patch("etcd.Client") as m_etcd:
@ -152,7 +157,9 @@ class TestGetETCDClient(base.TestCase):
m_etcd.assert_called_once_with( m_etcd.assert_called_once_with(
host=(("192.0.2.1", 10042),), host=(("192.0.2.1", 10042),),
allow_reconnect=True, allow_reconnect=True,
read_timeout=2) read_timeout=2,
protocol='http',
ca_cert=None)
def test_get_etcd_client(self): def test_get_etcd_client(self):
start_script.VARIABLES = { start_script.VARIABLES = {
@ -166,6 +173,11 @@ class TestGetETCDClient(base.TestCase):
"connection_attempts": 3, "connection_attempts": 3,
"connection_delay": 0, "connection_delay": 0,
}, },
"security": {
"tls": {
"enabled": False
}
}
} }
with mock.patch("etcd.Client") as m_etcd: with mock.patch("etcd.Client") as m_etcd:
expected_value = object() expected_value = object()
@ -175,7 +187,9 @@ class TestGetETCDClient(base.TestCase):
m_etcd.assert_called_once_with( m_etcd.assert_called_once_with(
host=(('etcd.ccp.svc.cluster.local', 1234),), host=(('etcd.ccp.svc.cluster.local', 1234),),
allow_reconnect=True, allow_reconnect=True,
read_timeout=2) read_timeout=2,
protocol='http',
ca_cert=None)
def test_get_etcd_client_wrong(self): def test_get_etcd_client_wrong(self):
start_script.VARIABLES = { start_script.VARIABLES = {