Prevents disabling gossip keyring file from disabling gossip encryption. (#3278)

This commit is contained in:
James Phillips 2017-07-17 12:48:45 -07:00 committed by GitHub
parent 164262ec40
commit fff0f9698f
3 changed files with 237 additions and 62 deletions

View File

@ -794,10 +794,9 @@ func (a *Agent) consulConfig() (*consul.Config, error) {
// Setup the loggers
base.LogOutput = a.LogOutput
if !a.config.DisableKeyringFile {
if err := a.setupKeyrings(base); err != nil {
return nil, fmt.Errorf("Failed to configure keyring: %v", err)
}
// This will set up the LAN keyring, as well as the WAN for servers.
if err := a.setupKeyrings(base); err != nil {
return nil, fmt.Errorf("Failed to configure keyring: %v", err)
}
return base, nil
@ -1026,6 +1025,26 @@ func (a *Agent) setupNodeID(config *Config) error {
// setupKeyrings is used to initialize and load keyrings during agent startup
func (a *Agent) setupKeyrings(config *consul.Config) error {
// If the keyring file is disabled then just poke the provided key
// into the in-memory keyring.
if a.config.DisableKeyringFile {
if a.config.EncryptKey == "" {
return nil
}
keys := []string{a.config.EncryptKey}
if err := loadKeyring(config.SerfLANConfig, keys); err != nil {
return err
}
if a.config.Server {
if err := loadKeyring(config.SerfWANConfig, keys); err != nil {
return err
}
}
return nil
}
// Otherwise, we need to deal with the keyring files.
fileLAN := filepath.Join(a.config.DataDir, SerfLANKeyring)
fileWAN := filepath.Join(a.config.DataDir, SerfWANKeyring)
@ -1061,7 +1080,6 @@ LOAD:
}
}
// Success!
return nil
}

View File

@ -69,19 +69,22 @@ func loadKeyringFile(c *serf.Config) error {
return err
}
// Read in the keyring file data
keyringData, err := ioutil.ReadFile(c.KeyringFile)
if err != nil {
return err
}
// Decode keyring JSON
keys := make([]string, 0)
if err := json.Unmarshal(keyringData, &keys); err != nil {
return err
}
// Decode base64 values
return loadKeyring(c, keys)
}
// loadKeyring takes a list of base64-encoded strings and installs them in the
// given Serf's keyring.
func loadKeyring(c *serf.Config, keys []string) error {
keysDecoded := make([][]byte, len(keys))
for i, key := range keys {
keyBytes, err := base64.StdEncoding.DecodeString(key)
@ -91,20 +94,16 @@ func loadKeyringFile(c *serf.Config) error {
keysDecoded[i] = keyBytes
}
// Guard against empty keyring
if len(keysDecoded) == 0 {
return fmt.Errorf("no keys present in keyring file: %s", c.KeyringFile)
return fmt.Errorf("no keys present in keyring: %s", c.KeyringFile)
}
// Create the keyring
keyring, err := memberlist.NewKeyring(keysDecoded, keysDecoded[0])
if err != nil {
return err
}
c.MemberlistConfig.Keyring = keyring
// Success!
return nil
}

View File

@ -1,6 +1,8 @@
package agent
import (
"bytes"
"encoding/base64"
"fmt"
"io/ioutil"
"os"
@ -9,69 +11,225 @@ import (
"testing"
"github.com/hashicorp/consul/testutil"
"github.com/hashicorp/memberlist"
)
func checkForKey(key string, keyring *memberlist.Keyring) error {
rk, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return err
}
pk := keyring.GetPrimaryKey()
if !bytes.Equal(rk, pk) {
return fmt.Errorf("got %q want %q", pk, rk)
}
return nil
}
func TestAgent_LoadKeyrings(t *testing.T) {
t.Parallel()
key := "tbLJg26ZJyJ9pK3qhc9jig=="
// Should be no configured keyring file by default
a1 := NewTestAgent(t.Name(), nil)
defer a1.Shutdown()
t.Run("no keys", func(t *testing.T) {
a1 := NewTestAgent(t.Name(), nil)
defer a1.Shutdown()
c1 := a1.Config.ConsulConfig
if c1.SerfLANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfLANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
if c1.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
c1 := a1.Config.ConsulConfig
if c1.SerfLANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfLANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
if c1.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
})
// Server should auto-load LAN and WAN keyring files
a2 := &TestAgent{Name: t.Name(), Key: key}
a2.Start()
defer a2.Shutdown()
t.Run("server with keys", func(t *testing.T) {
a2 := &TestAgent{Name: t.Name(), Key: key}
a2.Start()
defer a2.Shutdown()
c2 := a2.Config.ConsulConfig
if c2.SerfLANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c2.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if c2.SerfWANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c2.SerfWANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
c2 := a2.Config.ConsulConfig
if c2.SerfLANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c2.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c2.SerfLANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
if c2.SerfWANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c2.SerfWANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c2.SerfWANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
})
// Client should auto-load only the LAN keyring file
cfg3 := TestConfig()
cfg3.Server = false
a3 := &TestAgent{Name: t.Name(), Config: cfg3, Key: key}
a3.Start()
defer a3.Shutdown()
t.Run("client with keys", func(t *testing.T) {
cfg3 := TestConfig()
cfg3.Server = false
a3 := &TestAgent{Name: t.Name(), Config: cfg3, Key: key}
a3.Start()
defer a3.Shutdown()
c3 := a3.Config.ConsulConfig
if c3.SerfLANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c3.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if c3.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c3.SerfWANConfig.KeyringFile)
}
if c3.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
c3 := a3.Config.ConsulConfig
if c3.SerfLANConfig.KeyringFile == "" {
t.Fatalf("should have keyring file")
}
if c3.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c3.SerfLANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
if c3.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c3.SerfWANConfig.KeyringFile)
}
if c3.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
})
}
func TestAgent_InmemKeyrings(t *testing.T) {
t.Parallel()
key := "tbLJg26ZJyJ9pK3qhc9jig=="
// Should be no configured keyring file by default
t.Run("no keys", func(t *testing.T) {
a1 := NewTestAgent(t.Name(), nil)
defer a1.Shutdown()
c1 := a1.Config.ConsulConfig
if c1.SerfLANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfLANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
if c1.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c1.SerfLANConfig.KeyringFile)
}
if c1.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
})
// Server should auto-load LAN and WAN keyring
t.Run("server with keys", func(t *testing.T) {
cfg2 := TestConfig()
cfg2.EncryptKey = key
cfg2.DisableKeyringFile = true
a2 := &TestAgent{Name: t.Name(), Config: cfg2}
a2.Start()
defer a2.Shutdown()
c2 := a2.Config.ConsulConfig
if c2.SerfLANConfig.KeyringFile != "" {
t.Fatalf("should not have keyring file")
}
if c2.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c2.SerfLANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
if c2.SerfWANConfig.KeyringFile != "" {
t.Fatalf("should not have keyring file")
}
if c2.SerfWANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c2.SerfWANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
})
// Client should auto-load only the LAN keyring
t.Run("client with keys", func(t *testing.T) {
cfg3 := TestConfig()
cfg3.EncryptKey = key
cfg3.DisableKeyringFile = true
cfg3.Server = false
a3 := &TestAgent{Name: t.Name(), Config: cfg3}
a3.Start()
defer a3.Shutdown()
c3 := a3.Config.ConsulConfig
if c3.SerfLANConfig.KeyringFile != "" {
t.Fatalf("should not have keyring file")
}
if c3.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c3.SerfLANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
if c3.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c3.SerfWANConfig.KeyringFile)
}
if c3.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded")
}
})
// Any keyring files should be ignored
t.Run("ignore files", func(t *testing.T) {
dir := testutil.TempDir(t, "consul")
defer os.RemoveAll(dir)
badKey := "unUzC2X3JgMKVJlZna5KVg=="
if err := initKeyring(filepath.Join(dir, SerfLANKeyring), badKey); err != nil {
t.Fatalf("err: %v", err)
}
if err := initKeyring(filepath.Join(dir, SerfWANKeyring), badKey); err != nil {
t.Fatalf("err: %v", err)
}
cfg4 := TestConfig()
cfg4.EncryptKey = key
cfg4.DisableKeyringFile = true
cfg4.DataDir = dir
a4 := &TestAgent{Name: t.Name(), Config: cfg4}
a4.Start()
defer a4.Shutdown()
c4 := a4.Config.ConsulConfig
if c4.SerfLANConfig.KeyringFile != "" {
t.Fatalf("should not have keyring file")
}
if c4.SerfLANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c4.SerfLANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
if c4.SerfWANConfig.KeyringFile != "" {
t.Fatalf("should not have keyring file")
}
if c4.SerfWANConfig.MemberlistConfig.Keyring == nil {
t.Fatalf("keyring should be loaded")
}
if err := checkForKey(key, c4.SerfWANConfig.MemberlistConfig.Keyring); err != nil {
t.Fatalf("err: %v", err)
}
})
}
func TestAgent_InitKeyring(t *testing.T) {