summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lucas <jflucas@research.att.com>2018-09-10 12:14:29 +0000
committerJack Lucas <jflucas@research.att.com>2018-09-10 12:50:51 +0000
commit6292de70ae19c84c01d12562c0e6682918fe30f8 (patch)
tree9546d23f7584f6f7bcda8f7cbce1e9ebde640a17
parentdcee205400592c9d629a5b059820dd402e994869 (diff)
Add support for TLS init container
Change-Id: I118af2c8a0294ffc89e045f8cdae24dfb7e57ab6 Issue-ID: DCAEGEN2-591 Signed-off-by: Jack Lucas <jflucas@research.att.com>
-rw-r--r--k8s/README.md27
-rw-r--r--k8s/configure/configure.py7
-rw-r--r--k8s/k8s-node-type.yaml24
-rw-r--r--k8s/k8sclient/k8sclient.py38
-rw-r--r--k8s/k8splugin/tasks.py10
-rw-r--r--k8s/pom.xml2
-rw-r--r--k8s/setup.py2
7 files changed, 90 insertions, 20 deletions
diff --git a/k8s/README.md b/k8s/README.md
index 5b2d0da..2f4b3a6 100644
--- a/k8s/README.md
+++ b/k8s/README.md
@@ -16,6 +16,9 @@ creates the following Kubernetes entities:
- If the blueprint specifies a logging directory via the `log_info` property, the `Deployment` includes a second container,
running the `filebeat` logging sidecar that ships logging information to the ONAP ELK stack. The `Deployment` will include
some additional volumes needed by filebeat.
+ - If the blueprint specifies that the component uses TLS (HTTPS) via the `tls_info` property, the `Deployment` includes an init container,
+ a volume that holds TLS certificate artifacts, and volume mounts on the init container and the component's container. The init container
+ populates the TLS certificate artifacts volume with certificates, keys, keystores, etc.
- If the blueprint indicates that the component exposes any ports, the plugin will create a Kubernetes `Service` that allocates an address
in the Kubernetes network address space that will route traffic to a container that's running the component. This `Service` provides a
fixed "virtual IP" for the component.
@@ -40,16 +43,20 @@ address=10.12.5.115:30270
Additional configuration information is stored in the Consul KV store under the key `k8s-plugin`.
The configuration is provided as JSON object with the following properties:
- - namespace: k8s namespace to use for DCAE
- - consul_dns_name: k8s internal DNS name for Consul (passed to containers)
- - image_pull_secrets: list of names of k8s secrets for accessing Docker registries, with the following properties:
- - filebeat: object containing onfiguration for setting up filebeat container
- - log_path: mount point for log volume in filebeat container
- - data_path: mount point for data volume in filebeat container
- - config_path: mount point for config volume in filebeat container
- - config_subpath: subpath for config data in filebeat container
- - config_map: name of a ConfigMap holding the filebeat configuration file
- - image: Docker image to use for filebeat
+ - `namespace`: k8s namespace to use for DCAE
+ - `consul_dns_name`: k8s internal DNS name for Consul (passed to containers)
+ - `image_pull_secrets`: list of names of k8s secrets for accessing Docker registries, with the following properties:
+ - `filebeat`: object containing onfiguration for setting up filebeat container
+ - `log_path`: mount point for log volume in filebeat container
+ - `data_path`: mount point for data volume in filebeat container
+ - `config_path`: mount point for config volume in filebeat container
+ - `config_subpath`: subpath for config data in filebeat container
+ - `config_map`: name of a ConfigMap holding the filebeat configuration file
+ - `image`: Docker image to use for filebeat
+ - `tls`: object containing configuration for setting up TLS init container
+ - `cert_path`: mount point for the TLS certificate artifact volume in the init container
+ - `image`: Docker image to use for the TLS init container
+
#### Kubernetes access information
The plugin accesses a Kubernetes cluster. The information and credentials for accessing a cluster are stored in a "kubeconfig"
diff --git a/k8s/configure/configure.py b/k8s/configure/configure.py
index fcf4044..03077d2 100644
--- a/k8s/configure/configure.py
+++ b/k8s/configure/configure.py
@@ -32,6 +32,9 @@ FB_CONFIG_SUBPATH = "filebeat.yml"
FB_CONFIG_MAP = "filebeat-conf"
FB_IMAGE = "docker.elastic.co/beats/filebeat:5.5.0"
+TLS_CERT_PATH = "/opt/tls/shared"
+TLS_IMAGE = "tls-init:latest"
+
def _set_defaults():
""" Set default configuration parameters """
return {
@@ -45,6 +48,10 @@ def _set_defaults():
"config_subpath" : FB_CONFIG_SUBPATH, # subpath for config data in filebeat container
"config_map" : FB_CONFIG_MAP, # ConfigMap holding the filebeat configuration
"image": FB_IMAGE # Docker image to use for filebeat
+ },
+ "tls": { # Configuration for setting up TLS init container
+ "cert_path" : TLS_CERT_PATH, # mount point for certificate volume in TLS init container
+ "image": TLS_IMAGE # Docker image to use for TLS init container
}
}
diff --git a/k8s/k8s-node-type.yaml b/k8s/k8s-node-type.yaml
index d43d76a..5dae20a 100644
--- a/k8s/k8s-node-type.yaml
+++ b/k8s/k8s-node-type.yaml
@@ -25,7 +25,7 @@ plugins:
k8s:
executor: 'central_deployment_agent'
package_name: k8splugin
- package_version: 1.4.2
+ package_version: 1.4.3
data_types:
@@ -79,6 +79,22 @@ data_types:
type: string
required: false
+ dcae.types.TLSInfo:
+ description: >
+ Information for using TLS (HTTPS). (The properties all have to be declared as not
+ required, otherwise the tls_info property on the node would also be required.)
+ properties:
+ cert_directory:
+ description: >
+ The path in the container where the component expects to find TLS-related data.
+ type: string
+ required: false
+ use_tls:
+ description: >
+ Flag indicating whether TLS (HTTPS) is to be used
+ type: boolean
+ required: false
+
node_types:
dcae.nodes.ContainerizedComponent:
# Bese type for all containerized components
@@ -109,6 +125,12 @@ node_types:
Information for setting up centralized logging via ELK.
required: false
+ tls_info:
+ type: dcae.types.TLSInfo
+ description: >
+ Information for setting up TLS (HTTPS).
+ required: false
+
replicas:
type: integer
description: >
diff --git a/k8s/k8sclient/k8sclient.py b/k8s/k8sclient/k8sclient.py
index 1c30534..eff51a3 100644
--- a/k8s/k8sclient/k8sclient.py
+++ b/k8s/k8sclient/k8sclient.py
@@ -84,7 +84,7 @@ def _parse_interval(t):
raise ValueError("Bad interval specification: {0}".format(t))
return time
-def _create_probe(hc, port):
+def _create_probe(hc, port, use_tls=False):
''' Create a Kubernetes probe based on info in the health check dictionary hc '''
probe_type = hc['type']
probe = None
@@ -99,7 +99,7 @@ def _create_probe(hc, port):
http_get = client.V1HTTPGetAction(
path = hc['endpoint'],
port = port,
- scheme = probe_type.upper()
+ scheme = 'HTTPS' if use_tls else probe_type.upper()
)
)
elif probe_type in ['script', 'docker']:
@@ -114,7 +114,7 @@ def _create_probe(hc, port):
)
return probe
-def _create_container_object(name, image, always_pull, env={}, container_ports=[], volume_mounts = [], readiness = None):
+def _create_container_object(name, image, always_pull, use_tls=False, env={}, container_ports=[], volume_mounts = [], readiness = None):
# Set up environment variables
# Copy any passed in environment variables
env_vars = [client.V1EnvVar(name=k, value=env[k]) for k in env.keys()]
@@ -130,7 +130,7 @@ def _create_container_object(name, image, always_pull, env={}, container_ports=[
hc_port = None
if len(container_ports) > 0:
hc_port = container_ports[0]
- probe = _create_probe(readiness, hc_port)
+ probe = _create_probe(readiness, hc_port, use_tls)
# Define container for pod
return client.V1Container(
@@ -145,6 +145,7 @@ def _create_container_object(name, image, always_pull, env={}, container_ports=[
def _create_deployment_object(component_name,
containers,
+ init_containers,
replicas,
volumes,
labels={},
@@ -166,6 +167,7 @@ def _create_deployment_object(component_name,
metadata=client.V1ObjectMeta(labels=labels),
spec=client.V1PodSpec(hostname=component_name,
containers=containers,
+ init_containers=init_containers,
volumes=volumes,
image_pull_secrets=ips)
)
@@ -333,6 +335,9 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
"config_subpath" : subpath for config data in filebeat container
"config_map" : ConfigMap holding the filebeat configuration
"image": Docker image to use for filebeat
+ - tls: a dictionary of TLS init container parameters:
+ "cert_path": mount point for certificate volume in init container
+ "image": Docker image to use for TLS init container
kwargs may have:
- volumes: array of volume objects, where a volume object is:
{"host":{"path": "/path/on/host"}, "container":{"bind":"/path/on/container","mode":"rw_or_ro"}
@@ -341,6 +346,8 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
- msb_list: array of msb objects, where an msb object is as described in msb/msb.py.
- log_info: an object with info for setting up ELK logging, with the form:
{"log_directory": "/path/to/container/log/directory", "alternate_fb_path" : "/alternate/sidecar/log/path"}
+ - tls_info: an object with info for setting up TLS (HTTPS), with the form:
+ {"use_tls": true, "cert_directory": "/path/to/container/cert/directory" }
- labels: dict with label-name/label-value pairs, e.g. {"cfydeployment" : "lsdfkladflksdfsjkl", "cfynode":"mycomponent"}
These label will be set on all the pods deployed as a result of this deploy() invocation.
- readiness: dict with health check info; if present, used to create a readiness probe for the main container. Includes:
@@ -375,6 +382,7 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
# Initialize the list of containers that will be part of the pod
containers = []
+ init_containers = []
# Set up the ELK logging sidecar container, if needed
log_info = kwargs.get("log_info")
@@ -395,7 +403,7 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
sidecar_volume_mounts.append(client.V1VolumeMount(name="filebeat-data", mount_path=fb["data_path"]))
# Create the container for the sidecar
- containers.append(_create_container_object("filebeat", fb["image"], False, {}, [], sidecar_volume_mounts))
+ containers.append(_create_container_object("filebeat", fb["image"], False, False, {}, [], sidecar_volume_mounts))
# Create the volume for the sidecar configuration data and the volume mount for it
# The configuration data is in a k8s ConfigMap that should be created when DCAE is installed.
@@ -404,14 +412,30 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
sidecar_volume_mounts.append(
client.V1VolumeMount(name="filebeat-conf", mount_path=fb["config_path"], sub_path=fb["config_subpath"]))
+ # Set up the TLS init container, if needed
+ tls_info = kwargs.get("tls_info")
+ use_tls = False
+ if tls_info and "use_tls" in tls_info and tls_info["use_tls"]:
+ if "cert_directory" in tls_info and len(tls_info["cert_directory"]) > 0:
+ use_tls = True
+ tls_config = k8sconfig["tls"]
+
+ # Create the certificate volume and volume mounts
+ volumes.append(client.V1Volume(name="tls-info", empty_dir=client.V1EmptyDirVolumeSource()))
+ volume_mounts.append(client.V1VolumeMount(name="tls-info", mount_path=tls_info["cert_directory"]))
+ init_volume_mounts = [client.V1VolumeMount(name="tls-info", mount_path=tls_config["cert_path"])]
+
+ # Create the init container
+ init_containers.append(_create_container_object("init-tls", tls_config["image"], False, False, {}, [], init_volume_mounts))
+
# Create the container for the component
# Make it the first container in the pod
- containers.insert(0, _create_container_object(component_name, image, always_pull, kwargs.get("env", {}), container_ports, volume_mounts, kwargs["readiness"]))
+ containers.insert(0, _create_container_object(component_name, image, always_pull, use_tls, kwargs.get("env", {}), container_ports, volume_mounts, kwargs["readiness"]))
# Build the k8s Deployment object
labels = kwargs.get("labels", {})
labels.update({"app": component_name})
- dep = _create_deployment_object(component_name, containers, replicas, volumes, labels, pull_secrets=k8sconfig["image_pull_secrets"])
+ dep = _create_deployment_object(component_name, containers, init_containers, replicas, volumes, labels, pull_secrets=k8sconfig["image_pull_secrets"])
# Have k8s deploy it
ext.create_namespaced_deployment(namespace, dep)
diff --git a/k8s/k8splugin/tasks.py b/k8s/k8splugin/tasks.py
index d32ce30..ba71bd9 100644
--- a/k8s/k8splugin/tasks.py
+++ b/k8s/k8splugin/tasks.py
@@ -296,6 +296,7 @@ def _create_and_start_container(container_name, image, **kwargs):
volumes=kwargs.get("volumes",[]),
ports=kwargs.get("ports",[]),
msb_list=kwargs.get("msb_list"),
+ tls_info=kwargs.get("tls_info"),
env = env,
labels = kwargs.get("labels", {}),
log_info=kwargs.get("log_info"),
@@ -324,6 +325,10 @@ def _parse_cloudify_context(**kwargs):
if "log_info" in ctx.node.properties and "log_directory" in ctx.node.properties["log_info"]:
kwargs["log_info"] = ctx.node.properties["log_info"]
+ # Pick up TLS info if present
+ if "tls_info" in ctx.node.properties:
+ kwargs["tls_info"] = ctx.node.properties["tls_info"]
+
# Pick up replica count and always_pull_image flag
if "replicas" in ctx.node.properties:
kwargs["replicas"] = ctx.node.properties["replicas"]
@@ -380,6 +385,7 @@ def _create_and_start_component(**kwargs):
"ports": kwargs.get("ports", None),
"envs": kwargs.get("envs", {}),
"log_info": kwargs.get("log_info", {}),
+ "tls_info": kwargs.get("tls_info", {}),
"labels": kwargs.get("labels", {}),
"readiness": kwargs.get("readiness",{})}
_create_and_start_container(service_component_name, image, **sub_kwargs)
@@ -524,6 +530,10 @@ def create_and_start_container_for_platforms(**kwargs):
if "log_info" in ctx.node.properties and "log_directory" in ctx.node.properties["log_info"]:
kwargs["log_info"] = ctx.node.properties["log_info"]
+ # Pick up TLS info if present
+ if "tls_info" in ctx.node.properties:
+ kwargs["tls_info"] = ctx.node.properties["tls_info"]
+
# Pick up replica count and always_pull_image flag
if "replicas" in ctx.node.properties:
kwargs["replicas"] = ctx.node.properties["replicas"]
diff --git a/k8s/pom.xml b/k8s/pom.xml
index 14baaf7..ea34f78 100644
--- a/k8s/pom.xml
+++ b/k8s/pom.xml
@@ -28,7 +28,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
<groupId>org.onap.dcaegen2.platform.plugins</groupId>
<artifactId>k8s</artifactId>
<name>k8s-plugin</name>
- <version>1.4.2-SNAPSHOT</version>
+ <version>1.4.3-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/k8s/setup.py b/k8s/setup.py
index 0fa7634..5897f61 100644
--- a/k8s/setup.py
+++ b/k8s/setup.py
@@ -23,7 +23,7 @@ from setuptools import setup
setup(
name='k8splugin',
description='Cloudify plugin for containerized components deployed using Kubernetes',
- version="1.4.2",
+ version="1.4.3",
author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
packages=['k8splugin','k8sclient','msb','configure'],
zip_safe=False,