Skip to content

tsidp-server: add -login-server for custom control servers - #202

Open
RyoKusnadi wants to merge 1 commit into
tailscale:mainfrom
RyoKusnadi:feat/104-login-server
Open

RyoKusnadi wants to merge 1 commit into
tailscale:mainfrom
RyoKusnadi:feat/104-login-server

Conversation

@RyoKusnadi

Copy link
Copy Markdown

Fixes #104

What

Adds a -login-server flag (env TS_LOGIN_SERVER) that sets tsnet.Server.ControlURL, so tsidp can join a tailnet run by a control server other than Tailscale's, such as Headscale. It works like tailscale up --login-server.

tsidp -login-server https://headscale.example.com
# or
TS_LOGIN_SERVER=https://headscale.example.com tsidp

Behavior

  • Empty (default): ControlURL is left unset, so tsnet behaves exactly as before, including honoring its own TS_CONTROL_URL env var. When -login-server is set, it takes precedence over TS_CONTROL_URL.

  • Precedence: the env var supplies the flag's default and an explicit flag wins, the same pattern as -advertise-tags and -authkey-file.

  • Validation (parseLoginServer): the value must be an absolute http:// or https:// URL with a host. It rejects:

    • credentials (https://user:pass@host, or any @), so they can't end up in logs
    • a query or fragment (?x=1, #f), which would break the URLs tsnet builds on top of it
    • a missing host (https://, https://:443) or an opaque form (https:host)

    On a bad value tsidp exits with code 1 and a fixed error message. Error messages never include any part of the input, so a mistyped URL that contains a token or password isn't written to the logs.

  • Normalizing: the scheme is lowercased and trailing slashes are removed (HTTPS://hs.example.com// → https://hs.example.com). The host keeps its case.

  • With -use-local-tailscaled: the flag has no effect (the local tailscaled must be set up with tailscale up --login-server instead), so tsidp logs a warning, as it already does for -authkey-file.

README: added the flag to the CLI flags table, the env var list and the Docker env table.

Tests

TestParseLoginServer is table-driven with 32 cases:

  • Accepted: empty, whitespace only, https, http with port, IPv6 with port, path, trailing slashes, uppercase scheme, surrounding whitespace.
  • Rejected: missing scheme, ftp://, no host, port without host, opaque URL, unparsable URL, userinfo, username only, query, empty query, fragment, empty fragment, plus malformed credential URLs (https:user:secret@host, user:secret@host, https://host:secret, …).
  • Every rejected case also asserts that the error text doesn't contain the input's secret.
gofmt -l .               # clean
go build ./...           # ok
go vet ./...             # ok
make test                # ok  github.com/tailscale/tsidp, ok  .../server

I also ran the built binary by hand: invalid values via both the flag and the env var exit 1 with the fixed messages; a valid value logs using custom control server url=... and proceeds to login; the flag overrides the env var; and -use-local-tailscaled logs the warning.

Not covered

As noted in the issue thread, tsidp serves HTTPS through ts.ListenTLS, which needs the control server to issue certificates. This PR only adds the control-server setting; it doesn't change how certificates are obtained, so tsidp may still be unable to serve HTTPS on control servers without certificate support. I didn't test against a live Headscale server.

The README notes that TS_ env names may move to TSIDP_ later. I used TS_LOGIN_SERVER to match the existing network settings (TS_HOSTNAME, TS_AUTHKEY_FILE, …) and the CLI's --login-server. Happy to rename it.

Add a -login-server flag, with TS_LOGIN_SERVER as its environment
variable, that sets tsnet.Server.ControlURL. This lets tsidp join a
tailnet run by a control server other than Tailscale's, such as
Headscale, the same way `tailscale up --login-server` does.

The value must be an absolute http:// or https:// URL with a host.
URLs with credentials, a query or a fragment are rejected, and error
messages never repeat the input so a mistyped URL can't leak a secret
into the logs. The scheme is lowercased and trailing slashes are
removed. When the flag is empty, tsnet keeps its default behavior,
including honoring TS_CONTROL_URL. With -use-local-tailscaled the flag
has no effect and a warning is logged, as for -authkey-file.

Fixes tailscale#104

Signed-off-by: Ryo Kusnadi <ryokusnadi@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for login-server for non-Tailscale control servers

1 participant