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 @@ type phase struct { { // 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 @@ type phase struct { // 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 @@ type phase struct { // 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 @@ type phase struct { 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 @@ type phase struct { { 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 @@ type phase struct { "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 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "::/64,1::/64", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -291,6 +300,7 @@ type phase struct { "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 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_DEST_IP": "1.2.3.4", "TS_USERSPACE": "false", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -341,6 +352,7 @@ type phase struct { "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 @@ type phase struct { 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 @@ type phase struct { "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 @@ type phase struct { "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 @@ type phase struct { 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 @@ type phase struct { 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 @@ type phase struct { Name: "dns", Env: map[string]string{ "TS_ACCEPT_DNS": "true", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ { @@ -616,6 +634,7 @@ type phase struct { 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 @@ type phase struct { { Name: "hostname", Env: map[string]string{ - "TS_HOSTNAME": "my-server", + "TS_HOSTNAME": "my-server", + "TS_AUTH_ONCE": "false", }, Phases: []phase{ {