researchcloud-items

Installation scripts for SURF ResearchCloud catalog components

View the Project on GitHub UtrechtUniversity/researchcloud-items

Role jupyterhub

back to index

Summary

Install JupyterHub on the workspace, by default with SRAM auth enabled.

Requires

Description

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:

Authentication and authorization

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.

Variables

Architecture

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

See also

History

2025 Written by Dawa Ometto (Utrecht University)

back to index