Files
jupyterhub/docs/source/security-basics.rst
2017-07-21 11:23:43 -07:00

177 lines
6.0 KiB
ReStructuredText

Security basics
===============
.. important::
You should not run JupyterHub without SSL encryption on a public network.
Security is the most important aspect of configuring Jupyter. Three
configuration settings and one best practice are the main aspects of security
configuration:
1. :ref:`SSL encryption <ssl-encryption>` (to enable HTTPS)
2. :ref:`Cookie secret <cookie-secret>` (a key for encrypting browser cookies)
3. Proxy :ref:`authentication token <authentication-token>` (used for the Hub and
other services to authenticate to the Proxy)
4. Periodic :ref:`security audits <security-audits>`
The Hub hashes all secrets (e.g., auth tokens) before storing them in its
database. A loss of control over read-access to the database should have no
security impact on your deployment.
.. _ssl-encryption:
Enabling SSL encryption
-----------------------
Since JupyterHub includes authentication and allows arbitrary code execution,
you should not run it without SSL (HTTPS).
Using an SSL certificate
~~~~~~~~~~~~~~~~~~~~~~~~
This will require you to obtain an official, trusted SSL certificate or create a
self-signed certificate. Once you have obtained and installed a key and
certificate you need to specify their locations in the configuration file as
follows:
.. code-block:: python
c.JupyterHub.ssl_key = '/path/to/my.key'
c.JupyterHub.ssl_cert = '/path/to/my.cert'
Some cert files also contain the key, in which case only the cert is needed. It
is important that these files be put in a secure location on your server, where
they are not readable by regular users.
If you are using a **chain certificate**, see also chained certificate for SSL
in the JupyterHub `troubleshooting FAQ <troubleshooting>`_.
Using letsencrypt
~~~~~~~~~~~~~~~~~
It is also possible to use `letsencrypt <https://letsencrypt.org/>`_ to obtain
a free, trusted SSL certificate. If you run letsencrypt using the default
options, the needed configuration is (replace ``mydomain.tld`` by your fully
qualified domain name):
.. code-block:: python
c.JupyterHub.ssl_key = '/etc/letsencrypt/live/{mydomain.tld}/privkey.pem'
c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/{mydomain.tld}/fullchain.pem'
If the fully qualified domain name (FQDN) is ``example.com``, the following
would be the needed configuration:
.. code-block:: python
c.JupyterHub.ssl_key = '/etc/letsencrypt/live/example.com/privkey.pem'
c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/example.com/fullchain.pem'
If SSL termination happens outside of the Hub
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In certain cases, e.g. behind `SSL termination in NGINX <https://www.nginx.com/resources/admin-guide/nginx-ssl-termination/>`_,
allowing no SSL running on the hub may be the desired configuration option.
.. _cookie-secret:
Cookie secret
-------------
The cookie secret is an encryption key, used to encrypt the browser cookies used
for authentication. If this value changes for the Hub, all single-user servers
must also be restarted.
Normally, this value is stored in a file, the location of which can be specified
in a config file as follows:
.. code-block:: python
c.JupyterHub.cookie_secret_file = '/srv/jupyterhub/cookie_secret'
The content of this file should be 32 random bytes, encoded as hex.
An example would be to generate this file with:
.. code-block:: bash
openssl rand -hex 32 > /srv/jupyterhub/cookie_secret
In most deployments of JupyterHub, you should point this to a secure location on
the file system, such as ``/srv/jupyterhub/cookie_secret``. If the cookie secret
file doesn't exist when the Hub starts, a new cookie secret is generated and
stored in the file. The file must not be readable by ``group`` or ``other`` or the
server won't start. The recommended permissions for the cookie secret file are
``600`` (owner-only rw).
If you would like to avoid the need for files, the value can be loaded in the
Hub process from the ``JPY_COOKIE_SECRET`` environment variable, which is a
hex-encoded string. You can set it this way:
.. code-block:: bash
export JPY_COOKIE_SECRET=`openssl rand -hex 32`
For security reasons, this environment variable should only be visible to the
Hub. If you set it dynamically as above, all users will be logged out each time
the Hub starts.
You can also set the cookie secret in the configuration file
itself, ``jupyterhub_config.py``, as a binary string:
.. code-block:: python
c.JupyterHub.cookie_secret = bytes.fromhex('64 CHAR HEX STRING')
.. _authentication-token:
Proxy authentication token
--------------------------
The Hub authenticates its requests to the Proxy using a secret token that
the Hub and Proxy agree upon. The value of this string should be a random
string (for example, generated by ``openssl rand -hex 32``). You can pass
this value to the Hub and Proxy using either the ``CONFIGPROXY_AUTH_TOKEN``
environment variable:
.. code-block:: bash
export CONFIGPROXY_AUTH_TOKEN=`openssl rand -hex 32`
This environment variable needs to be visible to the Hub and Proxy.
Or you can set the value in the configuration file, ``jupyterhub_config.py``:
.. code-block:: python
c.JupyterHub.proxy_auth_token = '0bc02bede919e99a26de1e2a7a5aadfaf6228de836ec39a05a6c6942831d8fe5'
If you don't set the Proxy authentication token, the Hub will generate a random
key itself, which means that any time you restart the Hub you **must also
restart the Proxy**. If the proxy is a subprocess of the Hub, this should happen
automatically (this is the default configuration).
Another time you must set the Proxy authentication token yourself is if
you want other services, such as `nbgrader <https://github.com/jupyter/nbgrader>`_,
to also be able to connect to the Proxy.
.. _security-audits:
Security audits
---------------
We recommend that you do periodic reviews of your deployment's security. It's
good practice to keep JupyterHub, configurable-http-proxy, and nodejs
versions up to date.
A handy website for testing your deployment is
`Qualsys' SSL analyzer tool <https://www.ssllabs.com/ssltest/analyze.html>`_.