Implement TLS encryption for internal endpoints

This review is the first one in a series of patches and it introduces an
optional encryption for internal openstack endpoints, implementing part
of the add-ssl-internal-network spec.

Change-Id: I6589751626486279bf24725f22e71da8cd7f0a43
This commit is contained in:
Krzysztof Klimonda 2019-06-07 13:56:21 +00:00 committed by James Kirsch
parent aa135e37f7
commit b0ecd8b67c
15 changed files with 116 additions and 33 deletions

View File

@ -35,7 +35,8 @@ kolla_install_type: "binary"
kolla_internal_vip_address: "{{ kolla_internal_address }}"
kolla_internal_fqdn: "{{ kolla_internal_vip_address }}"
kolla_external_vip_address: "{{ kolla_internal_vip_address }}"
kolla_external_fqdn: "{{ kolla_internal_fqdn if kolla_external_vip_address == kolla_internal_vip_address else kolla_external_vip_address }}"
kolla_same_external_internal_vip: "{{ kolla_external_vip_address == kolla_internal_vip_address }}"
kolla_external_fqdn: "{{ kolla_internal_fqdn if kolla_same_external_internal_vip | bool else kolla_external_vip_address }}"
kolla_enable_sanity_checks: "no"
@ -457,8 +458,8 @@ opendaylight_websocket_port: "8185"
vitrage_api_port: "8999"
public_protocol: "{{ 'https' if kolla_enable_tls_external | bool else 'http' }}"
internal_protocol: "http"
admin_protocol: "http"
internal_protocol: "{{ 'https' if kolla_enable_tls_internal | bool else 'http' }}"
admin_protocol: "{{ 'https' if kolla_enable_tls_internal | bool else 'http' }}"
####################
# OpenStack options
@ -723,10 +724,13 @@ qdrouterd_user: "openstack"
# HAProxy options
####################
haproxy_user: "openstack"
haproxy_enable_external_vip: "{{ 'no' if kolla_external_vip_address == kolla_internal_vip_address else 'yes' }}"
kolla_enable_tls_external: "no"
haproxy_enable_external_vip: "{{ 'no' if kolla_same_external_internal_vip | bool else 'yes' }}"
kolla_enable_tls_internal: "no"
kolla_enable_tls_external: "{{ kolla_enable_tls_internal if kolla_same_external_internal_vip | bool else 'no' }}"
kolla_external_fqdn_cert: "{{ node_config }}/certificates/haproxy.pem"
kolla_internal_fqdn_cert: "{{ node_config }}/certificates/haproxy-internal.pem"
kolla_external_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca.crt"
kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca-internal.crt"
####################

View File

@ -9,6 +9,8 @@ export OS_INTERFACE=internal
export OS_IDENTITY_API_VERSION=3
export OS_REGION_NAME={{ openstack_region_name }}
export OS_AUTH_PLUGIN=password
{% if kolla_enable_tls_external | bool and kolla_external_fqdn_cacert %}
{% if kolla_enable_tls_internal | bool and kolla_internal_fqdn_cacert %}
export OS_CACERT={{ kolla_internal_fqdn_cacert }}
{% elif kolla_enable_tls_external | bool and kolla_external_fqdn_cacert %}
export OS_CACERT={{ kolla_external_fqdn_cacert }}
{% endif %}

View File

