261 lines
7 KiB
Go
261 lines
7 KiB
Go
|
// 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.
|
||
|
|
||
|
package cmd
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/spf13/cobra"
|
||
|
"github.com/spf13/pflag"
|
||
|
tml "golang.org/x/crypto/ssh/terminal"
|
||
|
|
||
|
"github.com/elastic/beats/libbeat/cmd/instance"
|
||
|
"github.com/elastic/beats/libbeat/common/cli"
|
||
|
"github.com/elastic/beats/libbeat/common/terminal"
|
||
|
"github.com/elastic/beats/libbeat/keystore"
|
||
|
)
|
||
|
|
||
|
func getKeystore(name, version string) (keystore.Keystore, error) {
|
||
|
b, err := instance.NewBeat(name, "", version)
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("error initializing beat: %s", err)
|
||
|
}
|
||
|
|
||
|
if err = b.Init(); err != nil {
|
||
|
return nil, fmt.Errorf("error initializing beat: %s", err)
|
||
|
}
|
||
|
|
||
|
return b.Keystore(), nil
|
||
|
}
|
||
|
|
||
|
// genKeystoreCmd initialize the Keystore command to manage the Keystore
|
||
|
// with the following subcommands:
|
||
|
// - create
|
||
|
// - add
|
||
|
// - remove
|
||
|
// - list
|
||
|
func genKeystoreCmd(
|
||
|
name, idxPrefix, version string,
|
||
|
runFlags *pflag.FlagSet,
|
||
|
) *cobra.Command {
|
||
|
keystoreCmd := cobra.Command{
|
||
|
Use: "keystore",
|
||
|
Short: "Manage secrets keystore",
|
||
|
}
|
||
|
|
||
|
keystoreCmd.AddCommand(genCreateKeystoreCmd(name, version))
|
||
|
keystoreCmd.AddCommand(genAddKeystoreCmd(name, version))
|
||
|
keystoreCmd.AddCommand(genRemoveKeystoreCmd(name, version))
|
||
|
keystoreCmd.AddCommand(genListKeystoreCmd(name, version))
|
||
|
|
||
|
return &keystoreCmd
|
||
|
}
|
||
|
|
||
|
func genCreateKeystoreCmd(name, version string) *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(name, version, flagForce)
|
||
|
}),
|
||
|
}
|
||
|
command.Flags().BoolVar(&flagForce, "force", false, "override the existing keystore")
|
||
|
return command
|
||
|
}
|
||
|
|
||
|
func genAddKeystoreCmd(name, version string) *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(name, version)
|
||
|
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(name, version string) *cobra.Command {
|
||
|
return &cobra.Command{
|
||
|
Use: "remove",
|
||
|
Short: "remove secret",
|
||
|
Run: cli.RunWith(func(cmd *cobra.Command, args []string) error {
|
||
|
store, err := getKeystore(name, version)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return removeKey(store, args)
|
||
|
}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func genListKeystoreCmd(name, version string) *cobra.Command {
|
||
|
return &cobra.Command{
|
||
|
Use: "list",
|
||
|
Short: "List keystore",
|
||
|
Run: cli.RunWith(func(cmd *cobra.Command, args []string) error {
|
||
|
store, err := getKeystore(name, version)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return list(store)
|
||
|
}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func createKeystore(name, version string, force bool) error {
|
||
|
store, err := getKeystore(name, version)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if store.IsPersisted() == true && force == false {
|
||
|
response := terminal.PromptYesNo("A keystore already exists, Overwrite?", true)
|
||
|
if response == true {
|
||
|
err := store.Create(true)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error creating the keystore: %s", err)
|
||
|
}
|
||
|
} else {
|
||
|
fmt.Println("Exiting without creating keystore.")
|
||
|
return nil
|
||
|
}
|
||
|
} else {
|
||
|
err := store.Create(true)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Error creating the keystore: %s", err)
|
||
|
}
|
||
|
}
|
||
|
fmt.Printf("Created %s keystore\n", name)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
if store.IsPersisted() == false {
|
||
|
if force == false {
|
||
|
answer := terminal.PromptYesNo("The keystore does not exist. Do you want to create it?", false)
|
||
|
if answer == false {
|
||
|
return errors.New("exiting without creating keystore")
|
||
|
}
|
||
|
}
|
||
|
err := store.Create(true)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("could not create keystore, error: %s", err)
|
||
|
}
|
||
|
fmt.Println("Created keystore")
|
||
|
}
|
||
|
|
||
|
key := strings.TrimSpace(keys[0])
|
||
|
value, err := store.Retrieve(key)
|
||
|
if value != nil && force == false {
|
||
|
if stdin == true {
|
||
|
return fmt.Errorf("the settings %s already exist in the keystore use `--force` to replace it", key)
|
||
|
}
|
||
|
answer := terminal.PromptYesNo(fmt.Sprintf("Setting %s already exists, Overwrite?", key), false)
|
||
|
if answer == false {
|
||
|
fmt.Println("Exiting without modifying keystore.")
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var keyValue []byte
|
||
|
if stdin {
|
||
|
reader := bufio.NewReader(os.Stdin)
|
||
|
keyValue, err = ioutil.ReadAll(reader)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("could not read input from stdin")
|
||
|
}
|
||
|
} else {
|
||
|
fmt.Printf("Enter value for %s: ", key)
|
||
|
keyValue, err = tml.ReadPassword(int(syscall.Stdin))
|
||
|
fmt.Println()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("could not read value from the input, error: %s", err)
|
||
|
}
|
||
|
}
|
||
|
if err = store.Store(key, keyValue); err != nil {
|
||
|
return fmt.Errorf("could not add the key in the keystore, error: %s", err)
|
||
|
}
|
||
|
if err = store.Save(); err != nil {
|
||
|
return fmt.Errorf("fail to save the keystore: %s", 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")
|
||
|
}
|
||
|
|
||
|
if store.IsPersisted() == false {
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
store.Delete(key)
|
||
|
err = store.Save()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("could not update the keystore with the changes, key: %s, error: %v", key, err)
|
||
|
}
|
||
|
fmt.Printf("successfully removed key: %s\n", key)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func list(store keystore.Keystore) error {
|
||
|
keys, err := store.List()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("could not read values from the keystore, error: %s", err)
|
||
|
}
|
||
|
for _, key := range keys {
|
||
|
fmt.Println(key)
|
||
|
}
|
||
|
return nil
|
||
|
}
|