Remote access
On your own machine spwn asks for nothing: it’s bound to 127.0.0.1, and anything that
can reach the port can already do anything you can. Bind it anywhere else and it requires an
account, so you can open it from another machine, a container or a cluster.
When accounts are on
Section titled “When accounts are on”spwn decides from the address it binds, unless you tell it otherwise:
| You run | Accounts |
|---|---|
spwn (binds 127.0.0.1) |
Off |
spwn serve --host 0.0.0.0 (or any non-loopback address) |
On |
spwn serve --auth |
On, even on localhost |
spwn serve --no-auth |
Off, even on 0.0.0.0 |
The flags win over the SPWN_AUTH environment variable, which wins over the bind.
SPWN_AUTH takes off, on (or local), proxy or oidc.
Use --no-auth only when you have your own gate in front: anyone who can reach the port gets
a shell.
The setup link
Section titled “The setup link”The first time spwn boots with accounts on and none exist yet, it prints a one-time link:
spwn has no account yet. Open this to make the first one:
http://localhost:4317/?setup=…Open it, choose a username and password, and you’re signed in. The link stops working the
moment that account exists. If the logs have rolled, the same token is in setup-token in
spwn’s data folder (mode 0600), and it’s removed once used. Set SPWN_SETUP_TOKEN to choose
the token yourself instead of having one minted.
In the Docker and Helm deployments, find it with logs … | grep -A3 'no account yet' (see
Install).
Sessions last 12 hours. Settings → Account changes your password, which signs out every other device, and has Sign out everywhere.
Behind a proxy: SPWN_PUBLIC_URL
Section titled “Behind a proxy: SPWN_PUBLIC_URL”Put an Ingress, nginx or any reverse proxy in front of spwn and set SPWN_PUBLIC_URL to the
URL people actually visit:
SPWN_PUBLIC_URL=https://spwn.example.com spwn serve --host 0.0.0.0 --no-openIt does three things:
- Origin checks. spwn refuses cross-origin requests that change state, WebSocket
handshakes and everything under
/ide. A proxy that rewrites theHostheader to its upstream’s name makes every request look cross-origin, and you get 403s with no obvious cause. WithSPWN_PUBLIC_URLset, theOriginis compared against it instead. - Secure cookies. The proxy terminates TLS, so spwn can’t see it. An
https://public URL is what marks the session cookieSecure. - Links. It’s the base of the setup link and, in OIDC mode, the redirect URI.
In the Helm chart it’s auth.publicUrl.
Access tokens
Section titled “Access tokens”A git client or CI job can’t sign in through a browser. Create an access token in
Settings → Account instead. Its secret (spwn_pat_…) is shown once. Send it as
Authorization: Bearer <token>, or as the password in HTTP Basic with any username, which is
what git does:
git clone http://me:spwn_pat_…@spwn.example.com/git/<project-name>spwn serves a read-only git endpoint at /git/<project>, by a project’s name or id. Tokens
work in every mode, and revoking one takes effect at once.
Proxy and OIDC modes
Section titled “Proxy and OIDC modes”If you already have an identity provider, spwn can use it instead of its own passwords. Both
modes need an image built with the enterprise feature
(docker build -f deploy/Dockerfile --build-arg CARGO_FEATURES=enterprise .). The default
build refuses them at startup, by name, rather than falling back to a password prompt.
proxy trusts an identity header set by whatever authenticates in front of spwn:
oauth2-proxy, Pomerium, an ingress auth-url, Cloudflare Access, IAP, Teleport. Prefer it
when you have one: your proxy already handles MFA and group rules.
SPWN_AUTH_PROXY_HEADER(required): the header, e.g.X-Auth-Request-Email.SPWN_AUTH_PROXY_FROM: comma-separated addresses or CIDR ranges allowed to assert it. Empty means any peer.
spwn doesn’t re-check the header, so it’s worth exactly what the path it came over is worth.
Set SPWN_AUTH_PROXY_FROM and a NetworkPolicy, so nothing can reach spwn without going
through the proxy. Accounts are created the first time the proxy lets someone through.
oidc runs the OpenID Connect flow itself (authorization code with PKCE), for a setup
with an identity provider and nothing doing forward-auth:
SPWN_OIDC_ISSUER,SPWN_OIDC_CLIENT_ID(required), andSPWN_PUBLIC_URL(required).SPWN_OIDC_CLIENT_SECRETorSPWN_OIDC_CLIENT_SECRET_FILE.SPWN_OIDC_SCOPES(defaultemail,profile;openidis always sent).SPWN_OIDC_AUTO_PROVISION=1to give anyone the provider admits an account. Without it, a sign-in must match an existing account by name.
Register <SPWN_PUBLIC_URL>/api/auth/oidc/callback with the provider. Accounts are keyed on
the provider’s issuer and subject, not the email.
The Helm chart sets all of these from its auth: values. See
deploy/charts/spwn
and design/011 for
the reasoning.