@ -1,5 +1,6 @@
#jinja2: lstrip_blocks: True
{%- set tls_bind_info = 'ssl crt /etc/haproxy/haproxy.pem' if kolla_enable_tls_external|bool else '' %}
{%- set external_tls_bind_info = 'ssl crt /etc/haproxy/haproxy.pem' if kolla_enable_tls_external|bool else '' %}
{%- set internal_tls_bind_info = 'ssl crt /etc/haproxy/haproxy-internal.pem' if kolla_enable_tls_internal|bool else '' %}
{%- macro userlist_macro(service_name, auth_user, auth_pass) %}
userlist {{ service_name }}-user
@ -36,12 +37,17 @@ listen {{ service_name }}
{% if external|bool %}
{% set vip_address = kolla_external_vip_address %}
{% if service_mode == 'http' %}
{% set tls_option = tls_bind_info %}
{% set tls_option = external_tls_bind_info %}
{# Replace the XFP header for external https requests #}
http-request set-header X-Forwarded-Proto https if { ssl_fc }
{% endif %}
{% else %}
{% set vip_address = kolla_internal_vip_address %}
{% if service_mode == 'http' %}
{% set tls_option = internal_tls_bind_info %}
{# Replace the XFP header for internal https requests #}
http-request set-header X-Forwarded-Proto https if { ssl_fc }
{% endif %}
{% endif %}
{{ "bind %s:%s %s"|e|format(vip_address, service_port, tls_option)|trim() }}
{# Redirect mode sets a redirect scheme instead of members #}

View File

@ -1,5 +1,6 @@
#jinja2: lstrip_blocks: True
{%- set tls_bind_info = 'ssl crt /etc/haproxy/haproxy.pem' if kolla_enable_tls_external|bool else '' %}
{%- set external_tls_bind_info = 'ssl crt /etc/haproxy/haproxy.pem' if kolla_enable_tls_external|bool else '' %}
{%- set internal_tls_bind_info = 'ssl crt /etc/haproxy/haproxy-internal.pem' if kolla_enable_tls_internal|bool else '' %}
{%- macro userlist_macro(service_name, auth_user, auth_pass) %}
userlist {{ service_name }}-user
@ -29,12 +30,17 @@ frontend {{ service_name }}_front
{% if external|bool %}
{% set vip_address = kolla_external_vip_address %}
{% if service_mode == 'http' %}
{% set tls_option = tls_bind_info %}
{% set tls_option = external_tls_bind_info %}
{# Replace the XFP header for external https requests #}
http-request set-header X-Forwarded-Proto https if { ssl_fc }
{% endif %}
{% else %}
{% set vip_address = kolla_internal_vip_address %}
{% if service_mode == 'http' %}
{% set tls_option = internal_tls_bind_info %}
{# Replace the XFP header for internal https requests #}
http-request set-header X-Forwarded-Proto https if { ssl_fc }
{% endif %}
{% endif %}
{{ "bind %s:%s %s"|e|format(vip_address, service_port, tls_option)|trim() }}
{# Redirect mode sets a redirect scheme instead of a backend #}

View File

@ -109,6 +109,23 @@
notify:
- Restart haproxy container
- name: Copying over haproxy-internal.pem
vars:
service: "{{ haproxy_services['haproxy'] }}"
copy:
src: "{{ kolla_internal_fqdn_cert }}"
dest: "{{ node_config_directory }}/haproxy/{{ item }}"
mode: "0660"
become: true
when:
- kolla_enable_tls_internal | bool
- inventory_hostname in groups[service.group]
- service.enabled | bool
with_items:
- "haproxy-internal.pem"
notify:
- Restart haproxy container
- name: Copying over haproxy start script
vars:
service: "{{ haproxy_services['haproxy'] }}"

View File

@ -77,20 +77,34 @@
check_mode: no
run_once: true
- name: Checking if haproxy certificate exists
- name: Checking if external haproxy certificate exists
run_once: true
local_action: stat path={{ kolla_external_fqdn_cert }}
register: haproxy_cert_file
changed_when: false
when: kolla_enable_tls_external | bool
- name: Fail if haproxy certificate is absent
- name: Fail if external haproxy certificate is absent
run_once: true
local_action: fail msg="haproxy certificate file is not found. Ensure it exists as {{ kolla_external_fqdn_cert }}"
local_action: fail msg="External haproxy certificate file is not found. It is configured via 'kolla_external_fqdn_cert'"
when:
- kolla_enable_tls_external | bool
- haproxy_cert_file.stat.exists == false
- name: Checking if internal haproxy certificate exists
run_once: true
local_action: stat path={{ kolla_internal_fqdn_cert }}
register: haproxy_internal_cert_file
changed_when: false
when: kolla_enable_tls_internal | bool
- name: Fail if internal haproxy certificate is absent
run_once: true
local_action: fail msg="Internal haproxy certificate file is not found. It is configured via 'kolla_internal_fqdn_cert'"
when:
- kolla_enable_tls_internal | bool
- haproxy_internal_cert_file.stat.exists == false
- name: Checking the kolla_external_vip_interface is present
fail: "msg='Please check the kolla_external_vip_interface property - interface {{ kolla_external_vip_interface }} not found'"
when:

View File

@ -25,6 +25,13 @@
"owner": "root",
"perm": "0600",
"optional": {{ (not kolla_enable_tls_external | bool) | string | lower }}
},
{
"source": "{{ container_config_directory }}/haproxy-internal.pem",
"dest": "/etc/haproxy/haproxy-internal.pem",
"owner": "root",
"perm": "0600",
"optional": {{ (not kolla_enable_tls_internal | bool) | string | lower }}
}
]
}

View File

@ -13,7 +13,7 @@ global
{% endfor %}
{% endif %}
stats socket /var/lib/kolla/haproxy/haproxy.sock group kolla mode 660
{% if kolla_enable_tls_external | bool %}
{% if kolla_enable_tls_external or kolla_enable_tls_internal | bool %}
ssl-default-bind-ciphers DEFAULT:!MEDIUM:!3DES
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
tune.ssl.default-dh-param 4096

View File

@ -42,10 +42,16 @@ horizon_services:
enabled: "{{ enable_horizon }}"
mode: "http"
external: false
port: "{{ horizon_port }}"
port: "{% if kolla_enable_tls_internal|bool %}443{% else %}{{ horizon_port }}{% endif %}"
listen_port: "{{ horizon_listen_port }}"
frontend_http_extra:
- "balance source"
horizon_redirect:
enabled: "{{ enable_horizon|bool and kolla_enable_tls_internal|bool }}"
mode: "redirect"
external: false
port: "{{ horizon_port }}"
listen_port: "{{ horizon_listen_port }}"
horizon_external:
enabled: "{{ enable_horizon }}"
mode: "http"

View File

@ -32,7 +32,7 @@ TraceEnable off
</Location>
</VirtualHost>
{% if kolla_enable_tls_external | bool %}
{% if kolla_enable_tls_external or kolla_enable_tls_internal| bool %}
Header edit Location ^http://(.*)$ https://$1
{% endif %}

View File

@ -55,7 +55,7 @@ DATABASES = {
#CSRF_COOKIE_SECURE = True
#SESSION_COOKIE_SECURE = True
{% if kolla_enable_tls_external | bool %}
{% if kolla_enable_tls_external or kolla_enable_tls_internal | bool %}
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True

View File

@ -234,7 +234,7 @@ debug = {{ nova_logging_debug }}
[wsgi]
api_paste_config = /etc/nova/api-paste.ini
{% if kolla_enable_tls_external | bool %}
{% if kolla_enable_tls_external or kolla_enable_tls_internal | bool %}
secure_proxy_ssl_header = HTTP_X_FORWARDED_PROTO
{% endif %}

View File

@ -33,10 +33,11 @@
when:
- nscd_status.rc == 0
- name: Checking internal and external VIP addresses differ
- name: Validate that internal and external vip address are different when TLS is enabled only on either the internal and external network
run_once: True
local_action: fail msg='kolla_external_vip_address and kolla_internal_vip_address must not be the same when TLS is enabled'
local_action: fail msg='kolla_external_vip_address and kolla_internal_vip_address must not be the same when only one network has TLS enabled'
changed_when: false
when:
- kolla_enable_tls_external | bool
- kolla_external_vip_address == kolla_internal_vip_address
- kolla_enable_tls_external | bool or kolla_enable_tls_internal | bool
- not (kolla_enable_tls_external | bool and kolla_enable_tls_internal | bool)
- kolla_same_external_internal_vip | bool

View File

@ -73,19 +73,26 @@ TLS Configuration
~~~~~~~~~~~~~~~~~
An additional endpoint configuration option is to enable or disable
TLS protection for the external VIP. TLS allows a client to authenticate
the OpenStack service endpoint and allows for encryption of the requests
and responses.
.. note::
The kolla_internal_vip_address and kolla_external_vip_address must
be different to enable TLS on the external network.
TLS protection for the internal and/or external VIP. TLS allows a client to
authenticate the OpenStack service endpoint and allows for encryption of the
requests and responses.
The configuration variables that control TLS networking are:
- kolla_enable_tls_external
- kolla_external_fqdn_cert
- kolla_enable_tls_internal
- kolla_internal_fqdn_cert
.. note::
If TLS is enabled only on the internal or the external network
the kolla_internal_vip_address and kolla_external_vip_address must
be different.
If there is only a single network configured in your network topology
(opposed to configuring seperate internal and external networks), TLS
can be enabled using only the internal network configuration variables.
The default for TLS is disabled, to enable TLS networking:
@ -94,6 +101,12 @@ The default for TLS is disabled, to enable TLS networking:
kolla_enable_tls_external: "yes"
kolla_external_fqdn_cert: "{{ node_config }}/certificates/mycert.pem"
and/or
kolla_enable_tls_internal: "yes"
kolla_internal_fqdn_cert: "{{ node_config }}/certificates/mycert-internal.pem"
.. note::
TLS authentication is based on certificates that have been
@ -111,9 +124,9 @@ These two files will be provided by your Certificate Authority. These
two files are the server certificate with private key and the CA certificate
with any intermediate certificates. The server certificate needs to be
installed with the kolla deployment and is configured with the
``kolla_external_fqdn_cert`` parameter. If the server certificate provided
is not already trusted by the client, then the CA certificate file will
need to be distributed to the client.
``kolla_external_fqdn_cert`` or ``kolla_internal_fqdn_cert`` parameter.
If the server certificate provided is not already trusted by the client,
then the CA certificate file will need to be distributed to the client.
When using TLS to connect to a public endpoint, an OpenStack client will
have settings similar to this:

View File

@ -0,0 +1,7 @@
---
features:
- |
Added configuration parameters ``kolla_enable_tls_internal``,
``kolla_internal_fqdn_cert``, and ``kolla_internal_fqdn_cacert`` to
optionally enable TLS encryption for openstack endpoints on the internal
network.