Chapter 6. Hardening the Dashboard service

This chapter describes security hardening considerations for Red Hat OpenStack Platform deployments that use the OpenStack Dashboard (horizon).

The Dashboard gives users a self-service portal for provisioning their own resources (within the limits set by administrators). For example, you can use the Dashboard to define instance flavors, upload virtual machine (VM) images, manage virtual networks, create security groups, start instances, and remotely access the instances through a management console.

The Dashboard should be treated with the same sensitivity as the OpenStack APIs, given both have the ability to grant access to cloud resources and configuration.

6.1. Planning Dashboard deployment

This section describes security aspects to consider prior to deploying the Dashboard (horizon) service.

6.1.1. Selecting a domain name

It is recommended that you deploy dashboard to a second-level domain, such as https://example.com, rather than deploying dashboard on a shared subdomain (at any level), for example https://openstack.example.org or https://horizon.openstack.example.org. It is also suggested that you avoid deploying the Dashboard to bare internal domains, such as https://horizon/. These recommendations are based on the limitations of browser same-origin-policy.

This approach helps you isolate cookies and security tokens from other domains, where you might not have complete control of the content. When deployed on a subdomain, the dashboard’s security is equivalent to the least secure application deployed on the same second-level domain.

You can further mitigate this risk by avoiding a cookie-backed session store, and configuring HTTP Strict Transport Security (HSTS) (described in this guide).

6.1.2. Configure ALLOWED_HOSTS

Web services can be vulnerable to threats associated with fake HTTP Host headers. To help mitigate this, consider configuring the ALLOWED_HOSTS setting to use the FQDN served by the OpenStack dashboard.

Once configured, if the value in the Host: header of an incoming HTTP request does not match any of the values in this list, an error will be raised and the requestor will not be able to proceed.

Horizon is built on the python Django web framework, which requires ALLOWED_HOSTS be set to protect against potentially malicious manipulation of the HTTP Host: header. Set this value to the FQDN the dashboard should be accessible from. For director, this setting is managed by HorizonAllowedHosts.

6.2. Understanding common web server vulnerabilities

This chapter describes how you can help mitigate some common web server vulnerabilities.

6.2.1. Cross Site Scripting (XSS)

The OpenStack Dashboard is customizable, and allows the entire Unicode character set in most fields; this extensibility could allow the introduction of cross-site scripting (XSS) vulnerabilities. Horizon includes tools to help developers avoid inadvertently creating XSS vulnerabilities, but they only work if developers use them correctly. It is recommended that you audit any custom dashboards, and pay particular attention to the following capabilities:

  • The mark_safe function.
  • is_safe - when used with custom template tags.
  • The safe template tag.
  • Anywhere auto escape is turned off, and any JavaScript which might evaluate improperly escaped data.

6.2.2. Cross Site Request Forgery (CSRF)

The OpenStack dashboard is designed to discourage developers from introducing cross-site scripting vulnerabilities with custom dashboards, as there is potential for threats to be introduced. Dashboards that use multiple JavaScript instances should be audited for vulnerabilities, such as inappropriate use of the @csrf_exempt decorator. Any dashboard that does not follow these recommended security settings should be carefully evaluated before CORS (Cross Origin Resource Sharing) restrictions are relaxed.

You should configure your web server to send a restrictive CORS header with each response, allowing only the dashboard domain and protocol. For example:Access-Control-Allow-Origin: https://example.com/. You should never allow the wild card origin.

6.2.3. Cross-Frame Scripting (XFS)

The disallow_iframe_embed setting disallows Dashboard from being embedded within an iframe. Legacy browsers can still be vulnerable to Cross-Frame Scripting (XFS) vulnerabilities, so this option adds extra security hardening for deployments that do not require iframes.

You can allow iframe embedding using the following parameter:

    parameter_defaults:
      ControllerExtraConfig:
        horizon::disallow_iframe_embed: false

6.2.4. Using HTTPS encryption for Dashboard traffic

It is recommended you use HTTPS to encrypt Dashboard traffic. You can do this by configuring it to use a valid, trusted certificate from a recognized certificate authority (CA). Private organization-issued certificates are only appropriate when the root of trust is pre-installed in all user browsers.

Configure HTTP requests to the dashboard domain to redirect to the fully qualified HTTPS URL.

For director-based deployments, see https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/14/html/advanced_overcloud_customization/sect-enabling_ssltls_on_the_overcloud.

6.2.5. HTTP Strict Transport Security (HSTS)

HTTP Strict Transport Security (HSTS) prevents browsers from making subsequent insecure connections after they have initially made a secure connection. If you have deployed your HTTP services on a public or an untrusted zone, HSTS is especially important.

For director-based deployments, this setting is enabled by default:

enable_secure_proxy_ssl_header: true

6.3. Caching the Dashboard content

6.3.1. Front-end caching

It is not recommended to use front-end caching tools with the Dashboard, as it renders dynamic content resulting directly from OpenStack API requests. As a result, front-end caching layers such as varnish can prevent the correct content from being displayed. The Dashboard uses Django, which serves static media directly served from the web service and already benefits from web host caching.

6.3.2. Session backend

For director-based deployments, the default session backend for horizon is django.contrib.sessions.backends.cache, which is combined with memcached. This approach is preferred to local-memory cache for performance reasons, is safer for highly-available and load balanced installs, and has the ability to share cache over multiple servers, while still treating it as a single cache.

