github.com/influxdata/telegraf@v1.30.3/cmd/telegraf/cmd_secretstore.go (about)

     1  // Command handling for secret-stores' "secrets" command
     2  package main
     3  
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/awnumar/memguard"
    12  	"github.com/urfave/cli/v2"
    13  	"golang.org/x/term"
    14  )
    15  
    16  func processFilterOnlySecretStoreFlags(ctx *cli.Context) Filters {
    17  	sectionFilters := []string{"inputs", "outputs", "processors", "aggregators"}
    18  	inputFilters := []string{"-"}
    19  	outputFilters := []string{"-"}
    20  	processorFilters := []string{"-"}
    21  	aggregatorFilters := []string{"-"}
    22  
    23  	// Only load the secret-stores
    24  	var secretstore string
    25  	if len(ctx.Lineage()) >= 2 {
    26  		parent := ctx.Lineage()[1] // ancestor contexts in order from child to parent
    27  		secretstore = parent.String("secretstore-filter")
    28  	}
    29  
    30  	// If both the parent and command filters are defined, append them together
    31  	secretstore = appendFilter(secretstore, ctx.String("secretstore-filter"))
    32  	secretstoreFilters := deleteEmpty(strings.Split(secretstore, ":"))
    33  	return Filters{sectionFilters, inputFilters, outputFilters, aggregatorFilters, processorFilters, secretstoreFilters}
    34  }
    35  
    36  func getSecretStoreCommands(m App) []*cli.Command {
    37  	return []*cli.Command{
    38  		{
    39  			Name:  "secrets",
    40  			Usage: "commands for listing, adding and removing secrets on all known secret-stores",
    41  			Subcommands: []*cli.Command{
    42  				{
    43  					Name:  "list",
    44  					Usage: "list known secrets and secret-stores",
    45  					Description: `
    46  The 'list' command requires passing in your configuration file
    47  containing the secret-store definitions you want to access. To get a
    48  list of available secret-store plugins, please have a look at
    49  https://github.com/influxdata/telegraf/tree/master/plugins/secretstores.
    50  
    51  For help on how to define secret-stores, check the documentation of the
    52  different plugins.
    53  
    54  Assuming you use the default configuration file location, you can run
    55  the following command to list the keys of all known secrets in ALL
    56  available stores
    57  
    58  > telegraf secrets list
    59  
    60  To get the keys of all known secrets in a particular store, you can run
    61  
    62  > telegraf secrets list mystore
    63  
    64  To also reveal the actual secret, i.e. the value, you can pass the
    65  '--reveal-secret' flag.
    66  `,
    67  					ArgsUsage: "[secret-store ID]...[secret-store ID]",
    68  					Flags: []cli.Flag{
    69  						&cli.BoolFlag{
    70  							Name:  "reveal-secret",
    71  							Usage: "also print the secret value",
    72  						},
    73  					},
    74  					Action: func(cCtx *cli.Context) error {
    75  						// Only load the secret-stores
    76  						filters := processFilterOnlySecretStoreFlags(cCtx)
    77  						g := GlobalFlags{
    78  							config:     cCtx.StringSlice("config"),
    79  							configDir:  cCtx.StringSlice("config-directory"),
    80  							plugindDir: cCtx.String("plugin-directory"),
    81  							password:   cCtx.String("password"),
    82  							debug:      cCtx.Bool("debug"),
    83  						}
    84  						w := WindowFlags{}
    85  						m.Init(nil, filters, g, w)
    86  
    87  						args := cCtx.Args()
    88  						var storeIDs []string
    89  						if args.Present() {
    90  							storeIDs = args.Slice()
    91  						} else {
    92  							ids, err := m.ListSecretStores()
    93  							if err != nil {
    94  								return fmt.Errorf("unable to determine secret-store IDs: %w", err)
    95  							}
    96  							storeIDs = ids
    97  						}
    98  						sort.Strings(storeIDs)
    99  
   100  						reveal := cCtx.Bool("reveal-secret")
   101  						for _, storeID := range storeIDs {
   102  							store, err := m.GetSecretStore(storeID)
   103  							if err != nil {
   104  								return fmt.Errorf("unable to get secret-store %q: %w", storeID, err)
   105  							}
   106  							keys, err := store.List()
   107  							if err != nil {
   108  								return fmt.Errorf("unable to get secrets from store %q: %w", storeID, err)
   109  							}
   110  							sort.Strings(keys)
   111  
   112  							fmt.Printf("Known secrets for store %q:\n", storeID)
   113  							for _, k := range keys {
   114  								var v []byte
   115  								if reveal {
   116  									if v, err = store.Get(k); err != nil {
   117  										return fmt.Errorf("unable to get value of secret %q from store %q: %w", k, storeID, err)
   118  									}
   119  								}
   120  								fmt.Printf("    %-30s  %s\n", k, string(v))
   121  								memguard.WipeBytes(v)
   122  							}
   123  						}
   124  
   125  						return nil
   126  					},
   127  				},
   128  				{
   129  					Name:  "get",
   130  					Usage: "retrieves value of given secret from given store",
   131  					Description: `
   132  The 'get' command requires passing in your configuration file
   133  containing the secret-store definitions you want to access. To get a
   134  list of available secret-store plugins, please have a look at
   135  https://github.com/influxdata/telegraf/tree/master/plugins/secretstores.
   136  and use the 'secrets list' command to get the IDs of available stores and
   137  key(s) of available secrets.
   138  
   139  For help on how to define secret-stores, check the documentation of the
   140  different plugins.
   141  
   142  Assuming you use the default configuration file location, you can run
   143  the following command to retrieve a secret from a secret store
   144  available stores
   145  
   146  > telegraf secrets get mystore mysecretkey
   147  
   148  This will fetch the secret with the key 'mysecretkey' from the secret-store
   149  with the ID 'mystore'.
   150  `,
   151  					ArgsUsage: "<secret-store ID> <secret key>",
   152  					Action: func(cCtx *cli.Context) error {
   153  						// Only load the secret-stores
   154  						filters := processFilterOnlySecretStoreFlags(cCtx)
   155  						g := GlobalFlags{
   156  							config:     cCtx.StringSlice("config"),
   157  							configDir:  cCtx.StringSlice("config-directory"),
   158  							plugindDir: cCtx.String("plugin-directory"),
   159  							password:   cCtx.String("password"),
   160  							debug:      cCtx.Bool("debug"),
   161  						}
   162  						w := WindowFlags{}
   163  						m.Init(nil, filters, g, w)
   164  
   165  						args := cCtx.Args()
   166  						if !args.Present() || args.Len() != 2 {
   167  							return errors.New("invalid number of arguments")
   168  						}
   169  
   170  						storeID := args.First()
   171  						key := args.Get(1)
   172  
   173  						store, err := m.GetSecretStore(storeID)
   174  						if err != nil {
   175  							return fmt.Errorf("unable to get secret-store: %w", err)
   176  						}
   177  						value, err := store.Get(key)
   178  						if err != nil {
   179  							return fmt.Errorf("unable to get secret: %w", err)
   180  						}
   181  						fmt.Printf("%s:%s = %s\n", storeID, key, value)
   182  
   183  						return nil
   184  					},
   185  				},
   186  				{
   187  					Name:  "set",
   188  					Usage: "create or modify a secret in the given store",
   189  					Description: `
   190  The 'set' command requires passing in your configuration file
   191  containing the secret-store definitions you want to access. To get a
   192  list of available secret-store plugins, please have a look at
   193  https://github.com/influxdata/telegraf/tree/master/plugins/secretstores.
   194  and use the 'secrets list' command to get the IDs of available stores and keys.
   195  
   196  For help on how to define secret-stores, check the documentation of the
   197  different plugins.
   198  
   199  Assuming you use the default configuration file location, you can run
   200  the following command to create a secret in anm available secret-store
   201  
   202  > telegraf secrets set mystore mysecretkey mysecretvalue
   203  
   204  This will create a secret with the key 'mysecretkey' in the secret-store
   205  with the ID 'mystore' with the value being set to 'mysecretvalue'. If a
   206  secret with that key ('mysecretkey') already existed in that store, its
   207  value will be modified.
   208  
   209  When you leave out the value of the secret like
   210  
   211  > telegraf secrets set mystore mysecretkey
   212  
   213  you will be prompted to enter the value of the secret.
   214  `,
   215  					ArgsUsage: "<secret-store ID> <secret key>",
   216  					Action: func(cCtx *cli.Context) error {
   217  						// Only load the secret-stores
   218  						filters := processFilterOnlySecretStoreFlags(cCtx)
   219  						g := GlobalFlags{
   220  							config:     cCtx.StringSlice("config"),
   221  							configDir:  cCtx.StringSlice("config-directory"),
   222  							plugindDir: cCtx.String("plugin-directory"),
   223  							password:   cCtx.String("password"),
   224  							debug:      cCtx.Bool("debug"),
   225  						}
   226  						w := WindowFlags{}
   227  						m.Init(nil, filters, g, w)
   228  
   229  						args := cCtx.Args()
   230  						if !args.Present() || args.Len() < 2 {
   231  							return errors.New("invalid number of arguments")
   232  						}
   233  
   234  						storeID := args.First()
   235  						key := args.Get(1)
   236  						value := args.Get(2)
   237  						if value == "" {
   238  							fmt.Printf("Enter secret value: ")
   239  							b, err := term.ReadPassword(int(os.Stdin.Fd()))
   240  							if err != nil {
   241  								return err
   242  							}
   243  							fmt.Println()
   244  							value = string(b)
   245  						}
   246  
   247  						store, err := m.GetSecretStore(storeID)
   248  						if err != nil {
   249  							return fmt.Errorf("unable to get secret-store: %w", err)
   250  						}
   251  						if err := store.Set(key, value); err != nil {
   252  							return fmt.Errorf("unable to set secret: %w", err)
   253  						}
   254  
   255  						return nil
   256  					},
   257  				},
   258  			},
   259  		},
   260  	}
   261  }