From ff842922690cd970ed42f8e123c411e4185b056f Mon Sep 17 00:00:00 2001 From: James Kirsch Date: Thu, 23 Apr 2020 08:24:09 -0700 Subject: [PATCH] Add support for encrypting heat api This patch introduces an optional backend encryption for Heat service. When used in conjunction with enabling TLS for service API endpoints, network communcation will be encrypted end to end, from client through HAProxy to the Heat service. Change-Id: Ic12f7574135dcaed2a462e902c775a55176ff03b Partially-Implements: blueprint add-ssl-internal-network Depends-On: https://review.opendev.org/722028/ --- ansible/roles/heat/defaults/main.yml | 9 ++++ ansible/roles/heat/tasks/config.yml | 30 +++++++++++- .../roles/heat/templates/heat-api-cfn.json.j2 | 24 +++++++++- ansible/roles/heat/templates/heat-api.json.j2 | 24 +++++++++- .../heat/templates/wsgi-heat-api-cfn.conf.j2 | 47 +++++++++++++++++++ .../heat/templates/wsgi-heat-api.conf.j2 | 47 +++++++++++++++++++ ...rypt-backend-haproxy-fb96285d74fb464c.yaml | 7 +++ ...end-haproxy-keystone-fb96285d74fb464c.yaml | 7 --- 8 files changed, 183 insertions(+), 12 deletions(-) create mode 100644 ansible/roles/heat/templates/wsgi-heat-api-cfn.conf.j2 create mode 100644 ansible/roles/heat/templates/wsgi-heat-api.conf.j2 create mode 100644 releasenotes/notes/encrypt-backend-haproxy-fb96285d74fb464c.yaml delete mode 100644 releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml diff --git a/ansible/roles/heat/defaults/main.yml b/ansible/roles/heat/defaults/main.yml index 6e13b3b0c7..f44b6e0b33 100644 --- a/ansible/roles/heat/defaults/main.yml +++ b/ansible/roles/heat/defaults/main.yml @@ -16,12 +16,14 @@ heat_services: external: false port: "{{ heat_api_port }}" listen_port: "{{ heat_api_listen_port }}" + tls_backend: "{{ heat_enable_tls_backend }}" heat_api_external: enabled: "{{ enable_heat }}" mode: "http" external: true port: "{{ heat_api_port }}" listen_port: "{{ heat_api_listen_port }}" + tls_backend: "{{ heat_enable_tls_backend }}" heat-api-cfn: container_name: heat_api_cfn group: heat-api-cfn @@ -36,12 +38,14 @@ heat_services: external: false port: "{{ heat_api_cfn_port }}" listen_port: "{{ heat_api_cfn_listen_port }}" + tls_backend: "{{ heat_enable_tls_backend }}" heat_api_cfn_external: enabled: "{{ enable_heat }}" mode: "http" external: true port: "{{ heat_api_cfn_port }}" listen_port: "{{ heat_api_cfn_listen_port }}" + tls_backend: "{{ heat_enable_tls_backend }}" heat-engine: container_name: heat_engine group: heat-engine @@ -173,3 +177,8 @@ heat_ks_user_roles: - project: "{{ openstack_auth.project_name }}" user: "{{ openstack_auth.username }}" role: "{{ heat_stack_owner_role }}" + +#################### +# TLS +#################### +heat_enable_tls_backend: "{{ kolla_enable_tls_backend }}" diff --git a/ansible/roles/heat/tasks/config.yml b/ansible/roles/heat/tasks/config.yml index 844c2027bf..d6117e21bc 100644 --- a/ansible/roles/heat/tasks/config.yml +++ b/ansible/roles/heat/tasks/config.yml @@ -33,7 +33,7 @@ - include_tasks: copy-certs.yml when: - - kolla_copy_ca_into_containers | bool + - kolla_copy_ca_into_containers | bool or heat_enable_tls_backend | bool - name: Copying over config.json files for services become: true @@ -82,5 +82,33 @@ notify: - Restart {{ item.key }} container +- name: Copying over heat-api wsgi config + vars: + service: "{{ heat_services['heat-api'] }}" + template: + src: "{{ role_path }}/templates/wsgi-heat-api.conf.j2" + dest: "{{ node_config_directory }}/heat-api/wsgi-heat-api.conf" + mode: "0660" + become: true + when: + - inventory_hostname in groups[service['group']] + - service.enabled | bool + notify: + - Restart heat-api container + +- name: Copying over heat-api-cfn wsgi config + vars: + service: "{{ heat_services['heat-api-cfn'] }}" + template: + src: "{{ role_path }}/templates/wsgi-heat-api-cfn.conf.j2" + dest: "{{ node_config_directory }}/heat-api-cfn/wsgi-heat-api-cfn.conf" + mode: "0660" + become: true + when: + - inventory_hostname in groups[service['group']] + - service.enabled | bool + notify: + - Restart heat-api-cfn container + - include_tasks: check-containers.yml when: kolla_action != "config" diff --git a/ansible/roles/heat/templates/heat-api-cfn.json.j2 b/ansible/roles/heat/templates/heat-api-cfn.json.j2 index 4077ab4cd2..3d7e483f52 100644 --- a/ansible/roles/heat/templates/heat-api-cfn.json.j2 +++ b/ansible/roles/heat/templates/heat-api-cfn.json.j2 @@ -1,18 +1,38 @@ +{% set heat_api_cfn_cmd = 'apache2' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd' %} +{% set wsgi_conf_dir = 'apache2/conf-enabled' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd/conf.d' %} { - "command": "heat-api-cfn", + "command": "/usr/sbin/{{ heat_api_cfn_cmd }} -DFOREGROUND", "config_files": [ { "source": "{{ container_config_directory }}/heat.conf", "dest": "/etc/heat/heat.conf", "owner": "heat", "perm": "0600" + },{ + "source": "{{ container_config_directory }}/wsgi-heat-api-cfn.conf", + "dest": "/etc/{{ wsgi_conf_dir }}/wsgi-heat-api-cfn.conf", + "owner": "heat", + "perm": "0600" }{% if heat_policy_file is defined %}, { "source": "{{ container_config_directory }}/{{ heat_policy_file }}", "dest": "/etc/heat/{{ heat_policy_file }}", "owner": "heat", "perm": "0600" - }{% endif %} + }{% endif %}{% if heat_enable_tls_backend | bool %}, + { + "source": "{{ container_config_directory }}/heat-cert.pem", + "dest": "/etc/heat/certs/heat-cert.pem", + "owner": "heat", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/heat-key.pem", + "dest": "/etc/heat/certs/heat-key.pem", + "owner": "heat", + "perm": "0600" + } + {% endif %} ], "permissions": [ { diff --git a/ansible/roles/heat/templates/heat-api.json.j2 b/ansible/roles/heat/templates/heat-api.json.j2 index 00a7ac2da2..f339f3383b 100644 --- a/ansible/roles/heat/templates/heat-api.json.j2 +++ b/ansible/roles/heat/templates/heat-api.json.j2 @@ -1,18 +1,38 @@ +{% set heat_api_cmd = 'apache2' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd' %} +{% set wsgi_conf_dir = 'apache2/conf-enabled' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd/conf.d' %} { - "command": "heat-api", + "command": "/usr/sbin/{{ heat_api_cmd }} -DFOREGROUND", "config_files": [ { "source": "{{ container_config_directory }}/heat.conf", "dest": "/etc/heat/heat.conf", "owner": "heat", "perm": "0600" + },{ + "source": "{{ container_config_directory }}/wsgi-heat-api.conf", + "dest": "/etc/{{ wsgi_conf_dir }}/wsgi-heat-api.conf", + "owner": "heat", + "perm": "0600" }{% if heat_policy_file is defined %}, { "source": "{{ container_config_directory }}/{{ heat_policy_file }}", "dest": "/etc/heat/{{ heat_policy_file }}", "owner": "heat", "perm": "0600" - }{% endif %} + }{% endif %}{% if heat_enable_tls_backend | bool %}, + { + "source": "{{ container_config_directory }}/heat-cert.pem", + "dest": "/etc/heat/certs/heat-cert.pem", + "owner": "heat", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/heat-key.pem", + "dest": "/etc/heat/certs/heat-key.pem", + "owner": "heat", + "perm": "0600" + } + {% endif %} ], "permissions": [ { diff --git a/ansible/roles/heat/templates/wsgi-heat-api-cfn.conf.j2 b/ansible/roles/heat/templates/wsgi-heat-api-cfn.conf.j2 new file mode 100644 index 0000000000..2b3136352a --- /dev/null +++ b/ansible/roles/heat/templates/wsgi-heat-api-cfn.conf.j2 @@ -0,0 +1,47 @@ +{% set heat_log_dir = '/var/log/kolla/heat' %} +{% if heat_install_type == 'binary' %} +{% set python_path = '/usr/lib/python3/dist-packages' if kolla_base_distro in ['debian', 'ubuntu'] else '/usr/lib/python2.7/site-packages' %} +{% else %} +{% set python_path = '/usr/lib/python' ~ distro_python_version ~ '/site-packages' %} +{% endif %} +{% set binary_path = '/usr/bin' if heat_install_type == 'binary' else '/var/lib/kolla/venv/bin' %} +{% if heat_enable_tls_backend | bool %} +{% if kolla_base_distro in ['centos'] %} +LoadModule ssl_module /usr/lib64/httpd/modules/mod_ssl.so +{% else %} +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so +{% endif %} +{% endif %} +Listen {{ api_interface_address | put_address_in_context('url') }}:{{ heat_api_cfn_listen_port }} + +ServerSignature Off +ServerTokens Prod +TraceEnable off + + + + AllowOverride None + Options None + Require all granted + + + + + + WSGIDaemonProcess heat-api-cfn processes={{ openstack_service_workers }} threads=1 user=heat group=heat display-name=%{GROUP} python-path={{ python_path }} + WSGIProcessGroup heat-api-cfn + WSGIScriptAlias / {{ binary_path }}/heat-wsgi-api-cfn + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + = 2.4> + ErrorLogFormat "%{cu}t %M" + + ErrorLog "{{ heat_log_dir }}/heat-api-cfn-error.log" + LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat + CustomLog "{{ heat_log_dir }}/heat-api-cfn-error.log" logformat +{% if heat_enable_tls_backend | bool %} + SSLEngine On + SSLCertificateFile /etc/heat/certs/heat-cert.pem + SSLCertificateKeyFile /etc/heat/certs/heat-key.pem +{% endif %} + diff --git a/ansible/roles/heat/templates/wsgi-heat-api.conf.j2 b/ansible/roles/heat/templates/wsgi-heat-api.conf.j2 new file mode 100644 index 0000000000..bdba923fbe --- /dev/null +++ b/ansible/roles/heat/templates/wsgi-heat-api.conf.j2 @@ -0,0 +1,47 @@ +{% set heat_log_dir = '/var/log/kolla/heat' %} +{% if heat_install_type == 'binary' %} +{% set python_path = '/usr/lib/python3/dist-packages' if kolla_base_distro in ['debian', 'ubuntu'] else '/usr/lib/python2.7/site-packages' %} +{% else %} +{% set python_path = '/usr/lib/python' ~ distro_python_version ~ '/site-packages' %} +{% endif %} +{% set binary_path = '/usr/bin' if heat_install_type == 'binary' else '/var/lib/kolla/venv/bin' %} +{% if heat_enable_tls_backend | bool %} +{% if kolla_base_distro in ['centos'] %} +LoadModule ssl_module /usr/lib64/httpd/modules/mod_ssl.so +{% else %} +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so +{% endif %} +{% endif %} +Listen {{ api_interface_address | put_address_in_context('url') }}:{{ heat_api_listen_port }} + +ServerSignature Off +ServerTokens Prod +TraceEnable off + + + + AllowOverride None + Options None + Require all granted + + + + + + WSGIDaemonProcess heat-api processes={{ openstack_service_workers }} threads=1 user=heat group=heat display-name=%{GROUP} python-path={{ python_path }} + WSGIProcessGroup heat-api + WSGIScriptAlias / {{ binary_path }}/heat-wsgi-api + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + = 2.4> + ErrorLogFormat "%{cu}t %M" + + ErrorLog "{{ heat_log_dir }}/heat-api-error.log" + LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat + CustomLog "{{ heat_log_dir }}/heat-api-error.log" logformat +{% if heat_enable_tls_backend | bool %} + SSLEngine On + SSLCertificateFile /etc/heat/certs/heat-cert.pem + SSLCertificateKeyFile /etc/heat/certs/heat-key.pem +{% endif %} + diff --git a/releasenotes/notes/encrypt-backend-haproxy-fb96285d74fb464c.yaml b/releasenotes/notes/encrypt-backend-haproxy-fb96285d74fb464c.yaml new file mode 100644 index 0000000000..61baa77537 --- /dev/null +++ b/releasenotes/notes/encrypt-backend-haproxy-fb96285d74fb464c.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Added configuration options to enable backend TLS encryption from HAProxy + to the Keystone, Heat, and cinder service. When used in conjunction with + enabling TLS for service API endpoints, network communcation will be + encrypted end to end, from client through HAProxy to the backend service. diff --git a/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml b/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml deleted file mode 100644 index 2a778e9e72..0000000000 --- a/releasenotes/notes/encrypt-backend-haproxy-keystone-fb96285d74fb464c.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Added configuration options to enable backend TLS encryption from HAProxy - to the Keystone and cinder service. When used in conjunction with enabling - TLS for service API endpoints, network communcation will be encrypted end - to end, from client through HAProxy to the backend service.