68cb85d89e
made change to Horizon dashboard description in beginning of xml file removing extra white space Change-Id: I8a776010c06e0af99b2317475823355a3c6a4f18
259 lines
14 KiB
XML
259 lines
14 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<chapter xmlns:xi="http://www.w3.org/2001/XInclude"
|
||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||
xmlns="http://docbook.org/ns/docbook"
|
||
xmlns:db="http://docbook.org/ns/docbook" version="5.0"
|
||
xml:id="ch025_web-dashboard">
|
||
<?dbhtml stop-chunking?>
|
||
<title>Dashboard</title>
|
||
<para>Horizon is the OpenStack dashboard that provides users a self-service
|
||
portal to provision their own resources within the limits set by
|
||
administrators. 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.</para>
|
||
<para>The dashboard 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
|
||
<link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/#security"
|
||
>Django deployment and security documentation</link>.</para>
|
||
<para>The dashboard ships with reasonable default security settings,
|
||
and has good <link
|
||
xlink:href="http://docs.openstack.org/developer/horizon/topics/deployment.html"
|
||
>deployment and configuration documentation</link>.</para>
|
||
<section xml:id="ch025_web-dashboard-idp237648">
|
||
<title>Basic Web Server Configuration</title>
|
||
<para>The dashboard 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.</para>
|
||
<para>When using nginx, we recommend <link
|
||
xlink:href="http://docs.gunicorn.org/en/latest/deploy.html"
|
||
>gunicorn</link> 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.</para>
|
||
<para>When using Apache, we recommend <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/howto/deployment/wsgi/modwsgi/"
|
||
>mod_wsgi</link> to host dashboard.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp240704">
|
||
<title>HTTPS</title>
|
||
<para>The dashboard 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.</para>
|
||
<para>HTTP requests to the dashboard domain should be configured
|
||
to redirect to the fully qualified HTTPS URL.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp242624">
|
||
<title>HTTP Strict Transport Security (HSTS)</title>
|
||
<para>It is highly recommended to use HTTP Strict Transport
|
||
Security (HSTS).</para>
|
||
<para>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 <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#secure-proxy-ssl-header"
|
||
>Django documentation on modifying the SECURE_PROXY_SSL_HEADER
|
||
variable</link>.</para>
|
||
<para>See the chapter on PKI/SSL Everywhere for more specific
|
||
recommendations and server configurations for HTTPS
|
||
configurations, including the configuration of HSTS.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp245456">
|
||
<title>Front end Caching</title>
|
||
<para>Since dashboard is rendering dynamic content passed directly
|
||
from OpenStack API requests, we do not recommend front end
|
||
caching layers such as varnish. In Django, static media is
|
||
directly served from Apache or nginx and already benefits from
|
||
web host caching.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp246880">
|
||
<title>Domain Names</title>
|
||
<para>Many organizations typically deploy web applications at
|
||
subdomains of an overarching organization domain. It is natural
|
||
for users to expect a domain of the form
|
||
<uri>openstack.example.org</uri>. 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 name server
|
||
maintenance.</para>
|
||
<para>We strongly recommend deploying horizon to a
|
||
<emphasis>second-level domain</emphasis>, such as
|
||
<uri>https://example.com</uri>, and advise against deploying
|
||
horizon on a <emphasis>shared subdomain</emphasis> of any level,
|
||
for example <uri>https://openstack.example.org</uri> or
|
||
<uri>https://horizon.openstack.example.org</uri>. We also
|
||
advise against deploying to bare internal domains like
|
||
<uri>https://horizon/</uri>.</para>
|
||
<para>This recommendation is based on the limitations browser
|
||
same-origin-policy. The recommendations in this guide cannot
|
||
effectively protect users against known attacks if dashboard is
|
||
deployed on a domain which also hosts user-generated content,
|
||
such as scripts, images, or uploads of any kind, even if the
|
||
user-generated content is on a different subdomain. This
|
||
approach is used by most major web presences, such as
|
||
googleusercontent.com, fbcdn.com, github.io, and twimg.com, to
|
||
ensure that user generated content stays separate from cookies
|
||
and security tokens.</para>
|
||
<para>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, dashboard's
|
||
security is only as strong as the weakest application deployed
|
||
on the same second-level domain.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp251760">
|
||
<title>Static Media</title>
|
||
<para>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.</para>
|
||
<para>Django media settings are documented at <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#static-root"
|
||
>https://docs.djangoproject.com/en/1.5/ref/settings/#static-root</link>.</para>
|
||
<para>Dashboard's default configuration uses <link
|
||
xlink:href="http://django-compressor.readthedocs.org/"
|
||
>django_compressor</link> to compress and minify css and
|
||
JavaScript content before serving it. This process should be
|
||
statically done before deploying 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, we recommend disabling
|
||
resource compression entirely. Online compression dependencies
|
||
(less, nodejs) should not be installed on production
|
||
machines.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp255696">
|
||
<title>Secret Key</title>
|
||
<para>Dashboard 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.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp257248">
|
||
<title>Session Backend</title>
|
||
<para>Horizon's default session backend
|
||
(<emphasis>django.contrib.sessions.backends.signed_cookies</emphasis>)
|
||
stores user data in <emphasis>signed</emphasis> but
|
||
<emphasis>unencrypted </emphasis>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 <emphasis>storing sensitive access tokens in the
|
||
client browser</emphasis> 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.</para>
|
||
<para>If your architecture allows it, we recommend using
|
||
<emphasis>django.contrib.sessions.backends.cache</emphasis> 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 trade-offs.</para>
|
||
<para>For further details, consult the <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/topics/http/sessions/#configuring-the-session-engine"
|
||
>Django session backend documentation</link>.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp262288">
|
||
<title>Allowed Hosts</title>
|
||
<para>Configure 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. Wild card domains should be avoided.</para>
|
||
<para>For further details, see the <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts"
|
||
>Django documentation on settings</link>.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp264272">
|
||
<title>Cookies</title>
|
||
<para>Session Cookies should be set to HTTPONLY:</para>
|
||
<screen>
|
||
SESSION_COOKIE_HTTPONLY = True</screen>
|
||
<para>Never configure CSRF or session cookies to have a wild card
|
||
domain with a leading dot. Horizon's session and CSRF cookie
|
||
should be secured when deployed with HTTPS:</para>
|
||
<screen>
|
||
Code CSRF_COOKIE_SECURE = True
|
||
SESSION_COOKIE_SECURE = True</screen>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp266976">
|
||
<title>Password Auto Complete</title>
|
||
<para>We recommend that implementers do not change the default
|
||
password auto complete 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.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp268448">
|
||
<title>Cross Site Request Forgery (CSRF)</title>
|
||
<para>Django has a dedicated middleware for <link
|
||
xlink:href="https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#how-it-works"
|
||
>cross-site request forgery</link> (CSRF).</para>
|
||
<para>Dashboard 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.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp270608">
|
||
<title>Cross Site Scripting (XSS)</title>
|
||
<para>Unlike many similar systems, OpenStack dashboard 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).</para>
|
||
<para>Dashboard 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 auto escape
|
||
is turned off, and any JavaScript which might evaluate
|
||
improperly escaped data.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp272832">
|
||
<title>Cross Origin Resource Sharing (CORS)</title>
|
||
<para>Configure your web server to send a restrictive CORS header
|
||
with each response, allowing only the Horizon domain and
|
||
protocol:</para>
|
||
<screen>
|
||
Access-Control-Allow-Origin: https://example.com/</screen>
|
||
<para>Never allow the wild card origin.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp275056">
|
||
<title>Horizon Image Upload</title>
|
||
<para>We recommend that implementers <link
|
||
xlink:href="http://docs.openstack.org/developer/horizon/topics/deployment.html#file-uploads"
|
||
>disable HORIZON_IMAGES_ALLOW_UPLOAD</link> unless they have
|
||
implemented a plan to prevent resource exhaustion and denial of
|
||
service.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp276864">
|
||
<title>Upgrading</title>
|
||
<para>Django 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. Dashboard implementers are strongly
|
||
encouraged to run the latest stable release of Django with
|
||
up-to-date security releases.</para>
|
||
</section>
|
||
<section xml:id="ch025_web-dashboard-idp278672">
|
||
<title>Debug</title>
|
||
<para>Make sure DEBUG is set to False in production. In Django,
|
||
DEBUG displays stack traces and sensitive web server state
|
||
information on any exception.</para>
|
||
</section>
|
||
</chapter>
|