Support TLS connection to etcd

This change also modifies the devstack installation script to re-use
k8s api server etcd client certs as qinling etcd certs, and use TLS to
connect with etcd by default in devstack.

Because the etcd server in k8s 1.10 doesn't support https by default, this
patch also upgrade k8s to 1.11 in devstack installation.

Change-Id: I10959188eb8543d006f65b751557787171334a97
Task: 24227
Story: 2003284
This commit is contained in:
Lingxian Kong 2018-08-23 10:35:53 +12:00
parent e588e34969
commit 46457cdfe5
17 changed files with 105 additions and 35 deletions

View File

@ -81,6 +81,23 @@ function configure_k8s_certificates {
popd
}
function configure_etcd_certificates {
pushd $QINLING_DIR
mkdir_chown_stack $QINLING_CONF_DIR/pki/etcd
sudo cp /etc/kubernetes/pki/etcd/ca.crt $QINLING_CONF_DIR/pki/etcd/
# Re-use k8s api server etcd client cert
sudo cp /etc/kubernetes/pki/apiserver-etcd-client.crt $QINLING_CONF_DIR/pki/etcd/qinling-etcd-client.crt
sudo cp /etc/kubernetes/pki/apiserver-etcd-client.key $QINLING_CONF_DIR/pki/etcd/qinling-etcd-client.key
mkdir_chown_stack $QINLING_CONF_DIR/pki/etcd
# For the tempest user to read the key file when running tempest
chmod 644 $QINLING_CONF_DIR/pki/etcd/qinling-etcd-client.key
popd
}
function configure_qinling {
mkdir_chown_stack "$QINLING_AUTH_CACHE_DIR"
@ -123,6 +140,9 @@ function configure_qinling {
iniset $QINLING_CONF_FILE kubernetes use_api_certificate False
fi
# Config etcd TLS certs
configure_etcd_certificates
iniset $QINLING_CONF_FILE kubernetes replicas 5
}

View File

@ -20,7 +20,7 @@ debtcollector==1.19.0
decorator==4.2.1
dogpile.cache==0.6.5
enum-compat==0.0.2
etcd3gw==0.2.2
etcd3gw==0.2.3
eventlet==0.20.0
extras==1.0.0
fasteners==0.14.1

View File

@ -186,8 +186,40 @@ kubernetes_opts = [
ETCD_GROUP = 'etcd'
etcd_opts = [
cfg.StrOpt('host', default='127.0.0.1', help='Etcd service host address.'),
cfg.PortOpt('port', default=2379, help='Etcd service port.'),
cfg.StrOpt(
'host',
default='127.0.0.1',
help='Etcd service host address.'
),
cfg.PortOpt(
'port',
default=2379,
help='Etcd service port.'
),
cfg.StrOpt(
'protocol',
default='https',
choices=['http', 'https'],
help='Etcd connection protocol.'
),
cfg.StrOpt(
'ca_cert',
default='/etc/qinling/pki/etcd/ca.crt',
help='Path to CA certificate file to use to securely '
'connect to etcd server.'
),
cfg.StrOpt(
'cert_file',
default='/etc/qinling/pki/etcd/qinling-etcd-client.crt',
help='Path to client certificate file to use to securely '
'connect to etcd server.'
),
cfg.StrOpt(
'cert_key',
default='/etc/qinling/pki/etcd/qinling-etcd-client.key',
help='Path to client certificate key file to use to securely '
'connect to etcd server.'
),
]
RLIMITS_GROUP = 'resource_limits'

View File

@ -24,7 +24,12 @@ def get_client(conf=None):
conf = conf or CONF
if not CLIENT:
CLIENT = etcd3gw.client(host=conf.etcd.host, port=conf.etcd.port)
CLIENT = etcd3gw.client(host=conf.etcd.host,
port=conf.etcd.port,
protocol=conf.etcd.protocol,
ca_cert=conf.etcd.ca_cert,
cert_cert=conf.etcd.cert_file,
cert_key=conf.etcd.cert_key)
return CLIENT

View File

@ -45,10 +45,4 @@ QinlingGroup = [
cfg.StrOpt("nodejs_runtime_image",
default="openstackqinling/nodejs-runtime:0.0.1",
help="The NodeJS runtime being used in the tests."),
cfg.StrOpt('etcd_host',
default='127.0.0.1',
help='Etcd service host address.'),
cfg.PortOpt('etcd_port',
default=2379,
help='Etcd service port.'),
]

View File

@ -13,20 +13,18 @@
# limitations under the License.
from concurrent import futures
import etcd3gw
import hashlib
import json
import requests
import futurist
from oslo_serialization import jsonutils
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
from qinling_tempest_plugin.tests import base
from qinling_tempest_plugin.tests import utils
CONF = config.CONF
INVOKE_ERROR = "Function execution failed because of too much resource " \
"consumption"
@ -83,8 +81,7 @@ class ExecutionsTest(base.BaseQinlingTest):
"""
function_id = self.create_function()
etcd3_client = etcd3gw.client(host=CONF.qinling.etcd_host,
port=CONF.qinling.etcd_port)
etcd3_client = utils.get_etcd_client()
lock_id = "function_worker_%s_%s" % (function_id, 0)
with etcd3_client.lock(id=lock_id):
resp, body = self.client.create_execution(

View File

@ -12,15 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import etcd3gw
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
import tenacity
from qinling_tempest_plugin.tests import base
CONF = config.CONF
from qinling_tempest_plugin.tests import utils
class FunctionVersionsTest(base.BaseQinlingTest):
@ -104,8 +101,7 @@ class FunctionVersionsTest(base.BaseQinlingTest):
"""
function_id = self.create_function()
etcd3_client = etcd3gw.client(host=CONF.qinling.etcd_host,
port=CONF.qinling.etcd_port)
etcd3_client = utils.get_etcd_client()
lock_id = "function_version_%s" % function_id
with etcd3_client.lock(id=lock_id):
self.assertRaises(

View File

@ -14,6 +14,13 @@
import hashlib
from oslo_config import cfg
from qinling import config as qinling_config
from qinling.utils import etcd_util
QINLING_CONF = None
def md5(file=None, content=None):
hash_md5 = hashlib.md5()
@ -26,3 +33,16 @@ def md5(file=None, content=None):
hash_md5.update(content)
return hash_md5.hexdigest()
def get_etcd_client():
"""Use qinling's default CONF to connect to etcd."""
global QINLING_CONF
if not QINLING_CONF:
QINLING_CONF = cfg.ConfigOpts()
QINLING_CONF(args=[], project='qinling')
QINLING_CONF.register_opts(qinling_config.etcd_opts,
qinling_config.ETCD_GROUP)
return etcd_util.get_client(conf=QINLING_CONF)

View File

@ -0,0 +1,5 @@
---
features:
- Qinling can now use TLS certificates to securely connect to the etcd
service. It is enabled by default in Qinling Devstack installation. The
configuration is defined in ``etcd`` section in Qinling config file.

View File

@ -29,5 +29,5 @@ croniter>=0.3.4 # MIT License
python-dateutil>=2.5.3 # BSD
tenacity>=4.4.0 # Apache-2.0
PyMySQL>=0.7.6 # MIT License
etcd3gw>=0.2.2 # Apache-2.0
etcd3gw>=0.2.3 # Apache-2.0
cotyledon>=1.3.0 # Apache-2.0

View File

@ -55,6 +55,6 @@ function gate_base_setup {
function create_k8s_screen {
# Starts a proxy to the Kubernetes API server in a screen session
sudo screen -S kube_proxy -X quit || true
sudo screen -dmS kube_proxy && sudo screen -S kube_proxy -X screen -t kube_proxy
sudo screen -S kube_proxy -p kube_proxy -X stuff 'kubectl proxy --accept-hosts=".*" --address="0.0.0.0"\n'
sudo screen -dmS kube_proxy
sudo screen -S kube_proxy -p bash -X stuff 'kubectl proxy --accept-hosts=".*" --address="0.0.0.0"\n'
}

View File

@ -0,0 +1,2 @@
---
k8s_version: "1.11.0"

View File

@ -18,9 +18,9 @@
state: present
update_cache: yes
with_items:
- kubelet-1.9.3
- kubectl-1.9.3
- kubeadm-1.9.3
- kubelet-{{ k8s_version }}
- kubectl-{{ k8s_version }}
- kubeadm-{{ k8s_version }}
# On CentOS 7, the kubeadm package adds a configuration file that overrides
# kubelet's cgroup driver to systemd, we want to use the default driver

View File

@ -15,6 +15,6 @@
state: present
update_cache: yes
with_items:
- kubelet=1.9.3-00
- kubectl=1.9.3-00
- kubeadm=1.9.3-00
- kubelet={{ k8s_version }}-00
- kubectl={{ k8s_version }}-00
- kubeadm={{ k8s_version }}-00

View File

@ -0,0 +1,2 @@
---
k8s_version: "1.11.0"

View File

@ -17,7 +17,7 @@
- name: Init master
vars:
extra_opts: "{{ lookup('env', 'EXTRA_KUBEADM_INIT_OPTS') }}"
shell: kubeadm init --pod-network-cidr=192.168.0.0/16 --kubernetes-version=1.9.3 {{ extra_opts }}
shell: kubeadm init --pod-network-cidr=192.168.0.0/16 --kubernetes-version=v{{ k8s_version }} {{ extra_opts }}
register: kubeadm_init
- fail:

View File

@ -12,8 +12,5 @@
source /etc/os-release
export HOST_OS=${HOST_OS:="${ID}"}
# Set versions of K8s to use
export KUBE_VERSION=${KUBE_VERSION:-"v1.8.0"}
# Set Upstream DNS
export UPSTREAM_DNS=${UPSTREAM_DNS:-"8.8.8.8"}
export UPSTREAM_DNS=${UPSTREAM_DNS:-"8.8.8.8"}