Update skydive to use TLS

This change implements TLS configurations for skydive. All servers will
get their own certificates signed by the CA as setup on the
`skydive_service_setup_host` node.

> Documentation for TLS configuration can be found here: http://skydive.network/documentation/

Change-Id: I890b4a5d9076b0474ffe5649f9361cb6018c19fe
Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
This commit is contained in:
Kevin Carter 2019-01-20 23:57:46 -06:00 committed by Kevin Carter
parent 181edc376f
commit 6b92dba1d5
No known key found for this signature in database
GPG Key ID: 9443251A787B9FB3
13 changed files with 267 additions and 49 deletions

View File

@ -139,5 +139,6 @@
become: yes
roles:
- role: skydive_agent
skydive_service_setup_host: "{{ openstack_service_setup_host | default(groups['skydive_analyzers'][0]) }}"
tags:
- skydive-agent-setup

View File

@ -58,7 +58,6 @@ skydive_elasticsearch_port: "9200"
skydive_etcd_embedded: yes
skydive_etcd_port: 12379
skydive_etcd_listen_uri: "0.0.0.0:{{ skydive_etcd_port }}"
skydive_etcd_scheme: http
# If embedded etcd is disabled the etcd server must be defined.
# skydive_etcd_servers:
@ -137,3 +136,11 @@ skydive_os_service_insecure: true
# `config_template` provides an interface that will inser any
# option into the compatible configuration file using a deep merge.
skydive_config_overrides: {}
# Skydive SSL certificates will be generated when they do not exist. If the
# vertificates need to be regenerated set this option to true to force
# regenerate certificates.
skydive_ssl_regen: false
# Set the log level used by skydive
skydive_log_level: INFO

View File

@ -70,6 +70,7 @@
# NOTE(cloudnull): Locate a clouds.yaml file on the service setup host or localhost.
- name: Check for OpenStack deployment
run_once: true
block:
- name: Slurp clouds file
slurp:
@ -82,7 +83,7 @@
src: "{{ skydive_os_cloud_file }}"
register: clouds_file
delegate_to: "localhost"
failed_when: false
ignore_errors: yes
when:
- not (skydive_service_setup_host in ['localhost', '127.0.0.1'])
@ -91,25 +92,26 @@
msg: >-
No clouds file found, running without OpenStack integration.
when:
- not (clouds_file is success)
- clouds_file['content'] is undefined
# NOTE(cloudnull): If a clouds file is found the facts for the clouds file will be delegated
# to all hosts throughout the skydive deployment.
- name: Run OpenStack ingetration deployment
run_once: true
block:
- name: Enable OpenStack integration
set_fact:
clouds_yaml: "{{ clouds_file['content'] | b64decode | from_yaml }}"
skydive_auth_type: mykeystone
skydive_openstack_enabled: true
run_once: true
delegate_to: "{{ item }}"
delegate_facts: true
with_items: "{{ ansible_play_hosts }}"
- include_tasks: skydive_keystone.yml
run_once: true
when:
- clouds_file is success
- clouds_file['content'] is defined
- include_tasks: skydive_setup.yml
- include_tasks: skydive_ssl.yml

View File

@ -64,6 +64,18 @@
vars:
ansible_python_interpreter: "{{ skydive_service_setup_host_python_interpreter }}"
block:
- name: Ensure clouds file directory
file:
path: "{{ skydive_os_cloud_file | dirname }}"
state: directory
mode: "0750"
- name: Install binary skydive
copy:
content: "{{ clouds_yaml | to_nice_yaml }}"
dest: "{{ skydive_os_cloud_file }}"
mode: "0640"
- name: Add skydive project
os_project:
cloud: "{{ skydive_os_cloud }}"

View File

