Skip to content

Latest commit

 

History

History
171 lines (109 loc) · 7.98 KB

007-deployment-auth.md

File metadata and controls

171 lines (109 loc) · 7.98 KB

title = "SIP 007 - Deployment Authentication and Authorisation" template = "main" date = "2022-09-30T01:01:01Z"

Summary: User experience and implementation design for authentication to deployment targets.

Owners: ivan.towlson@fermyon.com

Created: Sep 30, 2022

Background

spin deploy currently requires the user to authenticate on every deployment. For a "username-password" style of authentication, this is relatively painless as the user can set the HIPPO_USERNAME and HIPPO_PASSWORD environment variables and never need to worry about it. However, it's unsatisfactory for token-based schemes such as OAuth or device code login, which are modelled more around a login experience that grants an access token.

We want to provide a way for spin deploy to work smoothly against environments configured with these schemes, as well as the existing "username-password" environments.

Current experience

To recap, the current spin deploy authentication experience is:

  • --bindle-server or $BINDLE_URL - required
  • --bindle-username or $BINDLE_USERNAME - optional
  • --bindle-password or $BINDLE_PASSWORD - optional
  • --hippo-server or $HIPPO_URL - required
  • --hippo-username or $HIPPO_USERNAME - required
  • --hippo-password or $HIPPO_PASSWORD - required

Proposal

Conceptual model

At any given time, Spin is either be logged out (no active deployment target, no credentials stored for any target) or logged in to a deployment target (URL and credentials stored for that target). Logging in is a separate step from deployment. Deployment requires Spin to be logged in, and always deploys to the stored URL with the stored credentials

NOTE: This will apply to existing username-password environments as well. The current UI for deploying to those environments goes away.

FUTURE: In future Spin may be able to store multiple deployment targets, in a similar manner to Kubernetes contexts. A user would then be able to switch between these contexts without re-establishing credentials. It would be desirable to have some level of this very early on, so that users or Fermyon staff could easily test on deployment targets running stable and canary Spin versions.

Login command

We propose to add a spin login command, which takes the desired Hippo server as an argument:

spin login --url https://example.com

This launches an interactive login experience as follows.

1. Determine auth type.

At the moment, Spin doesn't know whether a URL uses device flow or username-password, so spin login will prompt. If we can identify particular URLs or families of URLs whose auth mode is known, those can skip this step.

What authentication method does this server support?
1. Sign in with GitHub
2. Sign in with a username and password
Enter a number:

Programmatic consumers need a way to suppress this prompt, as follows:

  • If --get-device-code or --check-device-code is present, use GitHub auth.
  • Otherwise, support a --method=[username|github] flag to specify the method. This flag can be hidden from the online help.

FUTURE: We would implement an API for Spin to ask a server which auth mode(s) it supports.

2a. Username-password prompt.

If the mode is username-password, Spin prompts for these values. If the environment variables currently defined for spin deploy are set, these will be picked up and not be prompted for.

Hippo username: 
Hippo password:
# etc

The URLs (Hippo and Bindle) and credentials are stored on the machine.

2b. GitHub device authorisation flow.

If the mode is GitHub device auth, Spin prompts the user to open their browser:

$ spin login --url https://example.com
Copy your one-time code: tWOJCFhY
Press Enter to open https://example.com/device-authorization in your browser
# ...user hits Enter...
Waiting for device authorization...
Waiting for device authorization...
Device authorized!
Login successful.

The URL and token generated by the device authorisation flow are stored on the machine.

Logout command

spin logout destroys the current stored credentials and puts Spin in the 'logged out' state.

Deploy command changes

The spin deploy command will now act as follows:

  • The Hippo and Bindle flags/environment variables are removed.
  • If Spin is logged out, spin deploy prints a prompt to run spin login, and exits.
    • FUTURE: It will launch the login flow.
    • It would be good to have distinguished exit codes for "need to log in" vs "deployment failed," for programmatic consumption.
  • If Spin is logged in, spin deploy performs the current deployment flow, using the stored URL and credentials.
    • If auth fails (e.g. wrong password or expired token), spin deploy prints a prompt to run spin login, and exits.
    • FUTURE: It will launch the login flow.

Device authorisation flow detailed considerations

spin login is a new command and a relatively complex user experience. This section describes the behaviour in more detail.

Browser interaction

As part of device auth flow, the user needs to go to the verification URL in their browser and paste in the code.

We discussed:

  1. Opening the browser automatically
  2. Copying the user code to the clipboard

The current proposal follows the gh flow, which seems appropriate for GitHub auth. That is:

  1. The user hits a key to open the browser. This seems like a good compromise between the convenience factor and the potential surprise (or "on which of my five monitors did it open") of doing it when the user isn't expecting it.
  • A clickable URL is displayed in case automatic open doesn't work.
  1. The user is responsible for copying the code if they want to. This avoids the risk of blatting important clipboard contents. As the user has to hit a key to open the browser, they have plenty of time to copy the code, or memorise it, or jot it down on a scrap of parchment, whatever is suitable to their current state and workflow.

Verification polling

The device auth flow involves the client polling the server using the device code as the auth token. Each poll can have three outcomes:

  • 200 and the response contains a token: user has authorised this device
  • 200 and the response doesn't contain a token: user has not yet authorised this device
  • Server error
  • Network error

We propose to poll for up to 15 minutes (the expiry time of the code). If the user has not entered the code by then, spin login fails and exits.

Errors do not cause polling to terminate. We do not want a transient network error or server hiccup to block login. That said, if we can identify server responses that are necessarily fatal, we can in future terminate early on those. spin login will, however, report the error so that a user can cancel out if it's looking broken rather than gazing at a polling display for 15 minutes.

Token storage

When the user logs into a server, we need to store:

  • The server URL
  • Any server connection options, such as the --insecure flag
  • The credentials (token, username-password, etc.)

A simple solution is to store these in a file under a non-roaming directory. This is not fantastically secure for tokens, but may be enough for the preview. (And hey, it's good enough for kubectl.)

FUTURE: There will be either multiple files or multiple items in the file (a la kubeconfig). We might want to plan for this in our implementation.

Programmatic control

For environments like the VS Code extension, the standard interactive device auth flow is hard to manage. We therefore propose an alternative flow, controlled by flags that are hidden from interactive users, e.g.

$ spin login --url foo --get-device-code
{ "verificationUrl" : "...", "deviceCode" : "...", "userCode": " ..." }

$ spin login --url foo --check-device-code bar
{ "status" : "waiting" }

# user enters code into browser

$ spin login --url foo --check-device-code bar
{ "status" : "authorized", "token" : "..." }

Similarly, it should be possible to make username-password login non-interactive by passing suitable flags or environment variables.