Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/singleuser-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@ jobs:
release-image-ide:
if: github.event.inputs.dockerfile_name == 'IDE.Dockerfile'
runs-on: ubuntu-latest
strategy:
matrix:
include:
- py_ver: '3.11'
- py_ver: '3.12'
env:
PYTHON_VERSION: '3.11'
PYTHON_VERSION: ${{matrix.py_ver}}
JUPYTERHUB_VERSION: ${{github.event.inputs.jupyterhub_version}}
DOCKERFILE_NAME: ${{github.event.inputs.dockerfile_name}}
IMAGE_SUFFIX: '-ide'
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Table of Contents
- [Introduction](#introduction)
- [Quick Start](#quick-start)
- [Hub configuration env vars](#hub-configuration-env-vars)
- [Build Jupyterhub Singleuser Image](#build-jupyterhub-singleuser-image)
- [Configuration](#configuration)
- [Build](#build)
Expand All @@ -24,6 +25,20 @@ Directory explain:
- `~/hub` is a Docker based jupyterhub host server using DockerSpawner and Docker-in-Docker to launch jupyterhub singleuser server as a Docker container, in order to locally validate the singleuser images for development purpose.(**Don't recommend to use this in production, due to the security concern of Docker-in-Docker**)


## Hub configuration env vars

The hub image (`hub/config/jupyterhub_config.py`) requires the following environment variables at startup:

| Env var | Description | Example |
|---------|-------------|---------|
| `OAUTH2_CLIENT_ID` | Keycloak client ID | `codebook` |
| `OAUTH2_CLIENT_SECRET` | Keycloak client secret | (secret) |
| `KEYCLOAK_HOST` | Keycloak hostname, no scheme | `keycloak.datajoint.com` |
| `OAUTH_CALLBACK_URL` | Fully-qualified OAuth callback URL | `https://codebook.datajoint.com/hub/oauth_callback` |

The container will fail to start if any of these are unset.


## Build Jupyterhub Singleuser Image

### Configuration
Expand Down
24 changes: 18 additions & 6 deletions hub/config/jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,24 @@ async def refresh_user(self, user, handler=None):
c.JupyterHub.ssl_key = '/etc/letsencrypt/live/fakeservices.datajoint.io/privkey.pem'
c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/fakeservices.datajoint.io/fullchain.pem'
c.JupyterHub.authenticator_class = RefreshingAuthenticator
c.GenericOAuthenticator.client_id = os.getenv("OAUTH2_CLIENT_ID")
c.GenericOAuthenticator.client_secret = os.getenv("OAUTH2_CLIENT_SECRET")
c.GenericOAuthenticator.oauth_callback_url = "https://127.0.0.1:8000/hub/oauth_callback"
c.GenericOAuthenticator.authorize_url = "https://keycloak-qa.datajoint.io/realms/datajoint/protocol/openid-connect/auth"
c.GenericOAuthenticator.token_url = "https://keycloak-qa.datajoint.io/realms/datajoint/protocol/openid-connect/token"
c.GenericOAuthenticator.userdata_url = "https://keycloak-qa.datajoint.io/realms/datajoint/protocol/openid-connect/userinfo"
c.GenericOAuthenticator.client_id = os.environ["OAUTH2_CLIENT_ID"]
c.GenericOAuthenticator.client_secret = os.environ["OAUTH2_CLIENT_SECRET"]

# Keycloak host and OAuth callback URL come from environment so the hub image
# is reusable across environments. Set KEYCLOAK_HOST to the keycloak hostname
# (e.g. "keycloak.datajoint.com"), no scheme. OAUTH_CALLBACK_URL must be a
# fully-qualified HTTPS URL.
#
# Known residual risks (not yet addressed): verify=False is still in effect
# on the OAuth callback (see TODO above), and jupyter_codeserver_proxy is on
# its 1.0b3 beta pin.
_keycloak_host = os.environ["KEYCLOAK_HOST"]
_realm_path = "realms/datajoint/protocol/openid-connect"
c.GenericOAuthenticator.oauth_callback_url = os.environ["OAUTH_CALLBACK_URL"]
c.GenericOAuthenticator.authorize_url = f"https://{_keycloak_host}/{_realm_path}/auth"
c.GenericOAuthenticator.token_url = f"https://{_keycloak_host}/{_realm_path}/token"
c.GenericOAuthenticator.userdata_url = f"https://{_keycloak_host}/{_realm_path}/userinfo"
c.GenericOAuthenticator.logout_redirect_url = f"https://{_keycloak_host}/{_realm_path}/logout"
c.GenericOAuthenticator.login_service = "Datajoint"
c.GenericOAuthenticator.username_claim = "preferred_username"
c.GenericOAuthenticator.enable_auth_state = True
Expand Down