@ -36,8 +36,19 @@
group: "skydive"
mode: "0755"
with_items:
- "/var/lib/skydive"
- "/etc/skydive"
- "/var/lib/skydive"
- "/var/lib/skydive/etcd"
- name: Create skydive ssl path
file:
path: "{{ item }}"
state: directory
owner: "skydive"
group: "skydive"
mode: "0700"
with_items:
- "/var/lib/skydive/ssl"
- name: Check for ovsdb
stat:

View File

@ -0,0 +1,131 @@
---
# Copyright 2019, Rackspace US, 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.
- name: Purge skydive ssl certificates
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ skydive_ssl_bundle }}"
when:
- skydive_ssl_regen | bool
- name: SSL Block
run_once: true
delegate_to: "{{ skydive_service_setup_host }}"
block:
- name: Create CNF
template:
src: "skydive-openssl.cnf.j2"
dest: "{{ skydive_ssl_cnf }}"
owner: skydive
group: skydive
- name: Create CA cert
command: >-
openssl req
-new
-nodes
-x509
-subj "{{ skydive_ssl_ca_subject }}"
-days 3650
-keyout {{ skydive_ssl_ca_key }}
-out {{ skydive_ssl_ca_cert }}
args:
creates: "{{ skydive_ssl_ca_cert }}"
- name: Create CSR
command: >-
openssl req
-new
-nodes
-sha256
-subj "{{ skydive_ssl_signed_subject }}"
-days 3650
-keyout {{ skydive_ssl_key }}
-out {{ skydive_ssl_csr }}
-config {{ skydive_ssl_cnf }}
args:
creates: "{{ skydive_ssl_csr }}"
- name: Create SSL signed cert
command: >-
openssl x509
-req
-days 3650
-in {{ skydive_ssl_csr }}
-CA {{ skydive_ssl_ca_cert }}
-CAkey {{ skydive_ssl_ca_key }}
-out {{ skydive_ssl_cert }}
-set_serial 01
-extensions v3_req
-extfile {{ skydive_ssl_cnf }}
args:
creates: "{{ skydive_ssl_cert }}"
delegate_to: "{{ skydive_service_setup_host }}"
- name: Fetch skydive ssl csr
fetch:
src: "{{ skydive_ssl_csr }}"
dest: "/tmp/skydive/ssl/{{ skydive_ssl_csr | basename }}"
flat: true
run_once: true
delegate_to: "{{ skydive_service_setup_host }}"
- name: Fetch skydive ssl cert
fetch:
src: "{{ skydive_ssl_cert }}"
dest: "/tmp/skydive/ssl/{{ skydive_ssl_cert | basename }}"
flat: true
delegate_to: "{{ skydive_service_setup_host }}"
- name: Fetch skydive ssl key
fetch:
src: "{{ skydive_ssl_key }}"
dest: "/tmp/skydive/ssl/{{ skydive_ssl_key | basename }}"
flat: true
run_once: true
delegate_to: "{{ skydive_service_setup_host }}"
- name: Fetch skydive ca cert
fetch:
src: "{{ skydive_ssl_ca_cert }}"
dest: "/tmp/skydive/ssl/{{ skydive_ssl_ca_cert | basename }}"
flat: true
run_once: true
delegate_to: "{{ skydive_service_setup_host }}"
- name: Copy certifactes over
copy:
src: "/tmp/skydive/ssl/{{ item.path | basename }}"
dest: "{{ item.path }}"
owner: skydive
group: skydive
with_items: "{{ skydive_ssl_bundle }}"
- name: Cleanup system
delegate_to: "localhost"
run_once: true
block:
- name: Find temp skydive ssl certificates
find:
paths: "/tmp/skydive/ssl"
recurse: no
register: files_to_purge
- name: Purge temp skydive host ssl
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ files_to_purge.files }}"

View File

