Installation scripts for SURF ResearchCloud catalog components
View the Project on GitHub UtrechtUniversity/researchcloud-items
Install JupyterHub on the workspace, by default with SRAM auth enabled.
This role installs the JupyterHub webapplication.
The role will set certain facts that can be used by other roles to know where JupyterHub is installed:
jupyterhub_venv_path. String. Path of the virtual environment containing JupyterHub.jupyterhub_config_dir_path. String. Path to the directory containing the main configuration files (see jupyterhub_config_dir below).This role utilizes the nginx_reverse_proxy to activate support for Single Sing-on using SRAM (via the jhub_remote_user_authenticator plugin). If SRAM auth is enabled, extra Python code is added to the JupyterHub config file to enable use of jhub_remote_user_authenticator.
SRAM authentication is default, but can also be disabled. Other options include no authentication, or http basic auth.
JupyterHub’s sudospawner is used to run notebooks as specific users: when you login with user foo (usin e.g. SRAM), the hub (which runs as a dedicated service user itself) will use special sudo permissions to spawn a notebook server running as user foo on the workspace. Only users in the group specified by jupyterhub_allowed_users_group variable are allowed to spawn in this way.
Security Note: by default we ensure that JupyterHub listens on a Unix socket, instead of the default TCP port (8000). This is to prevent users with shell access from easily bypass authentication (by curl’ing localhost:8000 and setting the REMOTE_USER header, which is normally set by SRAM). See Architecture below.
jupyterhub_port: Int. Port on which the hub will listen. Default: 8000.jupyterhub_uri: String. Base URL under which the Hub will be served. Default: /.jupyterhub_auth: String. Should be one of sram, basic, or noauth. See the nginx location role. Default: sram.jupyterhub_bind_addr: String. IP address/host on which the hub will be listening. Default: 127.0.0.1.jupyterhub_extra_pkgs: List. Extra pypi packages that will be installed in jupyterhub’s venv in addition the required base packages. Default: [].jupyterhub_config_dir: String. Path where the configuration files should be stored. Default: /usr/local/etc/jupyterhub.jupyterhub_config_extra: String. Extra python code that will be inserted in the JupyterHub config file. The config object is called c. See the JupyterHub docs. Default: "".jupyterhub_allowed_users_group: String. Name of the group, users in which will be able to use jupyterhub.jupyterhub_enable_notebooks: Boolean. Whether to actually enable the use of notebooks. This can be disabled for non-standard use of JupyterHub, e.g. with the standalone proxy. Default: true.jupyterhub_config_env_keep: List of environment variables, the values of which will be passed along to each spawned webapplication. Default: ['JUPYTERHUB_ACTIVITY_URL', 'JUPYTERHUB_SERVER_NAME', 'JUPYTERHUB_API_URL', 'JUPYTERHUB_API_TOKEN', 'JUPYTERHUB_SERVICE_URL', 'JUPYTERHUB_SINGLEUSER_APP', 'JUPYTERHUB_USER', 'JUPYTERHUB_GROUP', 'PYTHONPATH', 'PATH', 'CONDA_ROOT', 'CONDA_DEFAULT_ENV].jupyterhub_proxy_config: Dict. Settings that will be passed on to the nginx_reverse_proxy role. Will be merged with the default proxy settings, so this variable allows you to override settings. See the proxy role for what the dict should look like. Default: {}.jupyterhub_http_username: String. HTTP username to use when setting jupyterhub_auth to basic. Default: "".jupyterhub_http_password: String. Default: "".jupyterhub_create_default_group: Boolean. Whether the group specified by jupyterhub_allowed_users_group should be created as a default group for all users. Default: true.jupyterhub_remote_user_header: String. Which HTTP header should be used to get the username from, when using remote user auth (SRAM). Default: REMOTE_USER.jupyterhub_activate_remote_user_auth: Boolean. Whether to enable remote user auth in the JupyterHub config. You can set this to true in order to test remote auth without actually having SRAM or another external auth provider, e.g. in CI. Default: false.jupyterhub_enable_unix_socket: Boolean. Whether all Hub elements should listen on Unix sockets (more secure) instead of TCP ports. See the Security Note above, and the Architecture section below. Default: true.By default we ensure that all JupyterHub components (the Hub proper, ConfigurableHTTPProxy and its API) listen on a Unix socket, instead of the default TCP port (8000). This is to prevent users with shell access from easily bypass authentication (by curl’ing localhost:8000 and setting the REMOTE_USER header, which is normally set by SRAM). The diagram below illustrates the architecture, and the way in which it remedies the kind of attack in question.
graph TD
subgraph Server Side
B(Nginx) -->|Sets REMOTE_USER header to alice<br/>Communicates via UDS| D(ConfigurableHTTPProxy)
D(ConfigurableHTTPProxy) <-->|Communicates via UDS| E(JupyterHub)
E(JupyterHub) -->|Spawns as user alice<br/>Provides API token| F(Single-User Notebook Server) -->|API requests to /hub/<br/>with API token|G
D -->|Proxies requests to| F
G(Nginx listening on UDS) -->|Proxies requests to<br/>|E
end
subgraph User Side
A(User Alice) -->|Connects with token| B(Nginx)
end
subgraph Authentication Server
A(User Alice) -->|Logs in| C(Authentication Server)
C-->|Provides token| A
B -->|Validates token| C(Authentication Server)
end
subgraph Impersonation Attempt
H(Impersonator Bob) -.->|Attempt to connect with `REMOTE_USER: alice`<br/>Blocked by UDS Permissions| D(ConfigurableHTTPProxy)
end
2025 Written by Dawa Ometto (Utrecht University)