github.com/aminovpavel/nomad@v0.11.8/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) Name() string { return "operator keyring" } 71 72 func (c *OperatorKeyringCommand) Run(args []string) int { 73 var installKey, useKey, removeKey string 74 var listKeys bool 75 76 flags := c.Meta.FlagSet("operator-keyring", FlagSetClient) 77 flags.Usage = func() { c.Ui.Output(c.Help()) } 78 79 flags.StringVar(&installKey, "install", "", "install key") 80 flags.StringVar(&useKey, "use", "", "use key") 81 flags.StringVar(&removeKey, "remove", "", "remove key") 82 flags.BoolVar(&listKeys, "list", false, "list keys") 83 84 if err := flags.Parse(args); err != nil { 85 return 1 86 } 87 88 c.Ui = &cli.PrefixedUi{ 89 OutputPrefix: "", 90 InfoPrefix: "==> ", 91 ErrorPrefix: "", 92 Ui: c.Ui, 93 } 94 95 // Only accept a single argument 96 found := listKeys 97 for _, arg := range []string{installKey, useKey, removeKey} { 98 if found && len(arg) > 0 { 99 c.Ui.Error("Only a single action is allowed") 100 c.Ui.Error(commandErrorText(c)) 101 return 1 102 } 103 found = found || len(arg) > 0 104 } 105 106 // Fail fast if no actionable args were passed 107 if !found { 108 c.Ui.Error("No actionable argument was passed") 109 c.Ui.Error("Either the '-install', '-use', '-remove' or '-list' flag must be set") 110 c.Ui.Error(commandErrorText(c)) 111 return 1 112 } 113 114 // All other operations will require a client connection 115 client, err := c.Meta.Client() 116 if err != nil { 117 c.Ui.Error(fmt.Sprintf("Error creating nomad cli client: %s", err)) 118 return 1 119 } 120 121 if listKeys { 122 c.Ui.Output("Gathering installed encryption keys...") 123 r, err := client.Agent().ListKeys() 124 if err != nil { 125 c.Ui.Error(fmt.Sprintf("error: %s", err)) 126 return 1 127 } 128 c.handleKeyResponse(r) 129 return 0 130 } 131 132 if installKey != "" { 133 c.Ui.Output("Installing new gossip encryption key...") 134 _, err := client.Agent().InstallKey(installKey) 135 if err != nil { 136 c.Ui.Error(fmt.Sprintf("error: %s", err)) 137 return 1 138 } 139 return 0 140 } 141 142 if useKey != "" { 143 c.Ui.Output("Changing primary gossip encryption key...") 144 _, err := client.Agent().UseKey(useKey) 145 if err != nil { 146 c.Ui.Error(fmt.Sprintf("error: %s", err)) 147 return 1 148 } 149 return 0 150 } 151 152 if removeKey != "" { 153 c.Ui.Output("Removing gossip encryption key...") 154 _, err := client.Agent().RemoveKey(removeKey) 155 if err != nil { 156 c.Ui.Error(fmt.Sprintf("error: %s", err)) 157 return 1 158 } 159 return 0 160 } 161 162 // Should never make it here 163 return 0 164 } 165 166 func (c *OperatorKeyringCommand) handleKeyResponse(resp *api.KeyringResponse) { 167 out := make([]string, len(resp.Keys)+1) 168 out[0] = "Key" 169 i := 1 170 for k := range resp.Keys { 171 out[i] = fmt.Sprintf("%s", k) 172 i = i + 1 173 } 174 c.Ui.Output(formatList(out)) 175 }