package cmd import ( "fmt" "os" "strings" "time" "github.com/charmbracelet/huh" "github.com/pquerna/otp/totp" cli "github.com/urfave/cli/v2" "aws-mgmt/pkg/client" ) const secretsDesc = `View secrets from AWS Secrets Manager.` var SecretsApp = &cli.App{ Name: "secrets", Usage: "view secrets", UsageText: "secrets [options]", HideHelpCommand: true, Args: true, ArgsUsage: "[secret]", Action: secretsFunc, Description: secretsDesc, Flags: flags, } var SecretsCommand = &cli.Command{ Name: "secrets", Usage: "view secrets", UsageText: "secrets [options]", HideHelpCommand: true, Args: true, ArgsUsage: "[secret]", Action: secretsFunc, Description: secretsDesc, Flags: flags, } var flags = []cli.Flag{ &cli.BoolFlag{ Name: "sh", Usage: "Print the equivalent AWS CLI / shell command(s) to stderr", }, &cli.StringSliceFlag{ Name: "tags", Usage: "Specify tags to filter secrets, like --tags type=totp", }, &cli.BoolFlag{ Name: "totp", Usage: "Generate a MFA token based on the secret value", }, } func secretsFunc(c *cli.Context) error { // create aws config cfg, err := client.CreateAWSConfig() if err != nil { return err } awsClient := client.NewAWSClient( client.SetConfig(cfg), ) // get hostname & domain secret := c.Args().Get(0) tags := parseTags(c.StringSlice("tags")) if secret == "" { secrets, err := awsClient.ListSecrets(tags) if err != nil { return err } if c.Bool("sh") { str := `aws secretsmanager list-secrets --query 'SecretList[].[Name,Description]' --output text | sort` fmt.Fprintln(os.Stderr, str) } if len(secrets) == 0 { return fmt.Errorf("no secrets found") } secret, err = selectSecretDialog(secrets) if err != nil { return err } } // get secret value for secretName secretValue, err := awsClient.GetSecretValue(secret) if err != nil { return err } // if the totp flag is set, generate a token if c.Bool("totp") { token, err := totp.GenerateCode(secretValue, time.Now()) if err != nil { return err } fmt.Println(token) } else { // print the aws cli equivalent command to output this secret to stderr if c.Bool("sh") { fmt.Fprintln(os.Stderr, fmt.Sprintf("aws secretsmanager get-secret-value --secret-id %s --query SecretString --output text --no-cli-pager", secret)) } fmt.Println(secretValue) } return nil } func parseTags(rawTags []string) map[string]string { tags := make(map[string]string) for _, tag := range rawTags { parts := strings.SplitN(tag, "=", 2) if len(parts) == 2 { tags[parts[0]] = parts[1] } } return tags } // selectSecretDialog prompts the user to select a secret from a list of SecretListEntry func selectSecretDialog(secretList []client.SecretListEntry) (string, error) { // create a select prompt for the user to choose a secret var secretName string options := make([]huh.Option[string], len(secretList)) // options := make([]huh.Option, len(secretList)) for i, secret := range secretList { // create a new option for each secret options[i] = huh.NewOption[string](strings.TrimSuffix(fmt.Sprintf("%s: %s", secret.Name, secret.Description), ": "), secret.Name) } huh.NewSelect[string](). Title("Select a secret"). Options(options...). Value(&secretName). Run() return secretName, nil }