You can review these settings in director’s horizon.yaml file:

          horizon::cache_backend: django.core.cache.backends.memcached.MemcachedCache
          horizon::django_session_engine: 'django.contrib.sessions.backends.cache'

6.4. Reviewing the secret key

The Dashboard depends on a shared SECRET_KEY setting for some security functions. The secret key should be a randomly generated string at least 64 characters long, which must be shared across all active dashboard instances. Compromise of this key might allow a remote attacker to execute arbitrary code. Rotating this key invalidates existing user sessions and caching. Do not commit this key to public repositories.

For director deployments, this setting is managed as the HorizonSecret value.

6.5. Configuring session cookies

The Dashboard session cookies can be open to interaction by browser technologies, such as JavaScript. For director deployments, you can harden this behavior using the HorizonSecureCookies setting.

Note

Never configure CSRF or session cookies to use a wildcard domain with a leading dot.

6.6. Static media

The dashboard’s static media should be deployed to a subdomain of the dashboard domain and served by the web server. The use of an external content delivery network (CDN) is also acceptable. This subdomain should not set cookies or serve user-provided content. The media should also be served with HTTPS.

Dashboard’s default configuration uses django_compressor to compress and minify CSS and JavaScript content before serving it. This process should be statically done before deploying the dashboard, rather than using the default in-request dynamic compression and copying the resulting files along with deployed code or to the CDN server. Compression should be done in a non-production build environment. If this is not practical, consider disabling resource compression entirely. Online compression dependencies (less, Node.js) should not be installed on production machines.

6.7. Validating password complexity

The OpenStack Dashboard (horizon) can use a password validation check to enforce password complexity.

You can specify a regular expression for password validation, as well as help text to be displayed for failed tests. The following example requires users to create a password of between 8 to 18 characters in length:

    parameter_defaults:
      HorizonPasswordValidator: '^.{8,18}$'
      HorizonPasswordValidatorHelp: 'Password must be between 8 and 18 characters.'

To apply this change to your deployment, save the settings as a file called horizon_password.yaml, and then pass it to the overcloud deploy command as follows. The <full environment> indicates that you must still include all of your original deployment parameters. For example:

    openstack overcloud deploy --templates \
      -e <full environment> -e  horizon_password.yaml

6.8. Enforce the administrator password check

The following setting is set to True by default, however it can be disabled using an environment file, if needed.

Note

These settings should only be set to False once the potential security impacts are fully understood.

The ENFORCE_PASSWORD_CHECK setting in Dashboard’s local_settings.py file displays an Admin Password field on the Change Password form, which helps verify that an administrator is initiating the password change.

You can disable ENFORCE_PASSWORD_CHECK using an environment file:

    parameter_defaults:
      ControllerExtraConfig:
        horizon::enforce_password_check: false

6.9. Disallow iframe embedding

Note

These settings should only be set to False once the potential security impacts are fully understood.

The DISALLOW_IFRAME_EMBED setting disallows Dashboard from being embedded within an iframe. Legacy browsers can still be vulnerable to Cross-Frame Scripting (XFS) vulnerabilities, so this option adds extra security hardening for deployments that do not require iframes. The setting is set to True by default, however it can be disabled using an environment file, if needed. For example, you can allow iframe embedding using the following parameter:

    parameter_defaults:
      ControllerExtraConfig:
        horizon::disallow_iframe_embed: false

6.10. Disable password reveal

The following setting is set to True by default, however it can be disabled using an environment file, if needed.

Note

These settings should only be set to False once the potential security impacts are fully understood.

The password reveal button allows a user at the Dashboard to view the password they are about to enter. This option can be toggled using the DISABLE_PASSWORD_REVEAL parameter:

    parameter_defaults:
      ControllerExtraConfig:
        horizon::disable_password_reveal: false

6.11. Display a logon banner for the Dashboard

Many regulated industries, such as HIPAA, PCI-DSS, and the U.S. Government, require you to display a user logo banner. You can create a logon banner by manually editing the /usr/share/openstack-dashboard/openstack_dashboard/themes/rcue/templates/auth/login.html file:

  1. Enter the required logon banner immediately prior to the {% include 'auth/_login.html' %} section. Note that HTML tags are allowed. For example:

    <snip>
    <div class="container">
      <div class="row-fluid">
        <div class="span12">
          <div id="brand">
            <img src="../../static/themes/rcue/images/RHOSP-Login-Logo.svg">
          </div><!--/#brand-->
        </div><!--/.span*-->
    
        <!-- Start of Logon Banner -->
        <p>Authentication to this information system reflects acceptance of user monitoring agreement.</p>
        <!-- End of Logon Banner -->
    
        {% include 'auth/_login.html' %}
      </div><!--/.row-fluid→
    </div><!--/.container-->
    
    {% block js %}
      {% include "horizon/_scripts.html" %}
    {% endblock %}
    
      </body>
    </html>
  2. The logon banner text will display immediately upon writing the file, and no restart of OpenStack services is needed. The updated dashboard will look similar to the following:

    logonbanner

6.12. Debugging the Dashboard service

It is recommend that you keep the DEBUG setting set to False in production environments. If set to True, Django might output stack traces to browser users that contain sensitive web server state information. In addition, DEBUG mode has the effect of disabling ALLOWED_HOSTS, which could be an undesirable result, depending on your requirements.