agent: fix loading keyring on agent start

This commit is contained in:
Ryan Uber 2014-10-10 11:13:30 -07:00
parent ab5fbe4094
commit 8a652c6ffa
5 changed files with 66 additions and 72 deletions

View File

@ -161,11 +161,6 @@ func (a *Agent) consulConfig() *consul.Config {
if a.config.DataDir != "" { if a.config.DataDir != "" {
base.DataDir = a.config.DataDir base.DataDir = a.config.DataDir
} }
if a.config.EncryptKey != "" {
key, _ := a.config.EncryptBytes()
base.SerfLANConfig.MemberlistConfig.SecretKey = key
base.SerfWANConfig.MemberlistConfig.SecretKey = key
}
if a.config.NodeName != "" { if a.config.NodeName != "" {
base.NodeName = a.config.NodeName base.NodeName = a.config.NodeName
} }
@ -263,21 +258,8 @@ func (a *Agent) consulConfig() *consul.Config {
func (a *Agent) setupServer() error { func (a *Agent) setupServer() error {
config := a.consulConfig() config := a.consulConfig()
// Load a keyring file, if present if err := a.setupKeyrings(config); err != nil {
keyfileLAN := filepath.Join(config.DataDir, serfLANKeyring) return fmt.Errorf("Failed to configure keyring: %v", err)
if _, err := os.Stat(keyfileLAN); err == nil {
config.SerfLANConfig.KeyringFile = keyfileLAN
}
if err := loadKeyringFile(config.SerfLANConfig); err != nil {
return err
}
keyfileWAN := filepath.Join(config.DataDir, serfWANKeyring)
if _, err := os.Stat(keyfileWAN); err == nil {
config.SerfWANConfig.KeyringFile = keyfileWAN
}
if err := loadKeyringFile(config.SerfWANConfig); err != nil {
return err
} }
server, err := consul.NewServer(config) server, err := consul.NewServer(config)
@ -292,13 +274,8 @@ func (a *Agent) setupServer() error {
func (a *Agent) setupClient() error { func (a *Agent) setupClient() error {
config := a.consulConfig() config := a.consulConfig()
// Load a keyring file, if present if err := a.setupKeyrings(config); err != nil {
keyfileLAN := filepath.Join(config.DataDir, serfLANKeyring) return fmt.Errorf("Failed to configure keyring: %v", err)
if _, err := os.Stat(keyfileLAN); err == nil {
config.SerfLANConfig.KeyringFile = keyfileLAN
}
if err := loadKeyringFile(config.SerfLANConfig); err != nil {
return err
} }
client, err := consul.NewClient(config) client, err := consul.NewClient(config)
@ -309,6 +286,47 @@ func (a *Agent) setupClient() error {
return nil return nil
} }
// setupKeyrings is used to initialize and load keyrings during agent startup
func (a *Agent) setupKeyrings(config *consul.Config) error {
fileLAN := filepath.Join(a.config.DataDir, serfLANKeyring)
fileWAN := filepath.Join(a.config.DataDir, serfWANKeyring)
if a.config.EncryptKey == "" {
goto LOAD
}
if _, err := os.Stat(fileLAN); err != nil {
if err := initKeyring(fileLAN, a.config.EncryptKey); err != nil {
return err
}
}
if a.config.Server {
if _, err := os.Stat(fileWAN); err != nil {
if err := initKeyring(fileWAN, a.config.EncryptKey); err != nil {
return err
}
}
}
LOAD:
if _, err := os.Stat(fileLAN); err == nil {
config.SerfLANConfig.KeyringFile = fileLAN
}
if err := loadKeyringFile(config.SerfLANConfig); err != nil {
return err
}
if a.config.Server {
if _, err := os.Stat(fileWAN); err == nil {
config.SerfWANConfig.KeyringFile = fileWAN
}
if err := loadKeyringFile(config.SerfWANConfig); err != nil {
return err
}
}
// Success!
return nil
}
// RPC is used to make an RPC call to the Consul servers // RPC is used to make an RPC call to the Consul servers
// This allows the agent to implement the Consul.Interface // This allows the agent to implement the Consul.Interface
func (a *Agent) RPC(method string, args interface{}, reply interface{}) error { func (a *Agent) RPC(method string, args interface{}, reply interface{}) error {

View File

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

View File

@ -154,30 +154,14 @@ func (c *Command) readConfig() *Config {
c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err)) c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
return nil return nil
} }
keyfileLAN := filepath.Join(config.DataDir, serfLANKeyring)
fileLAN := filepath.Join(config.DataDir, serfLANKeyring) if _, err := os.Stat(keyfileLAN); err == nil {
done, err := initKeyring(fileLAN, config.EncryptKey) c.Ui.Error("WARNING: LAN keyring exists but -encrypt given, ignoring")
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 { if config.Server {
fileWAN := filepath.Join(config.DataDir, serfWANKeyring) keyfileWAN := filepath.Join(config.DataDir, serfWANKeyring)
done, err := initKeyring(fileWAN, config.EncryptKey) if _, err := os.Stat(keyfileWAN); err == nil {
if err != nil { c.Ui.Error("WARNING: WAN keyring exists but -encrypt given, ignoring")
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,42 +18,41 @@ const (
serfWANKeyring = "serf/remote.keyring" serfWANKeyring = "serf/remote.keyring"
) )
// initKeyring will create a keyring file at a given path. Returns whether any // initKeyring will create a keyring file at a given path.
// action was taken and any applicable error. func initKeyring(path, key string) error {
func initKeyring(path, key string) (bool, error) {
var keys []string var keys []string
if _, err := base64.StdEncoding.DecodeString(key); err != nil { if _, err := base64.StdEncoding.DecodeString(key); err != nil {
return false, fmt.Errorf("Invalid key: %s", err) return fmt.Errorf("Invalid key: %s", err)
} }
// Just exit if the file already exists. // Just exit if the file already exists.
if _, err := os.Stat(path); err == nil { if _, err := os.Stat(path); err == nil {
return false, nil return nil
} }
keys = append(keys, key) keys = append(keys, key)
keyringBytes, err := json.Marshal(keys) keyringBytes, err := json.Marshal(keys)
if err != nil { if err != nil {
return false, err return err
} }
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return false, err return err
} }
fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil { if err != nil {
return false, err return err
} }
defer fh.Close() defer fh.Close()
if _, err := fh.Write(keyringBytes); err != nil { if _, err := fh.Write(keyringBytes); err != nil {
os.Remove(path) os.Remove(path)
return false, err return err
} }
return true, nil return nil
} }
// loadKeyringFile will load a gossip encryption keyring out of a file. The file // loadKeyringFile will load a gossip encryption keyring out of a file. The file

View File

@ -66,7 +66,7 @@ func TestAgent_LoadKeyrings(t *testing.T) {
t.Fatalf("keyring should be loaded") t.Fatalf("keyring should be loaded")
} }
if c.SerfWANConfig.KeyringFile != "" { if c.SerfWANConfig.KeyringFile != "" {
t.Fatalf("bad: %#v", c.SerfLANConfig.KeyringFile) t.Fatalf("bad: %#v", c.SerfWANConfig.KeyringFile)
} }
if c.SerfWANConfig.MemberlistConfig.Keyring != nil { if c.SerfWANConfig.MemberlistConfig.Keyring != nil {
t.Fatalf("keyring should not be loaded") t.Fatalf("keyring should not be loaded")
@ -87,13 +87,9 @@ func TestAgent_InitKeyring(t *testing.T) {
file := filepath.Join(dir, "keyring") file := filepath.Join(dir, "keyring")
// First initialize the keyring // First initialize the keyring
done, err := initKeyring(file, key1) if err := initKeyring(file, key1); err != nil {
if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if !done {
t.Fatalf("should have modified keyring")
}
content, err := ioutil.ReadFile(file) content, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
@ -104,14 +100,11 @@ func TestAgent_InitKeyring(t *testing.T) {
} }
// Try initializing again with a different key // Try initializing again with a different key
done, err = initKeyring(file, key2) if err := initKeyring(file, key2); err != nil {
if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if done {
t.Fatalf("should not have modified keyring")
}
// Content should still be the same
content, err = ioutil.ReadFile(file) content, err = ioutil.ReadFile(file)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)