Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable token auth for Jupyter notebooks [MD-404] #9452

Merged
merged 2 commits into from
Jun 20, 2024

Conversation

azhou-determined
Copy link
Contributor

@azhou-determined azhou-determined commented May 30, 2024

Ticket

Description

Enables access to a remote Jupyter server running as a Determined task outside Determined (use case here is to support VSCode integrations).

Jupyter in VSCode requires an access token, so this change modifies Determined auth logic to accept a token parameter in the proxy URLs.

Test Plan

Testing this requires VSCode with the Jupyter extension installed.

  • Launch a Jupyter notebook through the CLI:
    det notebook start
  • After the notebook starts up, it should print a URL for connecting to the running remote Jupyter server:
  • Copy this URL, go to VSCode
  • Create a new Jupyter notebook in VSCode
    image
  • In VSCode, click on "Select Kernel" -> "Select another kernel" -> "Existing Jupyter server"
  • You should see a prompt to enter the URL of a remote Jupyter server
  • Paste the URL from det notebook start into the prompt, it should contain a ?token= parameter.
  • Run some commands in the local notebook shell. Verify that VSCode is able to connect to the Determined Jupyter instance.

Checklist

  • Changes have been manually QA'd
  • User-facing API changes need the "User-facing API Change" label.
  • Release notes should be added as a separate file under docs/release-notes/.
    See Release Note for details.
  • Licenses should be included for new code which was copied and/or modified from any external code.

Copy link

netlify bot commented May 30, 2024

Deploy Preview for determined-ui canceled.

Name Link
🔨 Latest commit 3adaed5
🔍 Latest deploy log https://app.netlify.com/sites/determined-ui/deploys/667378c6cd8f440008bb3015

Copy link

codecov bot commented May 30, 2024

Codecov Report

Attention: Patch coverage is 2.58621% with 113 lines in your changes missing coverage. Please review.

Project coverage is 49.85%. Comparing base (ea929fc) to head (3adaed5).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9452      +/-   ##
==========================================
- Coverage   49.90%   49.85%   -0.06%     
==========================================
  Files        1245     1246       +1     
  Lines      161903   162007     +104     
  Branches     2887     2886       -1     
==========================================
- Hits        80795    80763      -32     
- Misses      80937    81073     +136     
  Partials      171      171              
Flag Coverage Δ
backend 43.88% <2.63%> (-0.15%) ⬇️
harness 63.81% <0.00%> (-0.01%) ⬇️
web 46.24% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
master/pkg/tasks/task_command.go 0.00% <ø> (ø)
harness/determined/cli/notebook.py 28.26% <0.00%> (-0.63%) ⬇️
master/internal/api_notebook.go 32.38% <0.00%> (+0.15%) ⬆️
master/internal/command/command.go 66.94% <42.85%> (-0.88%) ⬇️
master/internal/user/service.go 48.23% <0.00%> (-3.50%) ⬇️
master/internal/api_auth.go 41.60% <0.00%> (-7.00%) ⬇️
master/internal/db/postgres_notebook_sessions.go 0.00% <0.00%> (ø)
master/internal/command/command_service.go 63.20% <0.00%> (-11.24%) ⬇️

... and 7 files with indirect coverage changes

allo := c.refreshAllocationState()
notebookAddress := fmt.Sprintf("%s?token=%s", c.serviceAddress(), c.Base.UserSessionToken)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little worried about returning user tokens in /api/v1/notebooks for security reasons

is there a way around this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have to give the plain text link with the token to the user, so they could copy-paste it into their vscode, right? so probably no way to avoid sending these secrets over the wire.

we could maybe send the base URL and the token separately, so at least the automated URL scanners could not catch it. but that is security by obscurity.

Copy link
Contributor

@NicholasBlaskey NicholasBlaskey May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my issue is we are exposing Determined users tokens to other users. An non admin could snag an admins token from the api and just start making calls as that user. Or you could impersonate another user.

I have mentioned at least part of this in a DM but an alternative that doesn't expose more access into the system is

  1. Notebooks links in the API stay the same. When connecting from the CLI we add ?token=... to the link we print. This token comes from being logged into the CLI or webui.

  2. The proxy authenticates the request based on ?token if present.

  3. If vscode needs the notebook to be authenticated the proxy can add another layer of auth between itself and the notebook. This is optional to me since we don't assume this connection is authed today. But I don't think the notebook could use the CLI/webui token? as the token it expects because multiple tokens should be valid to access the notebook. Maybe you could rewrite token to a per Notebook credential.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, good point.

@azhou-determined azhou-determined force-pushed the vscode-notebooks branch 2 times, most recently from bbc95df to db62b72 Compare June 18, 2024 16:43
Copy link
Contributor

@NicholasBlaskey NicholasBlaskey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm


if _, err := Bun().NewInsert().Model(notebookSession).
Returning("id").Exec(ctx, &notebookSession.ID); err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: wrap these errors

@@ -131,6 +131,59 @@ func (cs *CommandService) LaunchGenericCommand(
return cmd, nil
}

// LaunchNotebookCommand creates notebook commands and persists them to the database.
func (cs *CommandService) LaunchNotebookCommand(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little worried about this logic diverging from the generic one LaunchGenericCommand

can we instead have LaunchGenericCommand check task type and only create a notebook session if task type is notebook?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i didn't want this either, but it's hard to isolate, since the notebook launch takes in a session parameter and also sprinkles in additional calls throughout the method.

// in two places:
// 1. A token query parameter in the request URL.
// 2. An HTTP Authorization header with a "token" type.
func extractNotebookTokenFromRequest(r *http.Request) (string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this doesn't need to return an error?

@azhou-determined azhou-determined merged commit 553521e into main Jun 20, 2024
83 of 98 checks passed
@azhou-determined azhou-determined deleted the vscode-notebooks branch June 20, 2024 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants