PT EN
Back to site

Notebook (Jupyter) — Administrator Guide

Giving analysts Python used to mean installing local environments, handing out credentials by e-mail and losing track of where the data ends up. With DATTA's Notebook environment, each analyst gets a full Jupyter inside the platform itself — same identity, same look, ready access to the data sources — while you keep credentials and isolation under central control. This guide covers how to enable the environment, the credential security model and how to diagnose the most common problems.

Audience: administration and operations. For analyst-facing notebook usage, see the Notebook Guide and the


What the analyst gets

  • A full Jupyter Lab (notebook + terminal), reachable at InvestigaçãoNotebook, with no local installation.
  • An individual, isolated environment per user, created on demand by JupyterHub.
  • Ready-made connectors to the platform's sources — Neo4j, OpenSearch, Trino, the platform cache, MinIO and Spark Connect — with the data credentials already injected into the environment.
  • A single identity: there is no separate login. Whoever is authenticated in DATTA enters the Notebook automatically.

How the identity travels

The Notebook portal asks the platform for an HttpOnly session cookie (datta_jwt), scoped to the /jupyter path. The JupyterHub authenticator validates that token (HS256, HS384 or HS512), requires the ANALISTA or ADMIN role and creates the hub user from the normalized e-mail — @ and . become -. The endpoint that issues this cookie is described in the API reference.

Traffic to /jupyter/ goes straight to the public JupyterHub proxy on port 8000; it does not pass through the platform's entry proxy, which keeps an equivalent route only as an internal fallback. Mind the correct internal address: it is jupyterhub-proxy-public:8000 — there is no address named just jupyterhub. The JUPYTER_URL configuration variable and the default used by the Copilot both point to the public proxy.


How to enable it in production

1. Individual environment image

The jupyter-datta image is built from docker/jupyter-datta/ (base quay.io/jupyter/minimal-notebook, plus the Neo4j, OpenSearch, Trino, platform cache and MinIO drivers, Spark Connect and the DATTA theme). It is identified by the last commit that changed that folder (7-character short SHA), decoupled from the Java release SHA: a release that does not touch the Notebook neither rebuilds the image nor swaps it under environments already open, and git show <tag> shows exactly what is running.

You do not compute or pin that tag by hand. The installer and the release script derive the tag, build and publish the image only when it is not yet in the registry (the build takes ~10 min and 3 GB) and hand the tag to the chart (jupyter.singleuser.image.tag) on every deployment. To build or rebuild outside a release:

bash
./scripts/datta-build-jupyter.sh            # tag derived from git
./scripts/datta-build-jupyter.sh --force    # rebuild even if it exists

Called from outside the server with the on-prem registry, the script builds on the server, from the commit published on GitHub — the registry only accepts connections from inside the cluster, and the commit must be published.

The image goes through a vulnerability scan before it is published; a HIGH/CRITICAL finding with a fix available blocks the push. Never use a floating latest.

The notebook's Spark is client only: the image ships the Spark Connect client 4.2.0, without the bundled Java distribution. Two practical consequences:

  • the version must match the Spark Connect server (k8s/jupyter/spark-connect.yml) — client and server speak the same protocol within a major line, so moving one without the other would break the sc:// connection;
  • there is no local Spark inside the notebook: a session created with master("local") no longer exists. The path is datta_clients.spark, which connects to the server. This removes 2 GB of Java libraries that shipped with critical flaws impossible to fix on their own — they travel inside the Spark package, and it is the package that is gone.

With jupyter.prepull.enabled: true (the installation default), every machine in the cluster downloads the image right after deployment. Without it, the first Notebook opening on each machine pays the whole download inside the environment start timeout — the screen sits in "Starting…" for minutes or fails.

2. Installation configuration

values-onprem-local.yaml ships jupyter.enabled: true. The credentials (jupyter.serviceToken, the MinIO keys and the remaining secrets) come from the .env file — or from the current release, as a fallback — and are injected by the release script.

3. Deployment

Run ./scripts/datta-release.sh (uniform release). It brings up the hub, the proxy, the internal addresses, the dedicated jupyter-user-secrets store and the /jupyter/ routing rule.


Credential security model

The Notebook environment runs arbitrary analyst code. That is why it receives credentials from a dedicated store (jupyter-user-secrets), never the platform's entire secret store (datta-secrets).

