From c229f4d5d86143712c100d6fba558024681f832e Mon Sep 17 00:00:00 2001 From: Stefan Koelle <50440224+skoelle@users.noreply.github.com> Date: Sun, 9 Aug 2026 12:37:51 +0200 Subject: [PATCH] Add AWS auth check (sts get-caller-identity) and configurable SSO login command --- config.example.yaml | 7 +++++++ internal/config/config.go | 20 ++++++++++++++++++-- internal/kubeexec/kubeexec.go | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index d5ebffb..edd50bd 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -17,3 +17,10 @@ context_pairs: # team-selection screen. Adjust this to whatever label your organization # actually uses (can contain a domain prefix, e.g. "example.org/team"). team_label_key: "example.org/team" + +# Command used to (re-)authenticate with AWS before the Secrets workflow, +# if 'aws sts get-caller-identity' fails (e.g. an expired AWS SSO session). +# Defaults to "aws sso login" if omitted. Override this if your organization +# wraps SSO login in a custom script or needs a specific --profile, e.g.: +# aws_sso_login_command: "aws sso login --profile my-profile" +aws_sso_login_command: "aws sso login" diff --git a/internal/config/config.go b/internal/config/config.go index b98091f..56a5701 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -11,10 +11,26 @@ import ( "github.com/skoelle/kctl-tui/internal/kctl" ) +// DefaultAWSSSOLoginCommand is used when the user has not configured a +// custom login command in their config.yaml. +const DefaultAWSSSOLoginCommand = "aws sso login" + // Config is the root structure of ~/.kctl-tui/config.yaml type Config struct { - ContextPairs []kctl.ContextPair `yaml:"context_pairs"` - TeamLabelKey string `yaml:"team_label_key"` + ContextPairs []kctl.ContextPair `yaml:"context_pairs"` + TeamLabelKey string `yaml:"team_label_key"` + AWSSSOLoginCommand string `yaml:"aws_sso_login_command"` +} + +// LoginCommand returns the configured AWS SSO login command, falling back +// to DefaultAWSSSOLoginCommand if none is set. Organizations that wrap +// SSO login in a custom script (e.g. to select a specific profile) can +// override this via aws_sso_login_command in config.yaml. +func (c Config) LoginCommand() string { + if c.AWSSSOLoginCommand == "" { + return DefaultAWSSSOLoginCommand + } + return c.AWSSSOLoginCommand } // DefaultPath returns the default config file location: ~/.kctl-tui/config.yaml diff --git a/internal/kubeexec/kubeexec.go b/internal/kubeexec/kubeexec.go index 07b6731..783e800 100644 --- a/internal/kubeexec/kubeexec.go +++ b/internal/kubeexec/kubeexec.go @@ -184,3 +184,23 @@ func GetAWSSecretString(secretID, region string) (string, error) { "--secret-id", secretID, "--region", region, "--query", "SecretString", "--output", "text") } + +// CheckAWSAuth performs a cheap, fast call to verify the current AWS +// credentials/SSO session are valid. Returns nil if authenticated, or the +// underlying error (e.g. an expired SSO session) otherwise. +func CheckAWSAuth() error { + _, err := runOutput("aws", "sts", "get-caller-identity", "--query", "Account", "--output", "text") + return err +} + +// RunAWSLogin returns an *exec.Cmd for the given login command (e.g. +// "aws sso login"), split on whitespace. The caller is responsible for +// running it interactively (e.g. via tea.ExecProcess) since SSO login +// typically requires opening a browser and confirming a device code. +func RunAWSLogin(loginCommand string) *exec.Cmd { + parts := strings.Fields(loginCommand) + if len(parts) == 0 { + parts = []string{"aws", "sso", "login"} + } + return exec.Command(parts[0], parts[1:]...) +}