Skip to content

CELINE Dashboards

This repository provides the CELINE Dashboards stack, a production‑ready analytics environment built around Apache Superset and Jupyter, secured through Keycloak and oauth2‑proxy, and fronted by Caddy.

The project is designed to deliver: - centralized SSO authentication, - consistent authorization across services, - Docker‑first local development and deployment, - extensible, auditable security logic aligned with the CELINE platform.


Overview

The stack exposes multiple web services (currently Superset and Jupyter) behind a single authentication boundary. Authentication is fully delegated to Keycloak via oauth2‑proxy, while each application consumes identity and authorization data from trusted headers or JWTs.

Key goals: - No local passwords in Superset or Jupyter - Automatic user provisioning - Role and group synchronization from Keycloak - Support for browser users and service / CLI tokens


Architecture

All services are fronted by Caddy, which delegates authentication to oauth2-proxy. oauth2-proxy validates sessions against Keycloak (OIDC). Authenticated requests are forwarded by Caddy to Superset or Jupyter, which each enforce authorization locally.

Component Role
Caddy Reverse proxy, TLS termination, forward_auth to oauth2-proxy
oauth2-proxy OIDC authentication gateway, injects identity headers
Keycloak Identity provider, group and role management
Superset Analytics dashboards, custom SecurityManager
Jupyter Notebook execution, JWT-based authorizer

Authentication and authorization flow:

  1. User accesses a protected service (Superset or Jupyter).
  2. Caddy delegates authentication to oauth2‑proxy (forward_auth).
  3. oauth2‑proxy authenticates the user via Keycloak (OIDC).
  4. Identity headers and access tokens are forwarded back to Caddy.
  5. Requests are proxied to the target service.
  6. Each service validates and enforces authorization locally:
  7. Superset via a custom SecurityManager
  8. Jupyter via a JWT‑based authorizer

Repository Structure

.
├── config/
│   ├── caddy/              # Reverse proxy configuration
│   ├── oauth2-proxy/       # oauth2-proxy configuration
│   ├── superset/           # Superset configuration and env files
│   └── jupyter/            # Jupyter server configuration
│
├── packages/
│   ├── celine-superset/    # celine.superset — Superset SSO plugin and management CLI (own src/, tests/)
│   └── celine-jupyter/     # celine.jupyter — Jupyter JWT authorizer (own src/, tests/)
├── pyproject.toml          # uv workspace root (members: packages/*), not a package
│
├── Dockerfile              # Superset image
├── Dockerfile.jupyter      # Jupyter image
├── docker-compose.yaml     # Full local stack
├── version.txt             # Superset image version
├── version.jupyter.txt     # Jupyter image version
├── taskfile.yaml           # Common developer tasks
└── README.md

Services

Superset

  • Authentication type: AUTH_REMOTE_USER
  • Login and logout fully delegated to oauth2‑proxy
  • Custom OAuth2ProxySecurityManager:
  • validates JWT signatures via Keycloak JWKS
  • auto‑creates users on first login
  • synchronizes roles on each login
  • maps the Keycloak realm role platform-admin and organisation groups to Superset roles

The mapping is defined in packages/celine-superset/src/celine/superset/auth/groups.py. There are exactly two levels:

Token claim Superset role
realm role platform-admin (realm_access.roles) Admin
organization.<slug>.groups: admins, managers, editors org:<slug>:<level>
organization.<slug>.groups: viewers, any other group, or membership alone org:<slug>:viewers

Realm groups (the top-level groups claim, e.g. /admins) and every other realm role grant nothing. An organisation's admins is that organisation's admin only.

Jupyter

  • No server token, password or login page: only an access token opens it
  • Runs as jupyter celine-server, Jupyter Server with the CELINE identity provider and authorizer built in
  • Trusts one issuer, CELINE_JUPYTER_JWT_ISSUER (the realm URL); tokens of any other issuer are refused before any key is fetched
  • Fails closed: it does not start when that issuer is unset, when the authentication cannot be loaded, or when configuration replaces it or re-opens unauthenticated access
  • Intended for notebook execution under the same SSO boundary

Only holders of the Keycloak realm role platform-admin get access (all or nothing). An organisation's admins group and a realm group such as /admins grant nothing.


Authentication & Identity

Keycloak

The realm is not defined here: celine-policies reconciles it. This stack consumes:

  • Realm: celine
  • Clients:
  • oauth2_proxy (browser SSO); its access token must carry realm_access.roles (the roles client scope) and organization (request organization:*)
  • celine-cli (service and CLI tokens)
  • Platform administrators: the realm role platform-admin
  • Organisation roles: each organisation's admins, managers, editors, viewers groups

oauth2‑proxy

oauth2‑proxy acts as the single authentication gateway:

  • Handles browser login flows
  • Injects identity headers and access tokens
  • Supports service tokens via skip_jwt_bearer_tokens
  • Shares cookies across *.celine.localhost

It is exposed through a dedicated SSO endpoint:

http://sso.celine.localhost

Documentation

Document Description
Architecture Service flow, auth chain, identity propagation
Authentication Keycloak realm, oauth2-proxy setup, JWT validation, cookie sharing
Services Superset SecurityManager, Jupyter JWT authorizer, Caddy config
Development task ensure-env, docker compose, service URLs, extensibility

Local Development

Prerequisites

  • Docker
  • Docker Compose
  • Task (https://taskfile.dev)

Setup

  1. Clone the repository
git clone https://github.com/celine-eu/celine-dashboards.git
cd celine-dashboards
  1. Initialize environment files
task ensure-env
  1. Start the full stack
docker compose up -d
  1. Access services

  2. Superset: http://superset.celine.localhost

  3. Jupyter: http://jupyter.celine.localhost
  4. SSO / oauth2‑proxy: http://sso.celine.localhost
  5. Keycloak: http://keycloak.celine.localhost

Docker Images & CI

Docker images are built and published automatically via GitHub Actions.

Superset

ghcr.io/celine-eu/superset:<version>
ghcr.io/celine-eu/superset:latest

The version is defined in version.txt.

Jupyter

ghcr.io/celine-eu/jupyter:<version>
ghcr.io/celine-eu/jupyter:latest

The version is defined in version.jupyter.txt.

Images are rebuilt automatically when relevant source or configuration files change.


Extensibility

This repository is intentionally structured to allow:

  • swapping or extending identity providers,
  • customizing JWT claim formats,
  • adding new services behind the same SSO boundary,
  • refining role‑based access control logic.

Authentication logic is isolated in reusable Python packages and kept stateless.


Contributing

Contributions are welcome.

Guidelines: - Keep authentication logic stateless and defensive - Do not introduce local login mechanisms - Ensure JWT validation remains explicit and verifiable - Add tests for any auth‑related changes


License

Copyright © 2025 Spindox Labs

Licensed under the Apache License, Version 2.0.
You may not use this file except in compliance with the License.

See http://www.apache.org/licenses/LICENSE-2.0 for details.