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 +