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

Local Companion (alpha) #3958

Merged
merged 11 commits into from
Apr 22, 2021
Merged

Local Companion (alpha) #3958

merged 11 commits into from
Apr 22, 2021

Conversation

csweichel
Copy link
Contributor

@csweichel csweichel commented Apr 15, 2021

Disclaimer

This a very first step and not at all indicative of UX, functionality or purpose. Here be dragons.


This PR adds the first spike towards a local Gitpod companion app. In this iteration the app can:

  • authenticate itself against Gitpod (caveats apply - see Next Steps) and store the token in the machine's keyring
  • listen for new workspaces
  • for each workspace, connect to supervisor using chisel running in the workspace, authenticated using the owner token
  • upload the local ~/.ssh/id_rsa.pub to the workspace's ~/.ssh/authorized_keys to facilitate SSH authentication
  • establish and maintain an SSH tunnel to each workspace
  • maintain an OpenSSH compatible ssh_config file for use with ssh and VS Code that maps workspace IDs to ports

Below is a quick demo of those features:

To make all of this happen, this PR

  • introduces a local app which at this point is a bare-minimum CLI written in Go. This is meant as a starting point towards building this out to a sensible and easy to use local companion. The local app is shipped as a Docker installer image.
  • extends server to support an OAuth like login flow for the local app. The local app spawns a webserver on localhost:<free-port>, opens a browser to $GITPOD_HOST/api/auth/local-app?returnTo=localhost:<free-port>. Gitpod, if the user is logged in, redirects to the returnTo URL passing an OTS URL from which the local app downloads a narrowly scoped Gitpod machine token. Passing the OTS prevents the token from ending up in the browser history or logs. We really should replace this with OAuth2 PKCE.
  • adds chisel to supervisor's endpoint, cmux'ing it together with gRPC and HTTP. To make this work I needed to fork chisel. We should consider upstreaming that change.
  • makes owner-token based authentication available as Header in addition to a Cookie. This way, any request towards ws-proxy with an x-gitpod-owner-token header will be properly authenticated as if that header's value came from the owner cookie.
  • reduces the character set we use to produce the owner token. This drastically improves the ease of use for this token because it removes the need for URL encoding and makes it easy to use on the command line.
  • adds seccomp-notify support for chmod("/dev/pts") calls as they are commonly made by SSH servers (like OpenSSH or dropbear). Those calls fail in a Gitpod workspace because /dev/ptmx and subsequent /dev/pts/ devices are bind mounts to the Kubernetes container where the "root" user inside a workspace has no privileges. Turns out that the ssh servers work just fine even if we degrade this particular chmod call to a noop.
  • adds a statically build SSH server (dropbear) to supervisor's build and makes supervisor start the SSH server on port 23001. This way supervisor runs on 22999, the IDE on 23000 and SSH on 23001. We also produce a host key for each workspace using dropbearkey prior to starting the SSH server. I considered making use of SO_REUSEPORT (which dropbear supports) to multiplex the SSH server into 22999 but don't think the complexity is worth it.
  • adds auto-upload of a local-app client's to the workspace using supervisor's terminal API. The local app starts a terminal, executes essentially echo $PUBLIC_KEY >> ~/.ssh/authorized_keys, and closes the terminal again.

How to test

  1. Login at https://cw-login-local.staging.gitpod-dev.com/workspaces/
  2. On your local machine (or a Gitpod workspace) download the local app:
    docker run --rm -it -v .:/out eu.gcr.io/gitpod-core-dev/build/local-app:cw-login-local.30
    
  3. Run the local app:
    ## Linux
    GITPOD_HOST=https://cw-login-local.staging.gitpod-dev.com/ ./local-app-linux
    
    ## OSX
    GITPOD_HOST=https://cw-login-local.staging.gitpod-dev.com/ ./local-app-darwin
    
    ## Windows
    set GITPOD_HOST=https://cw-login-local.staging.gitpod-dev.com/ 
    local-app-windows.exe
    
  4. Start a workspace on https://cw-login-local.staging.gitpod-dev.com/workspaces/
  5. Observe the log output of the local app - eventually it should say something like client: supervisor: Connected and client: ssh: Connected
  6. You should be able to SSH into the workspace using ssh -F /tmp/gitpod_ssh_config <your-workspace-id>
  7. If you configure VS Code to use /tmp/gitpod_ssh_config you can connect to your workspace using the Remote SSH extension:

Immediate Next Steps

  • replace custom login flow with OAuth2 PKCE
  • improve connection and discovery stability
    • don't list all instances but running ones only
    • find out where that 60 second timeout comes from
    • clean up local app state management. Not sure that "callback" interface is a good idea.
  • think of a better name
  • maybe introduce some UI, e.g. in the tray
  • think about heartbeating. Right now the workspace timeout is still bound to the tab. We could e.g. have the local-app do the heartbeating while the SSH-over-chisel connection is active.
  • figure out why the $PATH is broken (Go and Python are missing) make dropbear pass on the env vars to the children it spawns

@csweichel csweichel changed the title Local App (alpha) Local Companion (alpha) Apr 15, 2021
@svenefftinge
Copy link
Member

svenefftinge commented Apr 19, 2021

/werft run

👍 started the job as gitpod-build-cw-login-local.32

@svenefftinge
Copy link
Member

svenefftinge commented Apr 22, 2021

/werft run

👍 started the job as gitpod-build-cw-login-local.33

Copy link
Member

@akosyakov akosyakov left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog worth adding to www.gitpod.io/changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants