From 4899c2c1f4af7127512ef147cf1418e45f27ab5a Mon Sep 17 00:00:00 2001 From: Maisem Ali Date: Sun, 15 Oct 2023 18:41:28 -0700 Subject: [PATCH] cmd/containerboot: revert to using tailscale up This partially reverts commits a61a9ab087e16270bc039252e7620aae4de3d56e and 7538f386710b80c6b4c1997797be28a661210d4a and fully reverts 4823a7e591ef859250114ad20b337d4358af9ead. The goal of that commit was to reapply known config whenever the container restarts. However, that already happens when TS_AUTH_ONCE was false (the default back then). So we only had to selectively reapply the config if TS_AUTH_ONCE is true, this does exactly that. This is a little sad that we have to revert to `tailscale up`, but it fixes the backwards incompatibility problem. Updates tailscale/tailscale#9539 Signed-off-by: Maisem Ali --- cmd/containerboot/main.go | 54 +++++++------ cmd/containerboot/main_test.go | 136 ++++++++------------------------- 2 files changed, 60 insertions(+), 130 deletions(-) diff --git a/cmd/containerboot/main.go b/cmd/containerboot/main.go index 8d97df4e2..e5984a5b5 100644 --- a/cmd/containerboot/main.go +++ b/cmd/containerboot/main.go @@ -19,8 +19,7 @@ // - TS_TAILNET_TARGET_IP: proxy all incoming non-Tailscale traffic to the given // destination. // - TS_TAILSCALED_EXTRA_ARGS: extra arguments to 'tailscaled'. -// - TS_EXTRA_ARGS: extra arguments to 'tailscale login', these are not -// reset on restart. +// - TS_EXTRA_ARGS: extra arguments to 'tailscale up'. // - TS_USERSPACE: run with userspace networking (the default) // instead of kernel networking. // - TS_STATE_DIR: the directory in which to store tailscaled @@ -36,15 +35,9 @@ // - 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, 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. +// logged in. If false (the default, for backwards +// compatibility), forcibly log in every time the +// container starts. // - 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. @@ -118,7 +111,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", true), + AuthOnce: defaultBool("TS_AUTH_ONCE", false), Root: defaultEnv("TS_TEST_ONLY_ROOT", "/"), } @@ -212,7 +205,7 @@ func main() { } didLogin = true w.Close() - if err := tailscaleLogin(bootCtx, cfg); err != nil { + if err := tailscaleUp(bootCtx, cfg); err != nil { return fmt.Errorf("failed to auth tailscale: %v", err) } w, err = client.WatchIPNBus(bootCtx, ipn.NotifyInitialNetMap|ipn.NotifyInitialState) @@ -262,10 +255,12 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) // no deadline now that we're in steady state defer cancel() - // Now that we are authenticated, we can set/reset any of the - // settings that we need to. - if err := tailscaleSet(ctx, cfg); err != nil { - log.Fatalf("failed to auth tailscale: %v", err) + if cfg.AuthOnce { + // Now that we are authenticated, we can set/reset any of the + // settings that we need to. + if err := tailscaleSet(ctx, cfg); err != nil { + log.Fatalf("failed to auth tailscale: %v", err) + } } if cfg.ServeConfigPath != "" { @@ -545,29 +540,40 @@ func tailscaledArgs(cfg *settings) []string { return args } -// tailscaleLogin uses cfg to run 'tailscale login' everytime containerboot -// starts, or if TS_AUTH_ONCE is set, only the first time containerboot starts. -func tailscaleLogin(ctx context.Context, cfg *settings) error { - args := []string{"--socket=" + cfg.Socket, "login"} +// tailscaleUp uses cfg to run 'tailscale up' everytime containerboot starts, or +// if TS_AUTH_ONCE is set, only the first time containerboot starts. +func tailscaleUp(ctx context.Context, cfg *settings) error { + args := []string{"--socket=" + cfg.Socket, "up"} + if cfg.AcceptDNS { + args = append(args, "--accept-dns=true") + } else { + args = append(args, "--accept-dns=false") + } if cfg.AuthKey != "" { args = append(args, "--authkey="+cfg.AuthKey) } + if cfg.Routes != "" { + args = append(args, "--advertise-routes="+cfg.Routes) + } + if cfg.Hostname != "" { + args = append(args, "--hostname="+cfg.Hostname) + } if cfg.ExtraArgs != "" { args = append(args, strings.Fields(cfg.ExtraArgs)...) } - log.Printf("Running 'tailscale login'") + log.Printf("Running 'tailscale up'") cmd := exec.CommandContext(ctx, "tailscale", args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return fmt.Errorf("tailscale login failed: %v", err) + return fmt.Errorf("tailscale up failed: %v", err) } return nil } // tailscaleSet uses cfg to run 'tailscale set' to set any known configuration // options that are passed in via environment variables. This is run after the -// node is in Running state. +// node is in Running state and only if TS_AUTH_ONCE is set. func tailscaleSet(ctx context.Context, cfg *settings) error { args := []string{"--socket=" + cfg.Socket, "set"} if cfg.AcceptDNS { diff --git a/cmd/containerboot/main_test.go b/cmd/containerboot/main_test.go index 7a5280b6e..88d70b025 100644 --- a/cmd/containerboot/main_test.go +++ b/cmd/containerboot/main_test.go @@ -129,22 +129,16 @@ type phase struct { { // Out of the box default: runs in userspace mode, ephemeral storage, interactive login. Name: "no_args", - Env: map[string]string{ - "TS_AUTH_ONCE": "false", - }, - + Env: nil, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -152,21 +146,17 @@ type phase struct { // Userspace mode, ephemeral storage, authkey provided on every run. Name: "authkey", Env: map[string]string{ - "TS_AUTHKEY": "tskey-key", - "TS_AUTH_ONCE": "false", + "TS_AUTHKEY": "tskey-key", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -174,21 +164,17 @@ 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_ONCE": "false", + "TS_AUTH_KEY": "tskey-key", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -197,35 +183,30 @@ type phase struct { Env: map[string]string{ "TS_AUTHKEY": "tskey-key", "TS_STATE_DIR": filepath.Join(d, "tmp"), - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, { Name: "routes", Env: map[string]string{ - "TS_AUTHKEY": "tskey-key", - "TS_ROUTES": "1.2.3.0/24,10.20.30.0/24", - "TS_AUTH_ONCE": "false", + "TS_AUTHKEY": "tskey-key", + "TS_ROUTES": "1.2.3.0/24,10.20.30.0/24", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key --advertise-routes=1.2.3.0/24,10.20.30.0/24", }, }, { @@ -234,9 +215,6 @@ type phase struct { "proc/sys/net/ipv4/ip_forward": "0", "proc/sys/net/ipv6/conf/all/forwarding": "0", }, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false --advertise-routes=1.2.3.0/24,10.20.30.0/24", - }, }, }, }, @@ -246,13 +224,12 @@ 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{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key --advertise-routes=1.2.3.0/24,10.20.30.0/24", }, }, { @@ -261,9 +238,6 @@ type phase struct { "proc/sys/net/ipv4/ip_forward": "1", "proc/sys/net/ipv6/conf/all/forwarding": "0", }, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false --advertise-routes=1.2.3.0/24,10.20.30.0/24", - }, }, }, }, @@ -273,13 +247,12 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "::/64,1::/64", "TS_USERSPACE": "false", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key --advertise-routes=::/64,1::/64", }, }, { @@ -288,9 +261,6 @@ type phase struct { "proc/sys/net/ipv4/ip_forward": "0", "proc/sys/net/ipv6/conf/all/forwarding": "1", }, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false --advertise-routes=::/64,1::/64", - }, }, }, }, @@ -300,13 +270,12 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_ROUTES": "::/64,1.2.3.0/24", "TS_USERSPACE": "false", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key --advertise-routes=::/64,1.2.3.0/24", }, }, { @@ -315,9 +284,6 @@ type phase struct { "proc/sys/net/ipv4/ip_forward": "1", "proc/sys/net/ipv6/conf/all/forwarding": "1", }, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false --advertise-routes=::/64,1.2.3.0/24", - }, }, }, }, @@ -327,20 +293,16 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_DEST_IP": "1.2.3.4", "TS_USERSPACE": "false", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -350,20 +312,16 @@ type phase struct { "TS_AUTHKEY": "tskey-key", "TS_TAILNET_TARGET_IP": "100.99.99.99", "TS_USERSPACE": "false", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -384,7 +342,7 @@ type phase struct { State: ptr.To(ipn.NeedsLogin), }, WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, }, { @@ -400,7 +358,6 @@ 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", @@ -409,7 +366,7 @@ type phase struct { { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=kube:tailscale --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, WantKubeSecret: map[string]string{ "authkey": "tskey-key", @@ -417,9 +374,6 @@ type phase struct { }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, WantKubeSecret: map[string]string{ "authkey": "tskey-key", "device_fqdn": "test-node.test.ts.net", @@ -438,22 +392,18 @@ 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{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, WantKubeSecret: map[string]string{}, }, { - Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, + Notify: runningNotify, WantKubeSecret: map[string]string{}, }, }, @@ -464,7 +414,6 @@ 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, @@ -472,15 +421,12 @@ type phase struct { { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=kube:tailscale --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, WantKubeSecret: map[string]string{}, }, { - Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, + Notify: runningNotify, WantKubeSecret: map[string]string{}, }, }, @@ -510,7 +456,7 @@ type phase struct { State: ptr.To(ipn.NeedsLogin), }, WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, WantKubeSecret: map[string]string{ "authkey": "tskey-key", @@ -534,7 +480,6 @@ 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", @@ -543,7 +488,7 @@ type phase struct { { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=kube:tailscale --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --authkey=tskey-key", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --authkey=tskey-key", }, WantKubeSecret: map[string]string{ "authkey": "tskey-key", @@ -551,9 +496,6 @@ type phase struct { }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, WantKubeSecret: map[string]string{ "authkey": "tskey-key", "device_fqdn": "test-node.test.ts.net", @@ -586,20 +528,16 @@ 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{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking --socks5-server=localhost:1080 --outbound-http-proxy-listen=localhost:8080", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, @@ -607,20 +545,16 @@ type phase struct { Name: "dns", Env: map[string]string{ "TS_ACCEPT_DNS": "true", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=true", }, }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=true", - }, }, }, }, @@ -629,41 +563,31 @@ type phase struct { Env: map[string]string{ "TS_EXTRA_ARGS": "--widget=rotated", "TS_TAILSCALED_EXTRA_ARGS": "--experiments=widgets", - "TS_AUTH_ONCE": "false", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking --experiments=widgets", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login --widget=rotated", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --widget=rotated", }, - }, - { + }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false", - }, }, }, }, { Name: "hostname", Env: map[string]string{ - "TS_HOSTNAME": "my-server", - "TS_AUTH_ONCE": "false", + "TS_HOSTNAME": "my-server", }, Phases: []phase{ { WantCmds: []string{ "/usr/bin/tailscaled --socket=/tmp/tailscaled.sock --state=mem: --statedir=/tmp --tun=userspace-networking", - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock login", + "/usr/bin/tailscale --socket=/tmp/tailscaled.sock up --accept-dns=false --hostname=my-server", }, - }, - { + }, { Notify: runningNotify, - WantCmds: []string{ - "/usr/bin/tailscale --socket=/tmp/tailscaled.sock set --accept-dns=false --hostname=my-server", - }, }, }, },