158 lines
3.5 KiB
Go
158 lines
3.5 KiB
Go
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: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "totp",
|
|
Usage: "Generate a MFA token based on the secret value",
|
|
},
|
|
&cli.StringSliceFlag{
|
|
Name: "tags",
|
|
Usage: "Tags in the format key=value",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "sh",
|
|
Usage: "Print the equivalent AWS CLI / shell command(s)",
|
|
},
|
|
},
|
|
}
|
|
|
|
var SecretsCommand = &cli.Command{
|
|
Name: "secrets",
|
|
Usage: "view secrets",
|
|
UsageText: "secrets [options]",
|
|
HideHelpCommand: true,
|
|
Args: true,
|
|
ArgsUsage: "[secret]",
|
|
Action: secretsFunc,
|
|
Description: secretsDesc,
|
|
Flags: []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: "totp",
|
|
Usage: "Return a MFA token",
|
|
},
|
|
&cli.StringSliceFlag{
|
|
Name: "tags",
|
|
Usage: "Tags in the format key=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
|
|
|
|
}
|