From cfbf2b4f9485da5ad46d799456f336ba2a0bf07d Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Sun, 21 Sep 2014 11:52:28 -0700 Subject: [PATCH] command: allow wan ring to be modified separately from lan pools --- command/agent/command_test.go | 13 ++-- command/keyring.go | 72 +++++++++++-------- command/keyring_test.go | 65 +++++++++++++---- .../docs/commands/keyring.html.markdown | 9 +-- 4 files changed, 103 insertions(+), 56 deletions(-) diff --git a/command/agent/command_test.go b/command/agent/command_test.go index db7d1c9a5c..9c1bf4db5d 100644 --- a/command/agent/command_test.go +++ b/command/agent/command_test.go @@ -1,17 +1,12 @@ package agent import ( -<<<<<<< HEAD "fmt" "io/ioutil" "log" "os" -======= - "github.com/hashicorp/consul/testutil" - "github.com/mitchellh/cli" - "io/ioutil" "path/filepath" ->>>>>>> command: test generated keyring file content and conflicting args for agent + "strings" "testing" "github.com/hashicorp/consul/testutil" @@ -45,7 +40,6 @@ func TestValidDatacenter(t *testing.T) { } } -<<<<<<< HEAD func TestRetryJoin(t *testing.T) { dir, agent := makeAgent(t, nextConfig()) defer os.RemoveAll(dir) @@ -169,7 +163,9 @@ func TestRetryJoinWanFail(t *testing.T) { if code := cmd.Run(args); code == 0 { t.Fatalf("bad: %d", code) -======= + } +} + func TestArgConflict(t *testing.T) { ui := new(cli.MockUi) c := &Command{Ui: ui} @@ -196,6 +192,5 @@ func TestArgConflict(t *testing.T) { } if !strings.Contains(ui.ErrorWriter.String(), "keyring files exist") { t.Fatalf("bad: %#v", ui.ErrorWriter.String()) ->>>>>>> command: test generated keyring file content and conflicting args for agent } } diff --git a/command/keyring.go b/command/keyring.go index 83293a644c..630f0ba12c 100644 --- a/command/keyring.go +++ b/command/keyring.go @@ -22,7 +22,7 @@ type KeyringCommand struct { func (c *KeyringCommand) Run(args []string) int { var installKey, useKey, removeKey, init, dataDir string - var listKeys bool + var listKeys, wan bool cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError) cmdFlags.Usage = func() { c.Ui.Output(c.Help()) } @@ -33,6 +33,7 @@ func (c *KeyringCommand) Run(args []string) int { cmdFlags.BoolVar(&listKeys, "list", false, "list keys") cmdFlags.StringVar(&init, "init", "", "initialize keyring") cmdFlags.StringVar(&dataDir, "data-dir", "", "data directory") + cmdFlags.BoolVar(&wan, "wan", false, "operate on wan keyring") rpcAddr := RPCAddrFlag(cmdFlags) if err := cmdFlags.Parse(args); err != nil { @@ -105,51 +106,57 @@ func (c *KeyringCommand) Run(args []string) int { } if listKeys { - c.Ui.Info("Asking all WAN members for installed keys...") - if rval := c.listKeysOperation(client.ListKeysWAN); rval != 0 { - return rval + if wan { + c.Ui.Info("Asking all WAN members for installed keys...") + return c.listKeysOperation(client.ListKeysWAN) } c.Ui.Info("Asking all LAN members for installed keys...") - if rval := c.listKeysOperation(client.ListKeysLAN); rval != 0 { - return rval - } - return 0 + return c.listKeysOperation(client.ListKeysLAN) } if installKey != "" { - c.Ui.Info("Installing new WAN gossip encryption key...") - if rval := c.keyOperation(installKey, client.InstallKeyWAN); rval != 0 { - return rval - } - c.Ui.Info("Installing new LAN gossip encryption key...") - if rval := c.keyOperation(installKey, client.InstallKeyLAN); rval != 0 { - return rval + if wan { + c.Ui.Info("Installing new WAN gossip encryption key...") + if rval := c.keyOperation(installKey, client.InstallKeyWAN); rval != 0 { + return rval + } + } else { + c.Ui.Info("Installing new LAN gossip encryption key...") + if rval := c.keyOperation(installKey, client.InstallKeyLAN); rval != 0 { + return rval + } } c.Ui.Info("Successfully installed key!") return 0 } if useKey != "" { - c.Ui.Info("Changing primary WAN gossip encryption key...") - if rval := c.keyOperation(useKey, client.UseKeyWAN); rval != 0 { - return rval - } - c.Ui.Info("Changing primary LAN gossip encryption key...") - if rval := c.keyOperation(useKey, client.UseKeyLAN); rval != 0 { - return rval + if wan { + c.Ui.Info("Changing primary WAN gossip encryption key...") + if rval := c.keyOperation(useKey, client.UseKeyWAN); rval != 0 { + return rval + } + } else { + c.Ui.Info("Changing primary LAN gossip encryption key...") + if rval := c.keyOperation(useKey, client.UseKeyLAN); rval != 0 { + return rval + } } c.Ui.Info("Successfully changed primary key!") return 0 } if removeKey != "" { - c.Ui.Info("Removing WAN gossip encryption key...") - if rval := c.keyOperation(removeKey, client.RemoveKeyWAN); rval != 0 { - return rval - } - c.Ui.Info("Removing LAN gossip encryption key...") - if rval := c.keyOperation(removeKey, client.RemoveKeyLAN); rval != 0 { - return rval + if wan { + c.Ui.Info("Removing WAN gossip encryption key...") + if rval := c.keyOperation(removeKey, client.RemoveKeyWAN); rval != 0 { + return rval + } + } else { + c.Ui.Info("Removing LAN gossip encryption key...") + if rval := c.keyOperation(removeKey, client.RemoveKeyLAN); rval != 0 { + return rval + } } c.Ui.Info("Successfully removed key!") return 0 @@ -258,8 +265,9 @@ Usage: consul keyring [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. + With the exception of the -init argument, all operations performed by this + command can only be run against server nodes. All operations default to the + LAN gossip pool. Options: @@ -275,6 +283,8 @@ Options: -init= Create the initial keyring files for Consul to use containing the provided key. The -data-dir argument is required with this option. + -wan Operate on the WAN keyring instead of the LAN + keyring (default). -rpc-addr=127.0.0.1:8400 RPC address of the Consul agent. ` return strings.TrimSpace(helpText) diff --git a/command/keyring_test.go b/command/keyring_test.go index cc18ad7996..c7c0847f46 100644 --- a/command/keyring_test.go +++ b/command/keyring_test.go @@ -25,7 +25,7 @@ func TestKeyringCommandRun(t *testing.T) { defer a1.Shutdown() // The keyring was initialized with only the provided key - out := listKeys(t, a1.addr) + out := listKeys(t, a1.addr, false) if !strings.Contains(out, key1) { t.Fatalf("bad: %#v", out) } @@ -34,30 +34,56 @@ func TestKeyringCommandRun(t *testing.T) { } // Install the second key onto the keyring - installKey(t, a1.addr, key2) + installKey(t, a1.addr, key2, false) // Both keys should be present - out = listKeys(t, a1.addr) + out = listKeys(t, a1.addr, false) for _, key := range []string{key1, key2} { if !strings.Contains(out, key) { t.Fatalf("bad: %#v", out) } } + // WAN keyring is untouched + 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, key2) + useKey(t, a1.addr, key2, false) // Remove the original key - removeKey(t, a1.addr, key1) + removeKey(t, a1.addr, key1, false) // Make sure only the new key is present - out = listKeys(t, a1.addr) + out = listKeys(t, a1.addr, false) if strings.Contains(out, key1) { t.Fatalf("bad: %#v", out) } if !strings.Contains(out, key2) { t.Fatalf("bad: %#v", out) } + + // WAN keyring is still untouched + out = listKeys(t, a1.addr, true) + if !strings.Contains(out, key1) { + t.Fatalf("bad: %#v", out) + } + + // Rotate out the WAN key + installKey(t, a1.addr, key2, true) + useKey(t, a1.addr, key2, true) + removeKey(t, a1.addr, key1, true) + + // WAN keyring now has only the proper key + out = listKeys(t, a1.addr, true) + if !strings.Contains(out, key2) { + t.Fatalf("bad: %#v", out) + } + if strings.Contains(out, key1) { + t.Fatalf("bad: %#v", out) + } } func TestKeyringCommandRun_help(t *testing.T) { @@ -87,7 +113,7 @@ func TestKeyringCommandRun_failedConnection(t *testing.T) { } } -func TestKeyCommandRun_initKeyringFail(t *testing.T) { +func TestKeyringCommandRun_initKeyringFail(t *testing.T) { ui := new(cli.MockUi) c := &KeyringCommand{Ui: ui} @@ -106,7 +132,7 @@ func TestKeyCommandRun_initKeyringFail(t *testing.T) { } } -func TestKeyCommandRun_initKeyring(t *testing.T) { +func TestKeyringCommandRun_initKeyring(t *testing.T) { ui := new(cli.MockUi) c := &KeyringCommand{Ui: ui} @@ -153,11 +179,14 @@ func TestKeyCommandRun_initKeyring(t *testing.T) { } } -func listKeys(t *testing.T, addr string) string { +func listKeys(t *testing.T, addr string, wan bool) string { ui := new(cli.MockUi) c := &KeyringCommand{Ui: ui} args := []string{"-list", "-rpc-addr=" + addr} + if wan { + args = append(args, "-wan") + } code := c.Run(args) if code != 0 { @@ -167,33 +196,45 @@ func listKeys(t *testing.T, addr string) string { return ui.OutputWriter.String() } -func installKey(t *testing.T, addr string, key string) { +func installKey(t *testing.T, addr string, key string, wan bool) { ui := new(cli.MockUi) 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, key string) { +func useKey(t *testing.T, addr string, key string, wan bool) { ui := new(cli.MockUi) 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, key string) { +func removeKey(t *testing.T, addr string, key string, wan bool) { ui := new(cli.MockUi) 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/website/source/docs/commands/keyring.html.markdown b/website/source/docs/commands/keyring.html.markdown index ff3285dc68..6a635746c2 100644 --- a/website/source/docs/commands/keyring.html.markdown +++ b/website/source/docs/commands/keyring.html.markdown @@ -14,10 +14,9 @@ distributing new encryption keys to the cluster, retiring old encryption keys, and changing the keys used by the cluster to encrypt messages. Because Consul utilizes multiple gossip pools, this command will only operate -against a server node for most operations. All members in a Consul cluster, -regardless of operational mode (client or server) or datacenter, will be -modified/queried each time this command is run. This helps maintain operational -simplicity by managing the multiple pools as a single unit. +against a server node for most operations. By default, all operations carried +out by this command are run against the LAN gossip pool in the datacenter of the +agent. 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 @@ -60,4 +59,6 @@ The list of available flags are: * `-list` - List all keys currently in use within the cluster. +* `-wan` - Operate on the WAN keyring instead of the LAN keyring (default) + * `-rpc-addr` - RPC address of the Consul agent.