From b6037ef323f57d51d5cfbf0a6eca8b73ce1595eb Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Thu, 11 Sep 2014 22:28:23 -0700 Subject: [PATCH] agent: clean up keyring file implementation --- command/agent/agent.go | 79 ++++++++++++++++++++++++---------------- command/agent/command.go | 7 +++- command/agent/config.go | 9 +++-- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/command/agent/agent.go b/command/agent/agent.go index 5453f4ad95..781ecc90a0 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -19,6 +19,11 @@ import ( "github.com/hashicorp/serf/serf" ) +const ( + serfLANKeyring = "serf/local.keyring" + serfWANKeyring = "serf/remote.keyring" +) + /* The agent is the long running process that is run on every machine. It exposes an RPC interface that is used by the CLI to control the @@ -116,37 +121,14 @@ func Create(config *Config, logOutput io.Writer) (*Agent, error) { // Setup encryption keyring files if config.PersistKeyring && config.EncryptKey != "" { - serfDir := filepath.Join(config.DataDir, "serf") - if err := os.MkdirAll(serfDir, 0700); err != nil { - return nil, err - } - - keys := []string{config.EncryptKey} - keyringBytes, err := json.MarshalIndent(keys, "", " ") - if err != nil { - return nil, err - } - - paths := []string{ - filepath.Join(serfDir, "keyring_lan"), - filepath.Join(serfDir, "keyring_wan"), - } - - for _, path := range paths { - if _, err := os.Stat(path); err == nil { - continue - } - fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) - if err != nil { - return nil, err - } - defer fh.Close() - - if _, err := fh.Write(keyringBytes); err != nil { - os.Remove(path) + if config.Server { + if err := agent.initKeyringFile(serfWANKeyring); err != nil { return nil, err } } + if err := agent.initKeyringFile(serfLANKeyring); err != nil { + return nil, err + } } // Setup either the client or the server @@ -206,9 +188,8 @@ func (a *Agent) consulConfig() *consul.Config { base.SerfWANConfig.MemberlistConfig.SecretKey = key } if a.config.PersistKeyring { - lanKeyring := filepath.Join(base.DataDir, "serf", "keyring_lan") - wanKeyring := filepath.Join(base.DataDir, "serf", "keyring_wan") - + lanKeyring := filepath.Join(base.DataDir, serfLANKeyring) + wanKeyring := filepath.Join(base.DataDir, serfWANKeyring) base.SerfLANConfig.KeyringFile = lanKeyring base.SerfWANConfig.KeyringFile = wanKeyring } @@ -825,3 +806,39 @@ func (a *Agent) RemoveKeyLAN(key string) (*serf.KeyResponse, error) { km := a.client.KeyManagerLAN() return km.RemoveKey(key) } + +// initKeyringFile is used to create and initialize a persistent keyring file +// for gossip encryption keys. It is used at agent startup to dump the initial +// encryption key into a keyfile if persistence is enabled. +func (a *Agent) initKeyringFile(path string) error { + serfDir := filepath.Join(a.config.DataDir, "serf") + if err := os.MkdirAll(serfDir, 0700); err != nil { + return err + } + + keys := []string{a.config.EncryptKey} + keyringBytes, err := json.MarshalIndent(keys, "", " ") + if err != nil { + return err + } + + keyringFile := filepath.Join(a.config.DataDir, path) + + // If the keyring file already exists, don't re-initialize + if _, err := os.Stat(keyringFile); err == nil { + return nil + } + + fh, err := os.OpenFile(keyringFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) + if err != nil { + return err + } + defer fh.Close() + + if _, err := fh.Write(keyringBytes); err != nil { + os.Remove(keyringFile) + return err + } + + return nil +} diff --git a/command/agent/command.go b/command/agent/command.go index 6f1da6cf7a..94b6eacd30 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -220,7 +220,7 @@ func (c *Command) readConfig() *Config { } // Warn if an encryption key is passed while a keyring already exists - if config.EncryptKey != "" && config.CheckKeyringFiles() { + if config.EncryptKey != "" && (config.PersistKeyring && config.CheckKeyringFiles()) { c.Ui.Error(fmt.Sprintf( "WARNING: Keyring already exists, ignoring new key %s", config.EncryptKey)) @@ -594,7 +594,10 @@ func (c *Command) Run(args []string) int { } // Determine if gossip is encrypted - gossipEncrypted := (config.EncryptKey != "" || config.CheckKeyringFiles()) + gossipEncrypted := false + if config.EncryptKey != "" || (config.PersistKeyring && config.CheckKeyringFiles()) { + gossipEncrypted = true + } // Let the agent know we've finished registration c.agent.StartSync() diff --git a/command/agent/config.go b/command/agent/config.go index cb35961674..e4c1ee73aa 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -418,12 +418,13 @@ func (c *Config) ClientListenerAddr(override string, port int) (string, error) { // CheckKeyringFiles checks for existence of the keyring files for Serf func (c *Config) CheckKeyringFiles() bool { - serfDir := filepath.Join(c.DataDir, "serf") - if _, err := os.Stat(filepath.Join(serfDir, "keyring_lan")); err != nil { + if _, err := os.Stat(filepath.Join(c.DataDir, serfLANKeyring)); err != nil { return false } - if _, err := os.Stat(filepath.Join(serfDir, "keyring_wan")); err != nil { - return false + if c.Server { + if _, err := os.Stat(filepath.Join(c.DataDir, serfWANKeyring)); err != nil { + return false + } } return true }