@ -0,0 +1,43 @@
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = XX
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = XX
localityName = Locality Name (eg, city)
localityName_default = XX
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = OpenStack-Ansible
commonName = {{ ((ansible_domain | length) > 0) | ternary(ansible_domain, ansible_hostname) }}
commonName_max = 64
[v3_req]
basicConstraints = CA:TRUE
keyUsage = digitalSignature, keyEncipherment, keyCertSign
extendedKeyUsage = serverAuth,clientAuth
subjectAltName = @alt_names
[alt_names]
{% set ips = [] %}
{% set hostnames = [] %}
{% for node in groups['skydive_all'] %}
{% set _ansible_interface_name = hostvars[node]['skydive_network_device'] | default(hostvars[node]['ansible_default_ipv4']['interface']) | replace('-', '_') %}
{% set _skydive_ip = hostvars[node]['skydive_bind_address'] | default(hostvars[node]["ansible_" ~ _ansible_interface_name]['ipv4']['address']) %}
{% set _skydive_ansible_domain = hostvars[node]['ansible_domain'] | default(hostvars[node]['ansible_hostname'] ) %}
{% set _skydive_dns_name = ((_skydive_ansible_domain | length) > 0) | ternary(_skydive_ansible_domain, hostvars[node]['ansible_hostname']) %}
{% set _ = ips.append(_skydive_ip) %}
{% set _ = hostnames.append(_skydive_dns_name) %}
IP.{{ loop.index }} = {{ _skydive_ip }}
DNS.{{ loop.index }} = {{ _skydive_dns_name }}
{% endfor %}
{% set localhost_index = (groups['skydive_all'] | length) + 1 %}
{% if '127.0.0.1' not in ips %}
IP.{{ localhost_index }} = 127.0.0.1
{% endif %}
{% if 'localhost' not in hostnames %}
DNS.{{ localhost_index }} = localhost
{% endif %}

View File

@ -8,13 +8,17 @@ host_id: {{ ansible_hostname }}
tls:
# File path to X509 Certificate and Private Key to enable TLS communication
# Unique certificate per agent is recommended
# client_cert: /etc/ssl/certs/agent.domain.com.crt
# client_key: /etc/ssl/certs/agent.domain.com.key
{% if inventory_hostname in groups['skydive_agents'] %}
client_cert: {{ skydive_ssl_cert }}
client_key: {{ skydive_ssl_key }}
{% endif %}
# server_cert: /etc/ssl/certs/analyzer.domain.com.crt
# server_key: /etc/ssl/certs/analyzer.domain.com.key
{% if inventory_hostname in groups['skydive_analyzers'] %}
server_cert: {{ skydive_ssl_cert }}
server_key: {{ skydive_ssl_key }}
{% endif %}
# ca_cert: /etc/ssl/certs/ca.domain.com.crt
ca_cert: {{ skydive_ssl_ca_cert }}
http:
# define the Cookie HTTP Request Header
@ -358,7 +362,7 @@ storage:
{% endif %}
logging:
# level: INFO
level: {{ skydive_log_level }}
# Default backend used: stderr
backends:
@ -368,8 +372,15 @@ logging:
# - syslog
# configuration of the 'file' backend
{% if (inventory_hostname in groups['skydive_analyzers']) and (inventory_hostname in groups['skydive_agents']) %}
{% set _log_segment = 'aio' %}
{% elif (inventory_hostname in groups['skydive_analyzers']) %}
{% set _log_segment = 'analyzer' %}
{% else %}
{% set _log_segment = 'agent' %}
{% endif %}
file:
path: /var/log/skydive.log
path: /var/log/skydive-{{ _log_segment }}.log
# configuration encoder could be for all backends or for specific one
# encoder: json
@ -415,7 +426,7 @@ etcd:
# max_snap_files: 0
# path where the etcd files will be stored.
# data_dir: /var/lib/skydive/etcd
data_dir: /var/lib/skydive/etcd
# client parameters
{% if skydive_etcd_servers %}
@ -467,13 +478,14 @@ flow:
# 1194: OPENVPN
{% endif %}
{% if inventory_hostname in groups['skydive_analyzers'] %}
ui:
# Specify the extra assets folder. Javascript and CSS files present in this
# folder will be added to the WebUI.
# extra_assets: /usr/share/skydive/assets
# select between light, dark themes
# theme: dark
theme: light
# Settings specific to the topology view
topology:
@ -530,3 +542,4 @@ rbac:
# additional RBAC policy:
# - p, myuser, capture, write, deny
# - g, myuser, myrole
{% endif %}

