From 4283200534eafa444efd9bb408ddcb5c98a1d442 Mon Sep 17 00:00:00 2001 From: "Amy Marrich (spotz)" Date: Thu, 4 Oct 2018 09:06:38 -0500 Subject: [PATCH] Add ability for HTTP access to horizon Horizon has, since OSA's inception, been deployed with HTTPS access enabled, and has had no way to turn it off. Some use-cases may want to access via HTTP instead, so this patch enables the following: 1. Listen via HTTPS on a load balancer, but via HTTP on the horizon host and have the load balancer forward the correct headers. It will do this by default in the integrated build due to the presence of the load balancer, so the current behaviour is retained. 2. Enable HTTPS on the horizon host without a load balancer. This is the role's default behaviour which matches what it always has been. 3. Disable HTTPS entirely by setting ``haproxy_ssl: no`` (which will also disable https on haproxy. This setting is inherited by the new ``horizon_enable_ssl`` variable by default. This is a new option. Co-Authored-By: Jesse Pretorius Change-Id: I823f2f949258157e306dbf80570abe53373da0c3 Closes-Bug: 1794337 --- defaults/main.yml | 16 +++++++++++--- .../http-access-horizon-94c27a0aadb9f1b4.yaml | 22 +++++++++++++++++++ tasks/main.yml | 12 ++++++---- templates/horizon_local_settings.py.j2 | 9 +++++++- templates/openstack_dashboard.conf.j2 | 19 +++++++++++----- tests/os_horizon-overrides.yml | 5 +++++ 6 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 releasenotes/notes/http-access-horizon-94c27a0aadb9f1b4.yaml diff --git a/defaults/main.yml b/defaults/main.yml index 6cc4e359..91de19ac 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -203,11 +203,21 @@ horizon_ssl_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT/CN={{ horizo # horizon_user_ssl_key: # horizon_user_ssl_ca_cert: -# Set this to True if you do ssl termination on an external device, like the -# load balancer -horizon_external_ssl: false +# Toggle whether horizon should be served via SSL +horizon_enable_ssl: "{{ (haproxy_ssl | default(True)) | bool }}" + +# Toggle whether horizon is served via an external device, like a load +# balancer. This enables the use of the horizon_secure_proxy_ssl_header +# in the web server configuration. +# Note (odyssey4me): +# This variable is actually badly named, as it applies +# settings which have nothing to do with SSL. +horizon_external_ssl: "{{ (openstack_external_ssl | default(False)) | bool }}" # Set this to the header that your device sets when doing ssl termination +# Note (odyssey4me): +# This variable is actually badly named, as it applies +# settings which have nothing to do with SSL. horizon_secure_proxy_ssl_header: "X-Forwarded-Proto" horizon_secure_proxy_ssl_header_django: "HTTP_{{ horizon_secure_proxy_ssl_header | replace('-', '_') | upper }}" diff --git a/releasenotes/notes/http-access-horizon-94c27a0aadb9f1b4.yaml b/releasenotes/notes/http-access-horizon-94c27a0aadb9f1b4.yaml new file mode 100644 index 00000000..5e645f42 --- /dev/null +++ b/releasenotes/notes/http-access-horizon-94c27a0aadb9f1b4.yaml @@ -0,0 +1,22 @@ +--- +features: + - | + Horizon has, since OSA's inception, been deployed with HTTPS + access enabled, and has had no way to turn it off. Some use-cases + may want to access via HTTP instead, so this patch enables + the following. + + * Listen via HTTPS on a load balancer, but via HTTP on the + horizon host and have the load balancer forward the correct + headers. It will do this by default in the integrated build + due to the presence of the load balancer, so the current + behaviour is retained. + + * Enable HTTPS on the horizon host without a load balancer. + This is the role's default behaviour which matches what it + always has been. + + * Disable HTTPS entirely by setting ``haproxy_ssl: no`` (which + will also disable https on haproxy. This setting is inherited + by the new ``horizon_enable_ssl`` variable by default. This + is a new option. diff --git a/tasks/main.yml b/tasks/main.yml index d925b10d..699b834c 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -58,21 +58,25 @@ - include_tasks: horizon_ssl_self_signed.yml when: - - not horizon_external_ssl | bool + - horizon_enable_ssl | bool + - not (horizon_external_ssl | bool) - horizon_user_ssl_cert is not defined or horizon_user_ssl_key is not defined tags: - horizon-config - include_tasks: horizon_ssl_user_provided.yml - when: not horizon_external_ssl | bool + when: + - horizon_enable_ssl | bool + - not (horizon_external_ssl | bool) tags: - horizon-config - name: Update the ca certificates command: "update-ca-certificates -f" when: - - not horizon_external_ssl | bool - - ansible_pkg_mgr == 'apt' + - horizon_enable_ssl | bool + - not (horizon_external_ssl | bool) + - ansible_pkg_mgr == 'apt' tags: - horizon-config - horizon-ssl diff --git a/templates/horizon_local_settings.py.j2 b/templates/horizon_local_settings.py.j2 index 87825379..e6aa1d02 100644 --- a/templates/horizon_local_settings.py.j2 +++ b/templates/horizon_local_settings.py.j2 @@ -37,7 +37,7 @@ WEBROOT = '{{ horizon_webroot }}' # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = ['*'] -{% if horizon_external_ssl | bool %} +{% if (horizon_enable_ssl | bool) and (horizon_external_ssl | bool) %} # Set SSL proxy settings: # For Django 1.4+ pass this header from the proxy after terminating the SSL, # and don't forget to strip it from the client's request. @@ -46,10 +46,17 @@ ALLOWED_HOSTS = ['*'] SECURE_PROXY_SSL_HEADER = ('{{ horizon_secure_proxy_ssl_header_django }}', 'https') {% endif %} +{% if horizon_enable_ssl | bool %} # If Horizon is being served through SSL, then uncomment the following two # settings to better secure the cookies from security exploits CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True +{% else %} +# If Horizon is being served through SSL, then uncomment the following two +# settings to better secure the cookies from security exploits +CSRF_COOKIE_SECURE = False +SESSION_COOKIE_SECURE = False +{% endif %} # Define the time after which a Horizon session expires SESSION_TIMEOUT = {{ horizon_session_timeout }} diff --git a/templates/openstack_dashboard.conf.j2 b/templates/openstack_dashboard.conf.j2 index ff5ed7ea..8d8c0321 100644 --- a/templates/openstack_dashboard.conf.j2 +++ b/templates/openstack_dashboard.conf.j2 @@ -1,6 +1,8 @@ # {{ ansible_managed }} -{% if not horizon_external_ssl | bool %} +# If horizon is being served via SSL from this web server, +# then we must redirect HTTP requests to HTTPS. +{% if (horizon_enable_ssl | bool) and not (horizon_external_ssl | bool) %} ServerName {{ horizon_server_name }} RewriteEngine On @@ -9,14 +11,16 @@ {% endif %} - +# If horizon is being served via SSL via a load balancer, we +# need to listen via HTTP on this web server. If SSL is not +# enabled, then the same applies. + ServerName {{ horizon_server_name }} - LogLevel {{ horizon_log_level }} ErrorLog /var/log/horizon/horizon-error.log CustomLog /var/log/horizon/ssl_access.log {{ horizon_apache_custom_log_format }} Options +FollowSymLinks -{% if not horizon_external_ssl | bool %} +{% if (horizon_enable_ssl | bool) and not (horizon_external_ssl | bool) %} SSLEngine on SSLCertificateFile {{ horizon_ssl_cert }} SSLCertificateKeyFile {{ horizon_ssl_key }} @@ -24,12 +28,15 @@ SSLCACertificateFile {{ horizon_ssl_ca_cert }} {% endif -%} SSLCompression Off - SSLProtocol {{ horizon_ssl_protocol }} + SSLProtocol {{ horizon_ssl_protocol }} SSLHonorCipherOrder On SSLCipherSuite {{ horizon_ssl_cipher_suite }} SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown -{% else %} +{% endif %} +{% if (horizon_enable_ssl | bool) and (horizon_external_ssl | bool) %} RequestHeader set {{ horizon_secure_proxy_ssl_header }} "https" +{% elif not (horizon_enable_ssl | bool) and (horizon_external_ssl | bool) %} + RequestHeader set {{ horizon_secure_proxy_ssl_header }} "http" {% endif %} WSGIScriptAlias / {{ horizon_lib_wsgi_file }} diff --git a/tests/os_horizon-overrides.yml b/tests/os_horizon-overrides.yml index 48828543..9876e85d 100644 --- a/tests/os_horizon-overrides.yml +++ b/tests/os_horizon-overrides.yml @@ -37,3 +37,8 @@ tempest_tempest_conf_overrides: horizon_config_overrides: X_TEST_OPTION: True + +# This has to be set here because the common test-vars +# has haproxy_ssl set to no. +horizon_enable_ssl: yes +