internal/beatcmd/keystore_nofips.go (218 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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. //go:build !requirefips package beatcmd import ( "bufio" "errors" "fmt" "io" "os" "strings" "syscall" "github.com/spf13/cobra" "golang.org/x/term" "github.com/elastic/beats/v7/libbeat/common/cli" "github.com/elastic/beats/v7/libbeat/common/terminal" "github.com/elastic/elastic-agent-libs/keystore" ) var keystoreCommand = &cobra.Command{ Use: "keystore", Short: "Manage secrets keystore", } func init() { keystoreCommand.AddCommand(genCreateKeystoreCmd()) keystoreCommand.AddCommand(genAddKeystoreCmd()) keystoreCommand.AddCommand(genRemoveKeystoreCmd()) keystoreCommand.AddCommand(genListKeystoreCmd()) } func genCreateKeystoreCmd() *cobra.Command { var flagForce bool command := &cobra.Command{ Use: "create", Short: "Create keystore", Run: cli.RunWith(func(cmd *cobra.Command, args []string) error { return createKeystore(flagForce) }), } command.Flags().BoolVar(&flagForce, "force", false, "override the existing keystore") return command } func genAddKeystoreCmd() *cobra.Command { var flagForce bool var flagStdin bool command := &cobra.Command{ Use: "add", Short: "Add secret", Run: cli.RunWith(func(cmd *cobra.Command, args []string) error { store, err := getKeystore() if err != nil { return err } return addKey(store, args, flagForce, flagStdin) }), } command.Flags().BoolVar(&flagStdin, "stdin", false, "Use the stdin as the source of the secret") command.Flags().BoolVar(&flagForce, "force", false, "Override the existing key") return command } func genRemoveKeystoreCmd() *cobra.Command { return &cobra.Command{ Use: "remove", Short: "Remove secret", Run: cli.RunWith(func(cmd *cobra.Command, args []string) error { store, err := getKeystore() if err != nil { return err } return removeKey(store, args) }), } } func genListKeystoreCmd() *cobra.Command { return &cobra.Command{ Use: "list", Short: "List keystore", Run: cli.RunWith(func(cmd *cobra.Command, args []string) error { store, err := getKeystore() if err != nil { return err } return list(store) }), } } func createKeystore(force bool) error { store, err := getKeystore() if err != nil { return err } writableKeystore, err := keystore.AsWritableKeystore(store) if err != nil { return fmt.Errorf("error creating the keystore: %w", err) } if store.IsPersisted() && !force { overwrite := terminal.PromptYesNo("A keystore already exists, Overwrite?", false) if overwrite { err := writableKeystore.Create(true) if err != nil { return fmt.Errorf("error creating the keystore: %w", err) } } else { fmt.Println("Exiting without creating keystore.") return nil } } else { err := writableKeystore.Create(true) if err != nil { return fmt.Errorf("error creating the keystore: %w", err) } } fmt.Printf("Created apm-server keystore\n") return nil } func getKeystore() (keystore.Keystore, error) { _, _, keystore, err := LoadConfig() return keystore, err } func addKey(store keystore.Keystore, keys []string, force, stdin bool) error { if len(keys) == 0 { return errors.New("failed to create the secret: no key provided") } if len(keys) > 1 { return fmt.Errorf("could not create secret for: %s, you can only provide one key per invocation", keys) } writableKeystore, err := keystore.AsWritableKeystore(store) if err != nil { return fmt.Errorf("error creating the keystore: %w", err) } if !store.IsPersisted() { if !force { create := terminal.PromptYesNo("The keystore does not exist. Do you want to create it?", false) if !create { return errors.New("exiting without creating keystore") } } err := writableKeystore.Create(true) if err != nil { return fmt.Errorf("could not create keystore, error: %w", err) } fmt.Println("Created keystore") } key := strings.TrimSpace(keys[0]) if _, err := store.Retrieve(key); err == nil { if !force { if stdin { return fmt.Errorf("the settings %s already exist in the keystore use `--force` to replace it", key) } overwrite := terminal.PromptYesNo(fmt.Sprintf("Setting %s already exists, Overwrite?", key), false) if !overwrite { fmt.Println("Exiting without modifying keystore.") return nil } } } else if !errors.Is(err, keystore.ErrKeyDoesntExists) { return err } var keyValue []byte if stdin { reader := bufio.NewReader(os.Stdin) keyValue, err = io.ReadAll(reader) if err != nil { return fmt.Errorf("could not read input from stdin") } } else { fmt.Printf("Enter value for %s: ", key) keyValue, err = term.ReadPassword(int(syscall.Stdin)) fmt.Println() if err != nil { return fmt.Errorf("could not read value from the input, error: %w", err) } } if err = writableKeystore.Store(key, keyValue); err != nil { return fmt.Errorf("could not add the key in the keystore, error: %w", err) } if err = writableKeystore.Save(); err != nil { return fmt.Errorf("fail to save the keystore: %w", err) } else { fmt.Println("Successfully updated the keystore") } return nil } func removeKey(store keystore.Keystore, keys []string) error { if len(keys) == 0 { return errors.New("you must supply at least one key to remove") } writableKeystore, err := keystore.AsWritableKeystore(store) if err != nil { return fmt.Errorf("error deleting the keystore: %w", err) } if !store.IsPersisted() { return errors.New("the keystore doesn't exist. Use the 'create' command to create one") } for _, key := range keys { key = strings.TrimSpace(key) _, err := store.Retrieve(key) if err != nil { return fmt.Errorf("could not find key '%v' in the keystore", key) } writableKeystore.Delete(key) err = writableKeystore.Save() if err != nil { return fmt.Errorf("could not update the keystore with the changes, key: %s, error: %w", key, err) } fmt.Printf("successfully removed key: %s\n", key) } return nil } func list(store keystore.Keystore) error { listingKeystore, err := keystore.AsListingKeystore(store) if err != nil { return fmt.Errorf("error listing the keystore: %w", err) } keys, err := listingKeystore.List() if err != nil { return fmt.Errorf("could not read values from the keystore, error: %w", err) } for _, key := range keys { fmt.Println(key) } return nil }