From 4823a7e591ef859250114ad20b337d4358af9ead Mon Sep 17 00:00:00 2001 From: Denton Gentry Date: Thu, 28 Sep 2023 11:51:03 -0700 Subject: [PATCH] cmd/containerboot: set TS_AUTH_ONCE default to true. 1.50.0 switched containerboot from using `tailscale up` to `tailscale login`. A side-effect is that a re-usable authkey is now re-applied on every boot by `tailscale login`, where `tailscale up` would ignore an authkey if already authenticated. Though this looks like it is changing the default, in reality it is setting the default to match what 1.48 and all prior releases actually implemented. Fixes https://github.com/tailscale/tailscale/issues/9539 Fixes https://github.com/tailscale/corp/issues/14953 Signed-off-by: Denton Gentry --- cmd/containerboot/main.go | 14 ++++++++++---- cmd/containerboot/main_test.go | 32 ++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/cmd/containerboot/main.go b/cmd/containerboot/main.go index 893495063..59da2c062 100644 --- a/cmd/containerboot/main.go +++ b/cmd/containerboot/main.go @@ -36,9 +36,15 @@ // - TS_SOCKET: the path where the tailscaled LocalAPI socket should // be created. // - TS_AUTH_ONCE: if true, only attempt to log in if not already -// logged in. If false (the default, for backwards -// compatibility), forcibly log in every time the -// container starts. +// logged in. If false, forcibly log in every time the container starts. +// The default until 1.50.0 was false, but that was misleading: until +// 1.50, containerboot used `tailscale up` which would ignore an authkey +// argument if there was already a node key. Effectively, this behaved +// as though TS_AUTH_ONCE were always true. +// In 1.50.0 the change was made to use `tailscale login` instead of `up`, +// and login will reauthenticate every time it is given an authkey. +// In 1.50.1 we set the TS_AUTH_ONCE to true, to match the previously +// observed behavior. // - TS_SERVE_CONFIG: if specified, is the file path where the ipn.ServeConfig is located. // It will be applied once tailscaled is up and running. If the file contains // ${TS_CERT_DOMAIN}, it will be replaced with the value of the available FQDN. @@ -103,7 +109,7 @@ func main() { SOCKSProxyAddr: defaultEnv("TS_SOCKS5_SERVER", ""), HTTPProxyAddr: defaultEnv("TS_OUTBOUND_HTTP_PROXY_LISTEN", ""), Socket: defaultEnv("TS_SOCKET", "/tmp/tailscaled.sock"), - AuthOnce: defaultBool("TS_AUTH_ONCE", false), + AuthOnce: defaultBool("TS_AUTH_ONCE", true), Root: defaultEnv("TS_TEST_ONLY_ROOT", "/"), } diff --git a/cmd/containerboot/main_test.go b/cmd/containerboot/main_test.go index 2561e6724..b7147b75f 100644 --- a/cmd/containerboot/main_test.go +++ b/cmd/containerboot/main_test.go @@ -129,7 +129,10 @@ func TestContainerBoot(t *testing.T) { { // Out of the box default: runs in userspace mode, ephemeral storage, interactive login. Name: "no_args", - Env: nil, + Env: map[string]string{ + "TS_AUTH_ONCE": "false", + }, + Phases: []phase{ { WantCmds: []string{ @@ -149,7 +152,8 @@ func TestContainerBoot(t *testing.T) { // Userspace mode, ephemeral storage, authkey provided on every run. Name: "authkey", Env: map[string]string{ - "TS_AUTHKEY": "tskey-key", + "TS_AUTHKEY": "tskey-key", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -170,7 +174,8 @@ func TestContainerBoot(t *testing.T) { // Userspace mode, ephemeral storage, authkey provided on every run. Name: "authkey-old-flag", Env: map[string]string{ - "TS_AUTH_KEY": "tskey-key", + "TS_AUTH_KEY": "tskey-key", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -192,6 +197,7 @@ func TestContainerBoot(t *testing.T) { Env: map[string]string{ "TS_AUTHKEY": "tskey-key", "TS_STATE_DIR": filepath.Join(d, "tmp"), + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -211,8 +217,9 @@ func TestContainerBoot(t *testing.T) { { Name: "routes", Env: map[string]string{ - "TS_AUTHKEY": "tskey-key", - "TS_ROUTES": "1.2.3.0/24,10.20.30.0/24", + "TS_AUTHKEY": "tskey-key", + "TS_ROUTES": "1.2.3.0/24,10.20.30.0/24", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -239,6 +246,7 @@ func TestContainerBoot(t *testing.T) { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "1.2.3.0/24,10.20.30.0/24", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -265,6 +273,7 @@ func TestContainerBoot(t *testing.T) { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "::/64,1::/64", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -291,6 +300,7 @@ func TestContainerBoot(t *testing.T) { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "::/64,1.2.3.0/24", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -317,6 +327,7 @@ func TestContainerBoot(t *testing.T) { "TS_AUTHKEY": "tskey-key", "TS_DEST_IP": "1.2.3.4", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -341,6 +352,7 @@ func TestContainerBoot(t *testing.T) { "TS_AUTHKEY": "tskey-key", "TS_TAILNET_TARGET_IP": "100.99.99.99", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -393,6 +405,7 @@ func TestContainerBoot(t *testing.T) { Env: map[string]string{ "KUBERNETES_SERVICE_HOST": kube.Host, "KUBERNETES_SERVICE_PORT_HTTPS": kube.Port, + "TS_AUTH_ONCE": "false", }, KubeSecret: map[string]string{ "authkey": "tskey-key", @@ -430,6 +443,7 @@ func TestContainerBoot(t *testing.T) { "TS_KUBE_SECRET": "", "TS_STATE_DIR": filepath.Join(d, "tmp"), "TS_AUTHKEY": "tskey-key", + "TS_AUTH_ONCE": "false", }, KubeSecret: map[string]string{}, Phases: []phase{ @@ -455,6 +469,7 @@ func TestContainerBoot(t *testing.T) { "KUBERNETES_SERVICE_HOST": kube.Host, "KUBERNETES_SERVICE_PORT_HTTPS": kube.Port, "TS_AUTHKEY": "tskey-key", + "TS_AUTH_ONCE": "false", }, KubeSecret: map[string]string{}, KubeDenyPatch: true, @@ -524,6 +539,7 @@ func TestContainerBoot(t *testing.T) { Env: map[string]string{ "KUBERNETES_SERVICE_HOST": kube.Host, "KUBERNETES_SERVICE_PORT_HTTPS": kube.Port, + "TS_AUTH_ONCE": "false", }, KubeSecret: map[string]string{ "authkey": "tskey-key", @@ -575,6 +591,7 @@ func TestContainerBoot(t *testing.T) { Env: map[string]string{ "TS_SOCKS5_SERVER": "localhost:1080", "TS_OUTBOUND_HTTP_PROXY_LISTEN": "localhost:8080", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -595,6 +612,7 @@ func TestContainerBoot(t *testing.T) { Name: "dns", Env: map[string]string{ "TS_ACCEPT_DNS": "true", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -616,6 +634,7 @@ func TestContainerBoot(t *testing.T) { Env: map[string]string{ "TS_EXTRA_ARGS": "--widget=rotated", "TS_TAILSCALED_EXTRA_ARGS": "--experiments=widgets", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -635,7 +654,8 @@ func TestContainerBoot(t *testing.T) { { Name: "hostname", Env: map[string]string{ - "TS_HOSTNAME": "my-server", + "TS_HOSTNAME": "my-server", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ {