From 0f3a292ebde93c9508f230e1b0b49f22a80b4c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chlo=C3=A9=20Vulquin?= Date: Mon, 8 Apr 2024 17:49:43 +0200 Subject: [PATCH] cli/configure: respect $KUBECONFIG (#11604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmd/tailscale/cli: respect $KUBECONFIG * `$KUBECONFIG` is a `$PATH`-like: it defines a *list*. `tailscale config kubeconfig` works like the rest of the ecosystem so that if $KUBECONFIG is set it will write to the first existant file in the list, if none exist then the final entry in the list. * if `$KUBECONFIG` is an empty string, the old logic takes over. Notes: * The logic for file detection is inlined based on what `kind` does. Technically it's a race condition, since the file could be removed/added in between the processing steps, but the fallout shouldn't be too bad. https://github.com/kubernetes-sigs/kind/blob/v0.23.0-alpha/pkg/cluster/internal/kubeconfig/internal/kubeconfig/paths.go * The sandboxed (App Store) variant relies on a specific temporary entitlement to access the ~/.kube/config file. The entitlement is only granted to specific files, and so is not applicable to paths supplied by the user at runtime. While there may be other ways to achieve this access to arbitrary kubeconfig files, it's out of scope for now. Updates #11645 Signed-off-by: ChloƩ Vulquin --- cmd/tailscale/cli/configure-kube.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/cmd/tailscale/cli/configure-kube.go b/cmd/tailscale/cli/configure-kube.go index dcda2f030..a663a65bc 100644 --- a/cmd/tailscale/cli/configure-kube.go +++ b/cmd/tailscale/cli/configure-kube.go @@ -43,7 +43,20 @@ See: https://tailscale.com/s/k8s-auth-proxy } // kubeconfigPath returns the path to the kubeconfig file for the current user. -func kubeconfigPath() string { +func kubeconfigPath() (string, error) { + if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" { + if version.IsSandboxedMacOS() { + return "", errors.New("$KUBECONFIG is incompatible with the App Store version") + } + var out string + for _, out = range filepath.SplitList(kubeconfig) { + if info, err := os.Stat(out); !os.IsNotExist(err) && !info.IsDir() { + break + } + } + return out, nil + } + var dir string if version.IsSandboxedMacOS() { // The HOME environment variable in macOS sandboxed apps is set to @@ -55,7 +68,7 @@ func kubeconfigPath() string { } else { dir = homedir.HomeDir() } - return filepath.Join(dir, ".kube", "config") + return filepath.Join(dir, ".kube", "config"), nil } func runConfigureKubeconfig(ctx context.Context, args []string) error { @@ -76,7 +89,11 @@ func runConfigureKubeconfig(ctx context.Context, args []string) error { return fmt.Errorf("no peer found with hostname %q", hostOrFQDN) } targetFQDN = strings.TrimSuffix(targetFQDN, ".") - if err := setKubeconfigForPeer(targetFQDN, kubeconfigPath()); err != nil { + var kubeconfig string + if kubeconfig, err = kubeconfigPath(); err != nil { + return err + } + if err = setKubeconfigForPeer(targetFQDN, kubeconfig); err != nil { return err } printf("kubeconfig configured for %q\n", hostOrFQDN)