View File

@ -14,4 +14,7 @@
# limitations under the License.
sykdive_distro_packages:
- openssl
- python3-openssl
- python-openssl
- python-passlib

View File

@ -45,3 +45,19 @@ skydive_fabric: |-
# Inject the required basic authentication information
_skydive_basic_auth_users:
"{{ skydive_username }}": "{{ skydive_password }}"
skydive_ssl_cnf: "/var/lib/skydive/ssl/skydive-openssl.cnf"
skydive_ssl_key: "/var/lib/skydive/ssl/skydive.key"
skydive_ssl_csr: "/var/lib/skydive/ssl/skydive.csr"
skydive_ssl_cert: "/var/lib/skydive/ssl/skydive-{{ inventory_hostname | replace('_', '-') | replace(' ', '-') }}.crt"
skydive_ssl_signed_subject: "/C=XX/L=OpenStack-Cloud/O=OpenStack/OU=IT/CN={{ ((ansible_domain | length) > 0) | ternary(ansible_domain, ansible_hostname) }}"
skydive_ssl_ca_key: "/var/lib/skydive/ssl/skydive-ca.key"
skydive_ssl_ca_cert: "/var/lib/skydive/ssl/skydive-ca.crt"
skydive_ssl_ca_subject: "/C=XX/L=OpenStack-Cloud/O=OpenStack"
skydive_ssl_bundle:
- path: "{{ skydive_ssl_csr }}"
- path: "{{ skydive_ssl_cert }}"
- path: "{{ skydive_ssl_key }}"
- path: "{{ skydive_ssl_ca_cert }}"

View File

@ -14,4 +14,6 @@
# limitations under the License.
sykdive_distro_packages:
- openssl
- python2-passlib
- pyOpenSSL

View File

@ -14,4 +14,7 @@
# limitations under the License.
sykdive_distro_packages:
- openssl
- python2-pyOpenSSL
- python3-pyOpenSSL
- python-passlib

View File

@ -17,40 +17,14 @@
hosts: skydive_analyzers[0]
vars:
skydive_username: skydive
skydive_analyzer_port: 8082
skydive_network_device: "{{ ansible_default_ipv4['interface'] | replace('-', '_') }}"
skydive_analyzer_uri: "{{ (skydive_bind_address | default(hostvars[inventory_hostname]['ansible_' ~ skydive_network_device]['ipv4']['address'])) ~ ':' ~ skydive_analyzer_port }}"
tasks:
- name: Check API login
uri:
url: "http://{{ skydive_analyzer_uri }}/login"
status_code: "200"
method: POST
body: "username={{ skydive_username }}&password={{ skydive_password }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
register: skydive_login
- name: Check client status
command: skydive client status --username {{ skydive_username }} --password {{ skydive_password }}
register: skydive_client
until:
- skydive_login is success
- skydive_client is success
retries: 10
delay: 10
- name: Check API status
uri:
url: "http://{{ skydive_analyzer_uri }}/api/status"
method: GET
return_content: true
headers:
Cookie: "{{ skydive_login.set_cookie | regex_replace(',', ';') }}"
register: skydive_response
changed_when: false
until:
- skydive_response is success
- skydive_response.json is defined
retries: 10
delay: 5
run_once: true
- name: Show Skydive agents
debug:
var: "{{ skydive_response.json | to_json }}"
- name: Show Skydive client
debug: var=skydive_client