diff --git a/internal/app/config.go b/internal/app/config.go index 6c7b7a89..41b55fb6 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -42,6 +42,8 @@ func AddHistoryLocationItems(cs config.ConfigurationSet) error { return fmt.Errorf("adding history-location config: %w", err) } + cs.SetHistoryIgnore("history-location") //nolint + return nil } @@ -64,6 +66,10 @@ func AddHistoryConfigItems(cs config.ConfigurationSet) error { return fmt.Errorf("setting entry-id hidden: %w", err) } + cs.SetHistoryIgnore("max-history") //nolint + cs.SetHistoryIgnore("no-history") //nolint + cs.SetHistoryIgnore("entry-id") //nolint + return nil } @@ -111,6 +117,11 @@ func AddCommonConfigItems(cs config.ConfigurationSet) error { return fmt.Errorf("setting shorthand for log-level: %w", err) } + cs.SetHistoryIgnore("config") //nolint + cs.SetHistoryIgnore("log-level") //nolint + cs.SetHistoryIgnore("log-format") //nolint + cs.SetHistoryIgnore("non-interactive") //nolint + return nil } @@ -122,6 +133,9 @@ func AddHistoryIdentifierConfig(cs config.ConfigurationSet) error { return fmt.Errorf("adding id config: %w", err) } + cs.SetHistoryIgnore("alias") //nolint + cs.SetHistoryIgnore("id") //nolint + return nil } @@ -140,6 +154,10 @@ func AddHistoryQueryConfig(cs config.ConfigurationSet) error { return fmt.Errorf("adding provider-id config: %w", err) } + cs.SetHistoryIgnore("cluster-provider") //nolint + cs.SetHistoryIgnore("identity-provider") //nolint + cs.SetHistoryIgnore("provider-id") //nolint + return nil } diff --git a/internal/app/use.go b/internal/app/use.go index 4d5ad76c..d346fc94 100644 --- a/internal/app/use.go +++ b/internal/app/use.go @@ -147,20 +147,13 @@ func (a *App) getCluster(params *UseParams) (*provider.Cluster, error) { func (a *App) filterConfig(params *UseParams) map[string]string { filteredConfig := make(map[string]string) - idConfigSet := params.IdentityProvider.ConfigurationItems() - discConfigSet := params.Provider.ConfigurationItems() - commonIDConfigSet := provider.CommonIdentityConfig() - for _, configItem := range params.Context.ConfigurationItems().GetAll() { - cmnConfig := commonIDConfigSet.Get(configItem.Name) - idConfig := idConfigSet.Get(configItem.Name) - discConfig := discConfigSet.Get(configItem.Name) - if cmnConfig == nil && idConfig == nil && discConfig == nil { + if configItem.Sensitive { continue } - if configItem.Sensitive { + if configItem.HistoryIgnore { continue } diff --git a/internal/commands/configure/configure.go b/internal/commands/configure/configure.go index bf2cc79f..379c895a 100644 --- a/internal/commands/configure/configure.go +++ b/internal/commands/configure/configure.go @@ -89,5 +89,8 @@ func addConfig(cs config.ConfigurationSet) error { return fmt.Errorf("setting shorthand for file config item: %w", err) } + cs.SetHistoryIgnore("file") //nolint + cs.SetHistoryIgnore("output") //nolint + return nil } diff --git a/internal/commands/ls/ls.go b/internal/commands/ls/ls.go index 91767157..c6cb6a83 100644 --- a/internal/commands/ls/ls.go +++ b/internal/commands/ls/ls.go @@ -102,5 +102,7 @@ func addConfig(cs config.ConfigurationSet) error { return fmt.Errorf("adding output config item: %w", err) } + cs.SetHistoryIgnore("output") //nolint + return nil } diff --git a/internal/commands/root.go b/internal/commands/root.go index 8615d2bf..b0fc0d98 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -101,7 +101,7 @@ func RootCmd() (*cobra.Command, error) { cobra.OnInitialize(initConfig) - // Forge initial parsing of flags + // Force initial parsing of flags rootCmd.FParseErrWhitelist = cobra.FParseErrWhitelist{ UnknownFlags: true, } diff --git a/internal/commands/to/to.go b/internal/commands/to/to.go index ff81f487..0476a29e 100644 --- a/internal/commands/to/to.go +++ b/internal/commands/to/to.go @@ -108,5 +108,8 @@ func addConfig(cs config.ConfigurationSet) error { return fmt.Errorf("adding kubeconfig config items: %w", err) } + cs.SetHistoryIgnore("password") //nolint + cs.SetSensitive("password") //nolint + return nil } diff --git a/internal/commands/use/use.go b/internal/commands/use/use.go index d76fe7d5..48efb0cd 100644 --- a/internal/commands/use/use.go +++ b/internal/commands/use/use.go @@ -154,6 +154,8 @@ func addConfig(cs config.ConfigurationSet, clusterProvider provider.ClusterProvi return fmt.Errorf("adding kubeconfig config items: %w", err) } + cs.SetHistoryIgnore("set-current") //nolint + return nil } diff --git a/pkg/config/configset.go b/pkg/config/configset.go index 62a2cae1..ac6f3130 100644 --- a/pkg/config/configset.go +++ b/pkg/config/configset.go @@ -29,8 +29,8 @@ type Item struct { Name string Shorthand string Type ItemType - Sensitive bool Description string + Sensitive bool ResolutionPrompt string Value interface{} DefaultValue interface{} @@ -38,6 +38,7 @@ type Item struct { Hidden bool Deprecated bool DeprecatedMessage string + HistoryIgnore bool } func (i *Item) HasValue() bool { @@ -72,6 +73,7 @@ type ConfigurationSet interface { Add(item *Item) error AddSet(set ConfigurationSet) error SetSensitive(name string) error + SetHistoryIgnore(name string) error SetRequired(name string) error SetHidden(name string) error SetDeprecated(name string, message string) error @@ -156,6 +158,17 @@ func (s *configSet) SetSensitive(name string) error { return nil } +func (s *configSet) SetHistoryIgnore(name string) error { + item := s.Get(name) + if item == nil { + return ErrConfigNotFound + } + + item.HistoryIgnore = true + + return nil +} + func (s *configSet) SetRequired(name string) error { item := s.Get(name) if item == nil { diff --git a/pkg/plugins/discovery/aws/provider.go b/pkg/plugins/discovery/aws/provider.go index 4a9479ab..b4d9949f 100644 --- a/pkg/plugins/discovery/aws/provider.go +++ b/pkg/plugins/discovery/aws/provider.go @@ -78,6 +78,8 @@ func (p *eksClusterProvider) ConfigurationItems() config.ConfigurationSet { cs.SetRequired("region") //nolint: errcheck cs.SetRequired("partition") //nolint: errcheck + cs.SetHidden("profile") //nolint: errcheck + return cs } diff --git a/pkg/plugins/identity/saml/saml.go b/pkg/plugins/identity/saml/saml.go index 36ea7b38..30e7df26 100644 --- a/pkg/plugins/identity/saml/saml.go +++ b/pkg/plugins/identity/saml/saml.go @@ -106,22 +106,6 @@ func (p *samlIdentityProvider) Authenticate(ctx *provider.Context, clusterProvid return nil, ErrCreatingAccount } - exist, err := p.store.CredsExists() - if err != nil { - return nil, fmt.Errorf("checking if creds exist: %w", err) - } - if exist { - if !p.store.Expired() && !p.config.Force { - p.logger.Info("using cached creds") - id, err := p.store.Load() - if err != nil { - return nil, fmt.Errorf("loading identity: %w", err) - } - return id, nil - } - p.logger.Info("cached creds expired or force enabled, renewing") - } - err = account.Validate() if err != nil { return nil, fmt.Errorf("validating saml: %w", err) @@ -147,7 +131,7 @@ func (p *samlIdentityProvider) Authenticate(ctx *provider.Context, clusterProvid return nil, ErrNoSAMLAssertions } - userID, err := p.serviceProvider.ProcessAssertions(account, samlAssertion) + userID, err := p.serviceProvider.ProcessAssertions(account, samlAssertion, ctx.ConfigurationItems()) if err != nil { return nil, fmt.Errorf("processing assertions for: %s: %w", clusterProvider, err) } @@ -204,11 +188,9 @@ func (p *samlIdentityProvider) createAccount(cs config.ConfigurationSet) (*cfg.I func (p *samlIdentityProvider) resolveConfig(ctx *provider.Context) error { sp := p.serviceProvider - if ctx.IsInteractive() { - p.logger.Debug("running interactively, resolving SAML provider flags") - if err := sp.ResolveConfiguration(ctx.ConfigurationItems()); err != nil { - return fmt.Errorf("resolving flags: %w", err) - } + p.logger.Debug("resolving SAML provider flags") + if err := sp.ResolveConfiguration(ctx.ConfigurationItems(), ctx.IsInteractive()); err != nil { + return fmt.Errorf("resolving flags: %w", err) } return nil diff --git a/pkg/plugins/identity/saml/sp/aws/provider.go b/pkg/plugins/identity/saml/sp/aws/provider.go index 8c0a533d..841a0860 100644 --- a/pkg/plugins/identity/saml/sp/aws/provider.go +++ b/pkg/plugins/identity/saml/sp/aws/provider.go @@ -94,7 +94,7 @@ func (p *ServiceProvider) PopulateAccount(account *cfg.IDPAccount, cfg config.Co return nil } -func (p *ServiceProvider) ProcessAssertions(account *cfg.IDPAccount, samlAssertions string) (provider.Identity, error) { +func (p *ServiceProvider) ProcessAssertions(account *cfg.IDPAccount, samlAssertions string, cfg config.ConfigurationSet) (provider.Identity, error) { data, err := base64.StdEncoding.DecodeString(samlAssertions) if err != nil { return nil, fmt.Errorf("decoding SAMLAssertion: %w", err) @@ -119,7 +119,10 @@ func (p *ServiceProvider) ProcessAssertions(account *cfg.IDPAccount, samlAsserti return nil, fmt.Errorf("resolving aws role: %w", err) } - log.Printf("selected role: %s", role.RoleARN) + if err := cfg.SetValue("role-arn", role.RoleARN); err != nil { + return nil, fmt.Errorf("setting role-arn config value: %w", err) + } + p.logger.Debugf("selected role: %s", role.RoleARN) awsCreds, err := p.loginToStsUsingRole(account, role, samlAssertions) if err != nil { diff --git a/pkg/plugins/identity/saml/sp/aws/resolver.go b/pkg/plugins/identity/saml/sp/aws/resolver.go index 71f665a3..f57b9f91 100644 --- a/pkg/plugins/identity/saml/sp/aws/resolver.go +++ b/pkg/plugins/identity/saml/sp/aws/resolver.go @@ -19,6 +19,7 @@ package aws import ( "fmt" "sort" + "time" survey "github.com/AlecAivazis/survey/v2" "github.com/aws/aws-sdk-go/aws/endpoints" @@ -26,11 +27,23 @@ import ( "github.com/fidelity/kconnect/pkg/config" ) +const ( + profilePrefix = "kconnect-" +) + // ResolveConfiguration will resolve the values for the AWS specific config items that have no value. // It will query AWS and interactively ask the user for selections. -func (p *ServiceProvider) ResolveConfiguration(cfg config.ConfigurationSet) error { +func (p *ServiceProvider) ResolveConfiguration(cfg config.ConfigurationSet, interactive bool) error { p.logger.Debug("resolving AWS identity configuration items") + if err := p.resolveProfile("profile", cfg); err != nil { + return fmt.Errorf("resolving profile: %w", err) + } + + if !interactive { + return nil + } + // NOTE: resolution is only needed for required fields if err := p.resolveIdpProvider("idp-provider", cfg); err != nil { return fmt.Errorf("resolving idp-provider: %w", err) @@ -38,9 +51,7 @@ func (p *ServiceProvider) ResolveConfiguration(cfg config.ConfigurationSet) erro if err := p.resolveIdpEndpoint("idp-endpoint", cfg); err != nil { return fmt.Errorf("resolving idp-endpoint: %w", err) } - if err := p.resolveProfile("profile", cfg); err != nil { - return fmt.Errorf("resolving profile: %w", err) - } + if err := p.resolvePartition("partition", cfg); err != nil { return fmt.Errorf("resolving partition: %w", err) } @@ -62,18 +73,14 @@ func (p *ServiceProvider) resolveProfile(name string, cfg config.ConfigurationSe return nil } - profile := "" - prompt := &survey.Input{ - Message: "Enter the name of AWS profile", - } - if err := survey.AskOne(prompt, &profile, survey.WithValidator(survey.Required)); err != nil { - return fmt.Errorf("asking for profile name: %w", err) - } + now := time.Now().UTC() + profileName := fmt.Sprintf("%s%s", profilePrefix, now.Format("20060102150405")) - if err := cfg.SetValue(name, profile); err != nil { - p.logger.Errorf("failed setting profile config to %s: %s", profile, err.Error()) + if err := cfg.SetValue(name, profileName); err != nil { + p.logger.Errorf("failed setting profile config to %s: %s", profileName, err.Error()) return fmt.Errorf("setting profile config: %w", err) } + p.logger.Debugf("created AWS profile name: %s", profileName) return nil } diff --git a/pkg/plugins/identity/saml/sp/types.go b/pkg/plugins/identity/saml/sp/types.go index dbf7c21e..78c0b8d8 100644 --- a/pkg/plugins/identity/saml/sp/types.go +++ b/pkg/plugins/identity/saml/sp/types.go @@ -31,7 +31,7 @@ type ProviderConfig struct { type ServiceProvider interface { Validate(configItems config.ConfigurationSet) error - ResolveConfiguration(configItems config.ConfigurationSet) error + ResolveConfiguration(configItems config.ConfigurationSet, interactive bool) error PopulateAccount(account *cfg.IDPAccount, configItems config.ConfigurationSet) error - ProcessAssertions(account *cfg.IDPAccount, samlAssertions string) (provider.Identity, error) + ProcessAssertions(account *cfg.IDPAccount, samlAssertions string, configItems config.ConfigurationSet) (provider.Identity, error) } diff --git a/pkg/provider/config.go b/pkg/provider/config.go index ade434b0..b8eb1b48 100644 --- a/pkg/provider/config.go +++ b/pkg/provider/config.go @@ -38,7 +38,6 @@ type ClusterProviderConfig struct { type IdentityProviderConfig struct { Username string `json:"username" validate:"required"` Password string `json:"password" validate:"required"` - Force bool `json:"force"` IdpProtocol string `json:"idp-protocol" validate:"required"` } @@ -60,6 +59,8 @@ func AddCommonClusterConfig(cs config.ConfigurationSet) error { return fmt.Errorf("setting alias as sensitive: %w", err) } + cs.SetHistoryIgnore("alias") //nolint + return nil } @@ -77,11 +78,10 @@ func AddCommonIdentityConfig(cs config.ConfigurationSet) error { // CommonIdentityConfig creates a configset with the common identity config items func CommonIdentityConfig() config.ConfigurationSet { cs := config.NewConfigurationSet() - cs.String("username", "", "the username used for authentication") //nolint: errcheck - cs.String("password", "", "the password to use for authentication") //nolint: errcheck - cs.Bool("force", false, "If true then we force authentication every invocation") //nolint: errcheck - cs.String("idp-protocol", "", "the idp protocol to use (e.g. saml)") //nolint: errcheck - cs.SetSensitive("password") //nolint: errcheck + cs.String("username", "", "the username used for authentication") //nolint: errcheck + cs.String("password", "", "the password to use for authentication") //nolint: errcheck + cs.String("idp-protocol", "", "the idp protocol to use (e.g. saml)") //nolint: errcheck + cs.SetSensitive("password") //nolint: errcheck return cs }