agent: ignore -encrypt if provided when keyring exists

This commit is contained in:
Ryan Uber 2014-10-09 15:28:38 -07:00
parent 4203e7ab6d
commit ab5fbe4094
5 changed files with 45 additions and 64 deletions

View File

@ -81,11 +81,11 @@ func makeAgentKeyring(t *testing.T, conf *Config, key string) (string, *Agent) {
conf.DataDir = dir
fileLAN := filepath.Join(dir, serfLANKeyring)
if err := initKeyring(fileLAN, key); err != nil {
if _, err := initKeyring(fileLAN, key); err != nil {
t.Fatalf("err: %s", err)
}
fileWAN := filepath.Join(dir, serfWANKeyring)
if err := initKeyring(fileWAN, key); err != nil {
if _, err := initKeyring(fileWAN, key); err != nil {
t.Fatalf("err: %s", err)
}

View File

@ -156,17 +156,29 @@ func (c *Command) readConfig() *Config {
}
fileLAN := filepath.Join(config.DataDir, serfLANKeyring)
if err := initKeyring(fileLAN, config.EncryptKey); err != nil {
done, err := initKeyring(fileLAN, config.EncryptKey)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing keyring: %s", err))
return nil
}
if !done {
c.Ui.Error(fmt.Sprintf(
"WARNING: keyring file %s already exists, not overwriting",
fileLAN))
}
if config.Server {
fileWAN := filepath.Join(config.DataDir, serfWANKeyring)
if err := initKeyring(fileWAN, config.EncryptKey); err != nil {
done, err := initKeyring(fileWAN, config.EncryptKey)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing keyring: %s", err))
return nil
}
if !done {
c.Ui.Error(fmt.Sprintf(
"WARNING: keyring file %s already exists, not overwriting",
fileWAN))
}
}
}

View File

@ -18,51 +18,42 @@ const (
serfWANKeyring = "serf/remote.keyring"
)
// initKeyring will create a keyring file at a given path.
func initKeyring(path, key string) error {
// initKeyring will create a keyring file at a given path. Returns whether any
// action was taken and any applicable error.
func initKeyring(path, key string) (bool, error) {
var keys []string
if _, err := base64.StdEncoding.DecodeString(key); err != nil {
return fmt.Errorf("Invalid key: %s", err)
return false, fmt.Errorf("Invalid key: %s", err)
}
// Just exit if the file already exists.
if _, err := os.Stat(path); err == nil {
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if err := json.Unmarshal(content, &keys); err != nil {
return err
}
for _, existing := range keys {
if key == existing {
return nil
}
}
return false, nil
}
keys = append(keys, key)
keyringBytes, err := json.Marshal(keys)
if err != nil {
return err
return false, err
}
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return err
return false, err
}
fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return err
return false, err
}
defer fh.Close()
if _, err := fh.Write(keyringBytes); err != nil {
os.Remove(path)
return err
return false, err
}
return nil
return true, nil
}
// loadKeyringFile will load a gossip encryption keyring out of a file. The file

View File

@ -1,12 +1,10 @@
package agent
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
@ -78,6 +76,7 @@ func TestAgent_LoadKeyrings(t *testing.T) {
func TestAgent_InitKeyring(t *testing.T) {
key1 := "tbLJg26ZJyJ9pK3qhc9jig=="
key2 := "4leC33rgtXKIVUr9Nr0snQ=="
expected := fmt.Sprintf(`["%s"]`, key1)
dir, err := ioutil.TempDir("", "consul")
if err != nil {
@ -88,56 +87,36 @@ func TestAgent_InitKeyring(t *testing.T) {
file := filepath.Join(dir, "keyring")
// First initialize the keyring
if err := initKeyring(file, key1); err != nil {
t.Fatalf("err: %s", err)
}
content1, err := ioutil.ReadFile(file)
done, err := initKeyring(file, key1)
if err != nil {
t.Fatalf("err: %s", err)
}
if !strings.Contains(string(content1), key1) {
t.Fatalf("bad: %s", content1)
}
if strings.Contains(string(content1), key2) {
t.Fatalf("bad: %s", content1)
if !done {
t.Fatalf("should have modified keyring")
}
// Now initialize again with the same key
if err := initKeyring(file, key1); err != nil {
t.Fatalf("err: %s", err)
}
content2, err := ioutil.ReadFile(file)
content, err := ioutil.ReadFile(file)
if err != nil {
t.Fatalf("err: %s", err)
}
if !bytes.Equal(content1, content2) {
t.Fatalf("bad: %s", content2)
if string(content) != expected {
t.Fatalf("bad: %s", content)
}
// Initialize an existing keyring with a new key
if err := initKeyring(file, key2); err != nil {
t.Fatalf("err: %s", err)
}
content3, err := ioutil.ReadFile(file)
// Try initializing again with a different key
done, err = initKeyring(file, key2)
if err != nil {
t.Fatalf("err: %s", err)
}
if !strings.Contains(string(content3), key1) {
t.Fatalf("bad: %s", content3)
}
if !strings.Contains(string(content3), key2) {
t.Fatalf("bad: %s", content3)
if done {
t.Fatalf("should not have modified keyring")
}
// Unmarshal and make sure that key1 is still primary
var keys []string
if err := json.Unmarshal(content3, &keys); err != nil {
content, err = ioutil.ReadFile(file)
if err != nil {
t.Fatalf("err: %s", err)
}
if keys[0] != key1 {
t.Fatalf("bad: %#v", keys)
if string(content) != expected {
t.Fatalf("bad: %s", content)
}
}

View File

@ -93,9 +93,8 @@ The options below are all specified on the command-line.
automatically whenever the agent is restarted. This means that to encrypt
Consul's gossip protocol, this option only needs to be provided once on each
agent's initial startup sequence. If it is provided after Consul has been
initialized with an encryption key, then the provided key is simply added
as a secondary encryption key. More information on how keys can be changed
is available on the [keyring command](/docs/commands/keyring.html) page.
initialized with an encryption key, then the provided key is ignored and
a warning will be displayed.
* `-join` - Address of another agent to join upon starting up. This can be
specified multiple times to specify multiple agents to join. If Consul is