DashboardHorizon is the OpenStack dashboard, providing access to a majority of the capabilities available in OpenStack. These include provisioning users, defining instance flavors, uploading VM images, managing networks, setting up security groups, starting instances, and accessing the instances via a console.Horizon is based on the Django web framework, therefore secure deployment practices for Django apply directly to Horizon. This guide provides a popular set of Django security recommendations, further information can be found by reading the Django deployment and security documentation.Horizon ships with reasonable default security settings, and has good deployment and configuration documentation.Basic Web Server ConfigurationHorizon should be deployed as a Web Services Gateway Interface (WSGI) application behind an HTTPS proxy such as Apache or nginx. If Apache is not already in use, we recommend nginx since it is lighter weight and easier to configure correctly.When using nginx, we recommend gunicorn as the wsgi host with an appropriate number of synchronous workers. We strongly advise against deployments using fastcgi, scgi, or uWSGI. We strongly advise against the use of synthetic performance benchmarks when choosing a wsgi server.When using Apache, we recommend mod_wsgi to host Horizon.HTTPSHorizon should be deployed behind a secure HTTPS server using 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.HTTP requests to the Horizon domain should be configured to redirect to the fully qualified HTTPS URL.HTTP Strict Transport Security (HSTS)It is highly recommended to use HTTP Strict Transport Security (HSTS).NOTE: If you are using an HTTPS proxy in front of your web server, rather than using an HTTP server with HTTPS functionality, follow the Django documentation on modifying the SECURE_PROXY_SSL_HEADER variable.See the chapter on PKI/SSL Everywhere for more specific recommendations and server configurations for HTTPS configurations, including the configuration of HSTS.Frontend CachingSince Horizon is rendering dynamic content passed directly from OpenStack API requests, we do not recommend frontend caching layers such as varnish. In Django, static media is directly served from Apache or nginx and already benefits from web host caching.Domain NamesMany organizations typically deploy web applications at subdomains of an overarching organization domain. It is natural for users to expect a domain of the form openstack.example.org. In this context, there are often many other applications deployed in the same second-level namespace, often serving user-controlled content. This name structure is convenient and simplifies nameserver maintenance.We strongly recommend deploying horizon to a second-level domain, for example https://example.com, and advise against deploying horizon on a shared subdomain of any level, for example https://openstack.example.org or https://horizon.openstack.example.org. We also advise against deploying to bare internal domains like https://horizon/.This recommendation is based on the limitations browser same-origin-policy. The recommendations in this guide cannot effectively protect users against known attacks if Horizon is deployed on a domain which also hosts user-generated content (e.g. scripts, images, uploads of any kind) even if the user-generated content is on a different subdomain. This approach is used by most major web presences (e.g. googleusercontent.com, fbcdn.com, github.io, twimg.com) to ensure that user generated content stays separate from cookies and security tokens.Additionally, if you decline to follow this recommendation above about second-level domains, it is vital that you avoid the cookie backed session store and employ HTTP Strict Transport Security (HSTS). When deployed on a subdomain, Horizon's security is only as strong as the weakest application deployed on the same second-level domain.Static MediaHorizon's static media should be deployed to a subdomain of the Horizon 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.Django media settings are documented at https://docs.djangoproject.com/en/1.5/ref/settings/#static-root.Horizon'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 Horizon, 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, we recommend disabling resource minification entirely. Online compression dependencies (less, nodejs) should not be installed on production machines.Secret KeyHorizon depends on a shared SECRET_KEY setting for some security functions. It should be a randomly generated string at least 64 characters long. It must be shared across all active Horizon instances. Compromise of this key may 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.Session BackendHorizon's default session backend (django.contrib.sessions.backends.signed_cookies) stores user data in signed but unencrypted cookies stored in the browser. This approach allows the most simple session backend scaling since each Horizon instance is stateless, but it comes at the cost of storing sensitive access tokens in the client browser and transmitting them with every request. This backend ensures that session data has not been tampered with, but the data itself is not encrypted other than the encryption provided by HTTPS.If your architecture allows it, we recommend using django.contrib.sessions.backends.cache as your session backend with memcache as the cache. Memcache must not be exposed publicly, and should communicate over a secured private channel. If you choose to use the signed cookies backend, refer to the Django documentation understand the security tradeoffs.For further details, consult the Django session backend documentation.Allowed HostsConfigure the ALLOWED_HOSTS setting with the domain or domains where Horizon is available. Failure to configure this setting (especially if not following the recommendation above regarding second level domains) opens Horizon to a number of serious attacks. Wildcard domains should be avoided.For further details, see the Django documentation on settings.CookiesSession Cookies should be set to HTTPONLY:
SESSION_COOKIE_HTTPONLY = TrueNever configure CSRF or session cookies to have a wildcard domain with a leading dot. Horizon's session and CSRF cookie should be secured when deployed with HTTPS:
Code CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = TruePassword Auto CompleteWe recommend that implementers do not change the default password autocomplete behavior. Users choose stronger passwords in environments that allow them to use the secure browser password manager. Organizations which forbid the browser password manager should enforce this policy at the desktop level.Cross Site Request Forgery (CSRF)Django has a dedicated middleware for cross-site request forgery (CSRF).Horizon is designed to discourage developers from introducing cross-site scripting vulnerabilities with custom dashboards. However, it is important to audit custom dashboards, especially ones that are javascript-heavy for inappropriate use of the @csrf_exempt decorator. Dashboards which do not follow these recommended security settings should be carefully evaluated before restrictions are relaxed.Cross Site Scripting (XSS)Unlike many similar systems, OpenStack Horizon allows the entire unicode character set in most fields. This means developers have less latitude to make escaping mistakes that open attack vectors for cross-site scripting (XSS).Horizon provides tools for developers to avoid creating XSS vulnerabilities, but they only work if developers use them correctly. Audit any custom dashboards, paying particular attention to use of the mark_safe function, use of is_safe with custom template tags, the safe template tag, anywhere autoescape is turned off, and any javascript which might evaluate improperly escaped data.Cross Origin Resource Sharing (CORS)Configure your web server to send a restrictive CORS header with each response, allowing only the Horizon domain and protocol:
Access-Control-Allow-Origin: https://example.com/Never allow the wildcard origin.Horizon Image UploadWe recommend that implementers disable HORIZON_IMAGES_ALLOW_UPLOAD unless they have implemented a plan to prevent resource exhaustion and denial of service.UpgradingDjango security releases are generally well tested and aggressively backwards compatible. In almost all cases, new major releases of Django are also fully backwards compatible with previous releases. Horizon implementers are strongly encouraged to run the latest stable release of Django with up-to-date security releases.DebugMake sure DEBUG is set to False in production. In Django, DEBUG displays stack traces and sensitive web server state information on any exception.