The dedicated store holds only the "Data + MinIO" scope, and every value belongs to a dedicated least-privilege user (2026-09-04 audit):

  • NEO4J_PASSWORD — for the jupyter_reader user (reader role: read-only on every database), created by the Neo4j init job. Never the neo4j superuser password.
  • MINIO_ACCESS_KEY = jupyter and MINIO_SECRET_KEY — a user bound to the datta-jupyter policy: read on the warehouse and documents buckets, read and write only on the staging bucket. Never the root keys.
  • OpenSearch: no credential while the security plugin is disabled; once it is enabled, a read-only user goes here as OPENSEARCH_PASSWORD.

Both passwords are generated and preserved in the platform store (JUPYTER_NEO4J_PASSWORD, JUPYTER_MINIO_PASSWORD) and reach the notebook environment by reference to those two specific keys, never to the whole store. The dedicated store now holds only the MinIO user name.

Why this matters: the platform store carries JWT_SECRET, DATTA_VAULT_MASTER_KEY, GEMINI_API_KEY, DATTA_INTERNAL_TOKEN, ADMIN_DEFAULT_PASSWORD and others. An analyst could read any of them with an os.environ from inside a cell — exposing the whole store would leak the platform's secrets.

Two decisions complete the isolation:

  • A narrow store injected as a block, not key by key. The environment spawner cannot merge environment variable lists: a per-key reference would wipe the variable list the spawner itself defines. Hence a narrow store, injected whole.
  • No infrastructure token. The individual environment starts without automatically mounting the cluster's service-account token — from inside the notebook there is no infrastructure administration credential.

Copilot creates notebooks (optional feature)

The chat Copilot can create ready-made .dattanb notebooks in the user's environment, using Jupyter's Contents API. This requires a JupyterHub service token, registered in the hub with the access:servers scope — a DATTA token is not a valid JupyterHub token.

  • The token comes from JUPYTER_SERVICE_TOKEN, generated by setup-datta.sh and persisted in .env.
  • Without it, the hub does not register the service and notebook creation by the Copilot is disabled with a friendly notice — everything else in the Notebook works normally.
  • The release script preserves jupyter.serviceToken across releases, so the enablement is not lost on every deployment.

Quick diagnosis

SymptomLikely causeAction
"Notebook indisponível" (error state, with the HTTP code when available)the hub did not answer — it may be restarting or have jupyter.enabled=false; from the browser the two causes are indistinguishableWait a few seconds and reload the page (F5); if it persists, confirm jupyter.enabled: true in the installation configuration and check the hub's health from the platform console
"Checking…" that never endsAlready fixed: the screen had exits without a state (missing session, profile without access, cookie refused, silent hub) and no timeoutsThe screen is a state machine: every check has a timeout and every exit paints the bar (unavailable, no session, no permission, stopped, starting with a percentage, active, error with "Try again"); force an asset reload in the browser
Empty iframe / "refused to connect"frame-ancestors policy from the hub or from the individual environmentAlready handled: the hub and the spawner arguments set frame-ancestors 'self'
Permission error on /home/jovyanThe home directory volume is created owned by rootAlready handled: an initialization step adjusts ownership to the notebook user, and it ships with the installation
Copilot does not create notebooksJUPYTER_SERVICE_TOKEN missingSet it in .env and redeploy — optional feature, the Notebook keeps working without it
Notebook cannot connect to Neo4j/OpenSearch/MinIOCredential missing from the dedicated storeCheck that jupyter-user-secrets holds the four data keys
"Starting…" for minutes on the first openingThe image (~3 GB) was not on the machine yetEnable jupyter.prepull.enabled (installation default) — warming happens right after deployment, not on the first click
Environment does not start and the hub logs image not foundThe image tag handed to the chart does not exist in the registryRun ./scripts/datta-build-jupyter.sh (builds and publishes the git-derived tag) and redeploy

To tell at which gate access stops (hub, cookie issuance, cookie accepted by the hub, environment creation), follow the Notebook — E0 diagnosis runbook, which lists the four calls in order.


Learn more

  • Notebook Guide — analyst-facing notebook usage. creation.
  • Roles and permissions — where the ANALISTA and ADMIN roles come from.