diff --git a/build.assets/charts/Dockerfile-distroless b/build.assets/charts/Dockerfile-distroless index afc9ef481d768..3df8ee5f4f56d 100644 --- a/build.assets/charts/Dockerfile-distroless +++ b/build.assets/charts/Dockerfile-distroless @@ -33,6 +33,7 @@ FROM $BASE_IMAGE COPY --from=teleport /opt/staging / COPY --from=staging /opt/staging/root / COPY --from=staging /opt/staging/status /var/lib/dpkg/status.d +ENV TELEPORT_TOOLS_VERSION=off # Attempt a graceful shutdown by default # See https://goteleport.com/docs/reference/signals/ for signal reference. STOPSIGNAL SIGQUIT diff --git a/lib/autoupdate/tools/helper.go b/lib/autoupdate/tools/helper.go index f2e45b286d052..bad8752e5123f 100644 --- a/lib/autoupdate/tools/helper.go +++ b/lib/autoupdate/tools/helper.go @@ -69,6 +69,12 @@ func newUpdater(toolsDir string) (*Updater, error) { // If they differ, the requested version is downloaded and extracted into the client tools directory, // the installation is recorded in the configuration file, and the tool is re-executed with the updated version. func CheckAndUpdateLocal(ctx context.Context, currentProfileName string, reExecArgs []string) error { + // If client tools updates are explicitly disabled, we want to catch this as soon as possible + // so we don't try to read te user home directory, fail, and log warnings. + if os.Getenv(teleportToolsVersionEnv) == teleportToolsVersionEnvDisabled { + return nil + } + var err error if currentProfileName == "" { home := os.Getenv(types.HomeEnvVar) @@ -84,18 +90,20 @@ func CheckAndUpdateLocal(ctx context.Context, currentProfileName string, reExecA toolsDir, err := Dir() if err != nil { - slog.WarnContext(ctx, "Client tools update is disabled", "error", err) + slog.WarnContext(ctx, "Failed to detect the teleport home directory, client tools updates are disabled", "error", err) return nil } updater, err := newUpdater(toolsDir) if err != nil { - return trace.Wrap(err) + slog.WarnContext(ctx, "Failed to create the updater, client tools updates are disabled", "error", err) + return nil } slog.DebugContext(ctx, "Attempting to local update", "current_profile_name", currentProfileName) resp, err := updater.CheckLocal(ctx, currentProfileName) if err != nil { - return trace.Wrap(err) + slog.WarnContext(ctx, "Failed to check local teleport versions, client tools updates are disabled", "error", err) + return nil } if resp.ReExec { @@ -117,20 +125,28 @@ func CheckAndUpdateLocal(ctx context.Context, currentProfileName string, reExecA // the installed version is recorded in the configuration, and the tool is re-executed // with the updated version. func CheckAndUpdateRemote(ctx context.Context, currentProfileName string, insecure bool, reExecArgs []string) error { + // If client tools updates are explicitly disabled, we want to catch this as soon as possible + // so we don't try to read te user home directory, fail, and log warnings. + if os.Getenv(teleportToolsVersionEnv) == teleportToolsVersionEnvDisabled { + return nil + } + toolsDir, err := Dir() if err != nil { - slog.WarnContext(ctx, "Client tools update is disabled", "error", err) + slog.WarnContext(ctx, "Failed to detect the teleport home directory, client tools updates are disabled", "error", err) return nil } updater, err := newUpdater(toolsDir) if err != nil { - return trace.Wrap(err) + slog.WarnContext(ctx, "Failed to create the updater, client tools updates are disabled", "error", err) + return nil } slog.DebugContext(ctx, "Attempting to remote update", "current_profile_name", currentProfileName, "insecure", insecure) resp, err := updater.CheckRemote(ctx, currentProfileName, insecure) if err != nil { - return trace.Wrap(err) + slog.WarnContext(ctx, "Failed to check remote teleport versions, client tools updates are disabled", "error", err) + return nil } if !resp.Disabled && resp.ReExec { diff --git a/lib/autoupdate/tools/updater.go b/lib/autoupdate/tools/updater.go index 4f439ba03bcb4..1d470e586d131 100644 --- a/lib/autoupdate/tools/updater.go +++ b/lib/autoupdate/tools/updater.go @@ -52,6 +52,9 @@ import ( const ( // teleportToolsVersionEnv is environment name for requesting specific version for update. teleportToolsVersionEnv = "TELEPORT_TOOLS_VERSION" + // teleportToolsVersionEnvDisabled is a special value that disables teleport tools updates + // when assigned to the teleportToolsVersionEnv environment variable. + teleportToolsVersionEnvDisabled = "off" // teleportToolsVersionReExecEnv is internal environment name for transferring original // version to re-executed ones. teleportToolsVersionReExecEnv = "TELEPORT_TOOLS_VERSION_REEXEC" @@ -150,7 +153,7 @@ func (u *Updater) CheckLocal(ctx context.Context, profileName string) (resp *Upd requestedVersion := os.Getenv(teleportToolsVersionEnv) switch requestedVersion { // The user has turned off any form of automatic updates. - case "off": + case teleportToolsVersionEnvDisabled: return &UpdateResponse{Version: "", ReExec: false}, nil // Requested version already the same as client version. case u.localVersion: @@ -213,7 +216,7 @@ func (u *Updater) CheckRemote(ctx context.Context, proxyAddr string, insecure bo requestedVersion := os.Getenv(teleportToolsVersionEnv) switch requestedVersion { // The user has turned off any form of automatic updates. - case "off": + case teleportToolsVersionEnvDisabled: return &UpdateResponse{Version: "", ReExec: false}, nil // Requested version already the same as client version. case u.localVersion: @@ -427,7 +430,7 @@ func (u *Updater) Exec(ctx context.Context, toolsVersion string, args []string) if err := os.Unsetenv(teleportToolsVersionEnv); err != nil { return 0, trace.Wrap(err) } - env = append(env, teleportToolsVersionEnv+"=off") + env = append(env, teleportToolsVersionEnv+"="+teleportToolsVersionEnvDisabled) slog.DebugContext(ctx, "Disable next re-execution") } env = append(env, fmt.Sprintf("%s=%s", teleportToolsVersionReExecEnv, u.localVersion)) diff --git a/lib/autoupdate/tools/utils.go b/lib/autoupdate/tools/utils.go index dcd9b1f06ebda..0a32aee531ddd 100644 --- a/lib/autoupdate/tools/utils.go +++ b/lib/autoupdate/tools/utils.go @@ -113,7 +113,7 @@ func CheckToolVersion(toolPath string) (string, error) { // Execute "{tsh, tctl} version" and pass in TELEPORT_TOOLS_VERSION=off to // turn off all automatic updates code paths to prevent any recursion. command := exec.CommandContext(ctx, toolPath, "version") - command.Env = []string{teleportToolsVersionEnv + "=off"} + command.Env = []string{teleportToolsVersionEnv + "=" + teleportToolsVersionEnvDisabled} output, err := command.Output() if err != nil { slog.DebugContext(context.Background(), "failed to determine version",