diff --git a/.gitignore b/.gitignore index ce47fcc..eef317c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ dist/ .vscode .env* !.env.example +bin/ +.idea diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 107819b..47a3be8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,13 +63,15 @@ $ git checkout -b feature_x (make your changes) $ git status $ git add -$ git commit -m "descriptive commit message for your changes" +$ git commit -S -m "descriptive commit message for your changes" ``` > The `-b` specifies that you want to create a new branch called `feature_x`. > You only specify `-b` the first time you checkout because you are creating a > new branch. Once the `feature_x` branch exists, you can later switch to it > with only `git checkout feature_x`. +> The `-S` on the commit signs the commit. Please ensure you follow the instructions on +> [https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) Rebase `feature_x` to include updates from `upstream/master` diff --git a/README.md b/README.md index b817fa4..d6378ba 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ format. - [Non-Admin Users](#non-admin-users) - [M2M Command](#m2m-command) - [M2M Command Requirements](#m2m-command-requirements) + - [List-Profiles Command](#list-profiles-command) - [Configuration](#configuration) - [Global settings](#global-settings) - [Web command settings](#web-command-settings) @@ -70,6 +71,7 @@ format. | (empty) | When `okta-aws-cli` is executed without a subcommand and without arguments it will print the online help and exit. | | `web` | Human oriented retrieval of temporary IAM credentials through Okta authentication and device authorization. Note: if `okta-aws-cli` is not given a subcommand it defaults to this original `web` command when other arguments are present. | | `m2m` | Machine/headless oriented retrieval of temporary IAM credentials through Okta authentication with a private key. IMPORTANT! This a not a feature intended for a human use case. Be sure to use industry state of the art secrets management techniques with the private key. | +| `list-profiles` | Lists profile names in ~/.okta/okta.yaml. | | `debug` | Debug okta.yaml config file and exit. | ## Web Command @@ -319,6 +321,20 @@ role of the `sts:AssumeRoleWithWebIdentity` action type. This setting is on the trust relationship tab when viewing a specific role in the AWS Console. Also note the ARNs of these roles for later use. +## List-Profiles Command + +```shell +$ okta-aws-cli list-profiles +Profiles: + + sample-account X(Non-Prod) + sample-account X (Prod) + another-sample-account Y (Non-Prod) +``` + +List-profiles command is a human oriented command to show the list of profile names stored in the ~/.okta/okta.yaml file. The user +executes `okta-aws-cli list-profiles` where a list of profile name shall be listed for convenience. The names will be indented. + ## Configuration ### Global settings diff --git a/cmd/root/profileslist/profiles-list.go b/cmd/root/profileslist/profiles-list.go new file mode 100644 index 0000000..8194f22 --- /dev/null +++ b/cmd/root/profileslist/profiles-list.go @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023-Present, Okta, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package profileslist + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/okta/okta-aws-cli/internal/config" +) + +// NewProfilesListCommand Sets up the debug cobra sub command +func NewProfilesListCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-profiles", + Short: "Lists profile names in ~/.okta/okta.yaml", + RunE: func(cmd *cobra.Command, args []string) error { + config, err := config.EvaluateSettings() + if err != nil { + return err + } + + fmt.Println("Profiles:") + + keys, err := config.ReadConfigProfileKeys() + if err != nil { + return err + } + + for _, key := range keys { + fmt.Printf(" %s\n", key) + } + + return nil + }, + } + + return cmd +} diff --git a/cmd/root/root.go b/cmd/root/root.go index 01fefaf..3936d57 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -21,6 +21,8 @@ import ( "os" "path/filepath" + "github.com/okta/okta-aws-cli/cmd/root/profileslist" + "github.com/spf13/cobra" debugCmd "github.com/okta/okta-aws-cli/cmd/root/debug" @@ -157,6 +159,8 @@ func init() { rootCmd.AddCommand(m2mCmd) debugCfgCmd := debugCmd.NewDebugCommand() rootCmd.AddCommand(debugCfgCmd) + listProfilesCmd := profileslist.NewProfilesListCommand() + rootCmd.AddCommand(listProfilesCmd) } // NewRootCommand Sets up the root cobra command diff --git a/internal/config/config.go b/internal/config/config.go index 395cb9e..2b6a447 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -370,7 +370,7 @@ func NewConfig(attrs *Attributes) (*Config, error) { return cfg, nil } -func getFlagNameFromProfile(awsProfile string, flag string) string { +func getFlagNameFromProfile(awsProfile, flag string) string { profileKey := fmt.Sprintf("%s.%s", awsProfile, flag) if awsProfile != "" && viper.IsSet(profileKey) && viper.Get(profileKey) != "" { // NOTE: If the flag was from a multiple profiles keyed by aws profile @@ -384,6 +384,23 @@ func getFlagNameFromProfile(awsProfile string, flag string) string { return flag } +// ReadConfigProfileKeys returns the config profile names +func (c *Config) ReadConfigProfileKeys() ([]string, error) { + // Side loading multiple profiles from okta.yaml file if it exists + if oktaConfig, err := OktaConfig(); err == nil { + profiles := oktaConfig.AWSCLI.PROFILES + + keys := make([]string, 0, len(profiles)) + + for k := range profiles { + keys = append(keys, k) + } + return keys, err + } + + return nil, nil +} + func readConfig() (Attributes, error) { // Side loading multiple profiles from okta.yaml file if it exists if oktaConfig, err := OktaConfig(); err == nil { diff --git a/internal/output/aws_credentials_file.go b/internal/output/aws_credentials_file.go index 69c08e8..7363574 100644 --- a/internal/output/aws_credentials_file.go +++ b/internal/output/aws_credentials_file.go @@ -41,7 +41,7 @@ const ( ) // ensureConfigExists verify that the config file exists -func ensureConfigExists(filename string, profile string) error { +func ensureConfigExists(filename, profile string) error { if _, err := os.Stat(filename); err != nil { if errors.Is(err, os.ErrNotExist) { dir := filepath.Dir(filename) @@ -65,7 +65,7 @@ func ensureConfigExists(filename string, profile string) error { return nil } -func saveProfile(filename, profile string, cfc *oaws.CredsFileCredential, legacyVars, expiryVars bool, expiry string, regionVar string) error { +func saveProfile(filename, profile string, cfc *oaws.CredsFileCredential, legacyVars, expiryVars bool, expiry, regionVar string) error { config, err := updateConfig(filename, profile, cfc, legacyVars, expiryVars, expiry, regionVar) if err != nil { return err @@ -80,7 +80,7 @@ func saveProfile(filename, profile string, cfc *oaws.CredsFileCredential, legacy return nil } -func updateConfig(filename, profile string, cfc *oaws.CredsFileCredential, legacyVars, expiryVars bool, expiry string, region string) (config *ini.File, err error) { +func updateConfig(filename, profile string, cfc *oaws.CredsFileCredential, legacyVars, expiryVars bool, expiry, region string) (config *ini.File, err error) { config, err = ini.Load(filename) if err != nil { return @@ -131,7 +131,7 @@ func updateConfig(filename, profile string, cfc *oaws.CredsFileCredential, legac // updateIni will comment out any keys that are not "aws_access_key_id", // "aws_secret_access_key", "aws_session_token", "credential_process" -func updateINI(config *ini.File, profile string, legacyVars bool, expiryVars bool, region string) (*ini.File, error) { +func updateINI(config *ini.File, profile string, legacyVars, expiryVars bool, region string) (*ini.File, error) { ignore := []string{ "aws_access_key_id", "aws_secret_access_key", @@ -184,7 +184,7 @@ type AWSCredentialsFile struct { } // NewAWSCredentialsFile Creates a new -func NewAWSCredentialsFile(legacyVars bool, expiryVars bool, expiry string) *AWSCredentialsFile { +func NewAWSCredentialsFile(legacyVars, expiryVars bool, expiry string) *AWSCredentialsFile { return &AWSCredentialsFile{ LegacyAWSVariables: legacyVars, ExpiryAWSVariables: expiryVars, diff --git a/internal/paginator/paginator.go b/internal/paginator/paginator.go index c80d858..3b156fc 100644 --- a/internal/paginator/paginator.go +++ b/internal/paginator/paginator.go @@ -59,7 +59,7 @@ type Paginator struct { } // NewPaginator Paginator constructor -func NewPaginator(httpClient *http.Client, url *url.URL, headers *map[string]string, params *map[string]string) *Paginator { +func NewPaginator(httpClient *http.Client, url *url.URL, headers, params *map[string]string) *Paginator { pgntr := Paginator{ httpClient: httpClient, url: url,