github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/command/keyring.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/nomad/api"
     8  	"github.com/mitchellh/cli"
     9  )
    10  
    11  // KeyringCommand is a Command implementation that handles querying, installing,
    12  // and removing gossip encryption keys from a keyring.
    13  type KeyringCommand struct {
    14  	Meta
    15  }
    16  
    17  func (c *KeyringCommand) Run(args []string) int {
    18  	var installKey, useKey, removeKey, token string
    19  	var listKeys bool
    20  
    21  	flags := c.Meta.FlagSet("keys", FlagSetClient)
    22  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    23  
    24  	flags.StringVar(&installKey, "install", "", "install key")
    25  	flags.StringVar(&useKey, "use", "", "use key")
    26  	flags.StringVar(&removeKey, "remove", "", "remove key")
    27  	flags.BoolVar(&listKeys, "list", false, "list keys")
    28  	flags.StringVar(&token, "token", "", "acl token")
    29  
    30  	if err := flags.Parse(args); err != nil {
    31  		return 1
    32  	}
    33  
    34  	c.Ui = &cli.PrefixedUi{
    35  		OutputPrefix: "",
    36  		InfoPrefix:   "==> ",
    37  		ErrorPrefix:  "",
    38  		Ui:           c.Ui,
    39  	}
    40  
    41  	// Only accept a single argument
    42  	found := listKeys
    43  	for _, arg := range []string{installKey, useKey, removeKey} {
    44  		if found && len(arg) > 0 {
    45  			c.Ui.Error("Only a single action is allowed")
    46  			return 1
    47  		}
    48  		found = found || len(arg) > 0
    49  	}
    50  
    51  	// Fail fast if no actionable args were passed
    52  	if !found {
    53  		c.Ui.Error(c.Help())
    54  		return 1
    55  	}
    56  
    57  	// All other operations will require a client connection
    58  	client, err := c.Meta.Client()
    59  	if err != nil {
    60  		c.Ui.Error(fmt.Sprintf("Error creating nomad cli client: %s", err))
    61  		return 1
    62  	}
    63  
    64  	if listKeys {
    65  		c.Ui.Info("Gathering installed encryption keys...")
    66  		r, err := client.Agent().ListKeys()
    67  		if err != nil {
    68  			c.Ui.Error(fmt.Sprintf("error: %s", err))
    69  			return 1
    70  		}
    71  		c.handleKeyResponse(r)
    72  		return 0
    73  	}
    74  
    75  	if installKey != "" {
    76  		c.Ui.Info("Installing new gossip encryption key...")
    77  		_, err := client.Agent().InstallKey(installKey)
    78  		if err != nil {
    79  			c.Ui.Error(fmt.Sprintf("error: %s", err))
    80  			return 1
    81  		}
    82  		return 0
    83  	}
    84  
    85  	if useKey != "" {
    86  		c.Ui.Info("Changing primary gossip encryption key...")
    87  		_, err := client.Agent().UseKey(useKey)
    88  		if err != nil {
    89  			c.Ui.Error(fmt.Sprintf("error: %s", err))
    90  			return 1
    91  		}
    92  		return 0
    93  	}
    94  
    95  	if removeKey != "" {
    96  		c.Ui.Info("Removing gossip encryption key...")
    97  		_, err := client.Agent().RemoveKey(removeKey)
    98  		if err != nil {
    99  			c.Ui.Error(fmt.Sprintf("error: %s", err))
   100  			return 1
   101  		}
   102  		return 0
   103  	}
   104  
   105  	// Should never make it here
   106  	return 0
   107  }
   108  
   109  func (c *KeyringCommand) handleKeyResponse(resp *api.KeyringResponse) {
   110  	out := make([]string, len(resp.Keys)+1)
   111  	out[0] = "Key"
   112  	i := 1
   113  	for k := range resp.Keys {
   114  		out[i] = fmt.Sprintf("%s", k)
   115  		i = i + 1
   116  	}
   117  	c.Ui.Output(formatList(out))
   118  }
   119  
   120  func (c *KeyringCommand) Help() string {
   121  	helpText := `
   122  Usage: nomad keyring [options]
   123  
   124    Manages encryption keys used for gossip messages between Nomad servers. Gossip
   125    encryption is optional. When enabled, this command may be used to examine
   126    active encryption keys in the cluster, add new keys, and remove old ones. When
   127    combined, this functionality provides the ability to perform key rotation
   128    cluster-wide, without disrupting the cluster.
   129  
   130    All operations performed by this command can only be run against server nodes.
   131  
   132    All variations of the keyring command return 0 if all nodes reply and there
   133    are no errors. If any node fails to reply or reports failure, the exit code
   134    will be 1.
   135  
   136  General Options:
   137  
   138    ` + generalOptionsUsage() + `
   139  
   140  Keyring Options:
   141  
   142    -install=<key>            Install a new encryption key. This will broadcast
   143                              the new key to all members in the cluster.
   144    -list                     List all keys currently in use within the cluster.
   145    -remove=<key>             Remove the given key from the cluster. This
   146                              operation may only be performed on keys which are
   147                              not currently the primary key.
   148    -use=<key>                Change the primary encryption key, which is used to
   149                              encrypt messages. The key must already be installed
   150                              before this operation can succeed.
   151  `
   152  	return strings.TrimSpace(helpText)
   153  }
   154  
   155  func (c *KeyringCommand) Synopsis() string {
   156  	return "Manages gossip layer encryption keys"
   157  }