From 67d78628a311e51f26d6e38d7a5feac94a94d0af Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Fri, 12 Sep 2014 20:08:54 -0700 Subject: [PATCH] command: renamed keys to keyring to disambiguate usage --- command/{keys.go => keyring.go} | 34 +++--- command/{keys_test.go => keyring_test.go} | 105 ++++-------------- commands.go | 4 +- ...ys.html.markdown => keyring.html.markdown} | 39 ++++--- website/source/layouts/docs.erb | 4 +- 5 files changed, 63 insertions(+), 123 deletions(-) rename command/{keys.go => keyring.go} (86%) rename command/{keys_test.go => keyring_test.go} (50%) rename website/source/docs/commands/{keys.html.markdown => keyring.html.markdown} (60%) diff --git a/command/keys.go b/command/keyring.go similarity index 86% rename from command/keys.go rename to command/keyring.go index c603a3d53f..17d1c5c4c4 100644 --- a/command/keys.go +++ b/command/keyring.go @@ -14,13 +14,13 @@ import ( "github.com/ryanuber/columnize" ) -// KeysCommand is a Command implementation that handles querying, installing, +// KeyringCommand is a Command implementation that handles querying, installing, // and removing gossip encryption keys from a keyring. -type KeysCommand struct { +type KeyringCommand struct { Ui cli.Ui } -func (c *KeysCommand) Run(args []string) int { +func (c *KeyringCommand) Run(args []string) int { var installKey, useKey, removeKey, init, dataDir string var listKeys bool @@ -150,9 +150,12 @@ func (c *KeysCommand) Run(args []string) int { return 0 } +// keyFunc is a function which manipulates gossip encryption keyrings. This is +// used for key installation, removal, and primary key changes. type keyFunc func(string) (map[string]string, error) -func (c *KeysCommand) keyOperation(key string, fn keyFunc) int { +// keyOperation is a unified process for manipulating the gossip keyrings. +func (c *KeyringCommand) keyOperation(key string, fn keyFunc) int { var out []string failures, err := fn(key) @@ -172,9 +175,12 @@ func (c *KeysCommand) keyOperation(key string, fn keyFunc) int { return 0 } +// listKeysFunc is a function which handles querying lists of gossip keys type listKeysFunc func() (map[string]int, int, map[string]string, error) -func (c *KeysCommand) listKeysOperation(fn listKeysFunc) int { +// listKeysOperation is a unified process for querying and +// displaying gossip keys. +func (c *KeyringCommand) listKeysOperation(fn listKeysFunc) int { var out []string keys, numNodes, failures, err := fn() @@ -233,9 +239,9 @@ func initializeKeyring(path, key string) error { return nil } -func (c *KeysCommand) Help() string { +func (c *KeyringCommand) Help() string { helpText := ` -Usage: consul keys [options] +Usage: consul keyring [options] Manages encryption keys used for gossip messages. Gossip encryption is optional. When enabled, this command may be used to examine active encryption @@ -243,6 +249,9 @@ Usage: consul keys [options] functionality provides the ability to perform key rotation cluster-wide, without disrupting the cluster. + With the exception of the -init argument, all other operations performed by + this command can only be run against server nodes. + Options: -install= Install a new encryption key. This will broadcast @@ -254,19 +263,14 @@ Options: operation may only be performed on keys which are not currently the primary key. -list List all keys currently in use within the cluster. - -wan If talking with a server node, this flag can be used - to operate on the WAN gossip layer. -init= Create an initial keyring file for Consul to use - containing the provided key. By default, this option - will only initialize the LAN keyring. If the -wan - option is also passed, then the wan keyring will be - created as well. The -data-dir argument is required - with this option. + containing the provided key. The -data-dir argument + is required with this option. -rpc-addr=127.0.0.1:8400 RPC address of the Consul agent. ` return strings.TrimSpace(helpText) } -func (c *KeysCommand) Synopsis() string { +func (c *KeyringCommand) Synopsis() string { return "Manages gossip layer encryption keys" } diff --git a/command/keys_test.go b/command/keyring_test.go similarity index 50% rename from command/keys_test.go rename to command/keyring_test.go index 903d13b19f..d3f01ade92 100644 --- a/command/keys_test.go +++ b/command/keyring_test.go @@ -8,14 +8,13 @@ import ( "github.com/mitchellh/cli" ) -func TestKeysCommand_implements(t *testing.T) { - var _ cli.Command = &KeysCommand{} +func TestKeyringCommand_implements(t *testing.T) { + var _ cli.Command = &KeyringCommand{} } -func TestKeysCommandRun(t *testing.T) { +func TestKeyringCommandRun(t *testing.T) { key1 := "HS5lJ+XuTlYKWaeGYyG+/A==" key2 := "kZyFABeAmc64UMTrm9XuKA==" - key3 := "2k5VRlBIIKUPc1v77rsswg==" // Begin with a single key conf := agent.Config{EncryptKey: key1} @@ -23,7 +22,7 @@ func TestKeysCommandRun(t *testing.T) { defer a1.Shutdown() // The keyring was initialized with only the provided key - out := listKeys(t, a1.addr, false) + out := listKeys(t, a1.addr) if !strings.Contains(out, key1) { t.Fatalf("bad: %#v", out) } @@ -31,83 +30,36 @@ func TestKeysCommandRun(t *testing.T) { t.Fatalf("bad: %#v", out) } - // The key was installed on the WAN gossip layer also - out = listKeys(t, a1.addr, true) - if !strings.Contains(out, key1) { - t.Fatalf("bad: %#v", out) - } - if strings.Contains(out, key3) { - t.Fatalf("bad: %#v", out) - } - // Install the second key onto the keyring - installKey(t, a1.addr, false, key2) + installKey(t, a1.addr, key2) // Both keys should be present - out = listKeys(t, a1.addr, false) + out = listKeys(t, a1.addr) for _, key := range []string{key1, key2} { if !strings.Contains(out, key) { t.Fatalf("bad: %#v", out) } } - // Second key should not be installed on WAN - out = listKeys(t, a1.addr, true) - if strings.Contains(out, key2) { - t.Fatalf("bad: %#v", out) - } - // Change out the primary key - useKey(t, a1.addr, false, key2) + useKey(t, a1.addr, key2) // Remove the original key - removeKey(t, a1.addr, false, key1) + removeKey(t, a1.addr, key1) // Make sure only the new key is present - out = listKeys(t, a1.addr, false) + out = listKeys(t, a1.addr) if strings.Contains(out, key1) { t.Fatalf("bad: %#v", out) } if !strings.Contains(out, key2) { t.Fatalf("bad: %#v", out) } - - // Original key still remains on WAN keyring - out = listKeys(t, a1.addr, true) - if !strings.Contains(out, key1) { - t.Fatalf("bad: %#v", out) - } - - // Install second key on WAN keyring - installKey(t, a1.addr, true, key3) - - // Two keys now present on WAN keyring - out = listKeys(t, a1.addr, true) - for _, key := range []string{key1, key3} { - if !strings.Contains(out, key) { - t.Fatalf("bad: %#v", out) - } - } - - // Change WAN primary key - useKey(t, a1.addr, true, key3) - - // Remove original key from WAN keyring - removeKey(t, a1.addr, true, key1) - - // Only new key should exist on WAN keyring - out = listKeys(t, a1.addr, true) - if !strings.Contains(out, key3) { - t.Fatalf("bad: %#v", out) - } - if strings.Contains(out, key1) { - t.Fatalf("bad: %#v", out) - } } -func TestKeysCommandRun_help(t *testing.T) { +func TestKeyringCommandRun_help(t *testing.T) { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} code := c.Run(nil) if code != 1 { t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) @@ -119,9 +71,9 @@ func TestKeysCommandRun_help(t *testing.T) { } } -func TestKeysCommandRun_failedConnection(t *testing.T) { +func TestKeyringCommandRun_failedConnection(t *testing.T) { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} args := []string{"-list", "-rpc-addr=127.0.0.1:0"} code := c.Run(args) if code != 1 { @@ -132,14 +84,11 @@ func TestKeysCommandRun_failedConnection(t *testing.T) { } } -func listKeys(t *testing.T, addr string, wan bool) string { +func listKeys(t *testing.T, addr string) string { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} args := []string{"-list", "-rpc-addr=" + addr} - if wan { - args = append(args, "-wan") - } code := c.Run(args) if code != 0 { @@ -149,45 +98,33 @@ func listKeys(t *testing.T, addr string, wan bool) string { return ui.OutputWriter.String() } -func installKey(t *testing.T, addr string, wan bool, key string) { +func installKey(t *testing.T, addr string, key string) { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} args := []string{"-install=" + key, "-rpc-addr=" + addr} - if wan { - args = append(args, "-wan") - } - code := c.Run(args) if code != 0 { t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) } } -func useKey(t *testing.T, addr string, wan bool, key string) { +func useKey(t *testing.T, addr string, key string) { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} args := []string{"-use=" + key, "-rpc-addr=" + addr} - if wan { - args = append(args, "-wan") - } - code := c.Run(args) if code != 0 { t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) } } -func removeKey(t *testing.T, addr string, wan bool, key string) { +func removeKey(t *testing.T, addr string, key string) { ui := new(cli.MockUi) - c := &KeysCommand{Ui: ui} + c := &KeyringCommand{Ui: ui} args := []string{"-remove=" + key, "-rpc-addr=" + addr} - if wan { - args = append(args, "-wan") - } - code := c.Run(args) if code != 0 { t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String()) diff --git a/commands.go b/commands.go index 8fab257ace..f6cf50a91a 100644 --- a/commands.go +++ b/commands.go @@ -56,8 +56,8 @@ func init() { }, nil }, - "keys": func() (cli.Command, error) { - return &command.KeysCommand{ + "keyring": func() (cli.Command, error) { + return &command.KeyringCommand{ Ui: ui, }, nil }, diff --git a/website/source/docs/commands/keys.html.markdown b/website/source/docs/commands/keyring.html.markdown similarity index 60% rename from website/source/docs/commands/keys.html.markdown rename to website/source/docs/commands/keyring.html.markdown index beb9f38945..2b65241e6b 100644 --- a/website/source/docs/commands/keys.html.markdown +++ b/website/source/docs/commands/keyring.html.markdown @@ -1,21 +1,21 @@ --- layout: "docs" -page_title: "Commands: Keys" -sidebar_current: "docs-commands-keys" +page_title: "Commands: Keyring" +sidebar_current: "docs-commands-keyring" --- -# Consul Keys +# Consul Keyring -Command: `consul keys` +Command: `consul keyring` -The `keys` command is used to examine and modify the encryption keys used in +The `keyring` command is used to examine and modify the encryption keys used in Consul's [Gossip Pools](/docs/internals/gossip.html). It is capable of distributing new encryption keys to the cluster, revoking old encryption keys, and changing the key used by the cluster to encrypt messages. -Because Consul utilizes multiple gossip pools, this command will operate on only -a single pool at a time. The pool can be specified using the arguments -documented below. +Because Consul utilizes multiple gossip pools, this command will only operate +against a server node for most operations. The only operation which may be used +on client machines is the `-init` argument for initial key configuration. Consul allows multiple encryption keys to be in use simultaneously. This is intended to provide a transition state while the cluster converges. It is the @@ -23,23 +23,27 @@ responsibility of the operator to ensure that only the required encryption keys are installed on the cluster. You can ensure that a key is not installed using the `-list` and `-remove` options. -By default, modifications made using this command will **NOT** be persisted, and -will be lost when the agent shuts down. You can alter this behavior via the -`-persist-keyring` option in the -[Agent Configuration](/docs/agent/options.html). - All variations of the keys command will return 0 if all nodes reply and there are no errors. If any node fails to reply or reports failure, the exit code will be 1. ## Usage -Usage: `consul keys [options]` +Usage: `consul keyring [options]` -Exactly one of `-list`, `-install`, `-remove`, or `-update` must be provided. +Only one actionable argument may be specified per run, including `-init`, +`-list`, `-install`, `-remove`, and `-update`. The list of available flags are: +* `-init` - Creates the keyring file(s). This is useful to configure initial + encryption keyrings, which can later be mutated using the other arguments in + this command. This argument accepts an ASCII key, which can be generated using + the [keygen command](/docs/commands/keygen.html). + + This operation can be run on both client and server nodes and requires no + network connectivity. + * `-install` - Install a new encryption key. This will broadcast the new key to all members in the cluster. @@ -51,9 +55,4 @@ The list of available flags are: * `-list` - List all keys currently in use within the cluster. -* `-wan` - If talking with a server node, this flag can be used to operate on - the WAN gossip layer. By default, this command operates on the LAN layer. More - information about the different gossip layers can be found on the - [gossip protocol](/docs/internals/gossip.html) page. - * `-rpc-addr` - RPC address of the Consul agent. diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index 6c48f1dbbd..d6764e7929 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -79,8 +79,8 @@ keygen - > - keys + > + keyring >