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