mirror of https://github.com/hashicorp/consul
consul: first pass at keyring integration
parent
6c83ef119a
commit
e20a724999
|
@ -1,16 +1,21 @@
|
||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/consul"
|
"github.com/hashicorp/consul/consul"
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
|
"github.com/hashicorp/memberlist"
|
||||||
"github.com/hashicorp/serf/serf"
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -109,6 +114,33 @@ func Create(config *Config, logOutput io.Writer) (*Agent, error) {
|
||||||
// Initialize the local state
|
// Initialize the local state
|
||||||
agent.state.Init(config, agent.logger)
|
agent.state.Init(config, agent.logger)
|
||||||
|
|
||||||
|
// Setup encryption keyring files
|
||||||
|
if !config.DisableKeyring && config.EncryptKey != "" {
|
||||||
|
keyringBytes, err := json.MarshalIndent([]string{config.EncryptKey})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
paths := []string{
|
||||||
|
filepath.Join(config.DataDir, "serf", "keyring_lan"),
|
||||||
|
filepath.Join(config.DataDir, "serf", "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)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setup either the client or the server
|
// Setup either the client or the server
|
||||||
var err error
|
var err error
|
||||||
if config.Server {
|
if config.Server {
|
||||||
|
@ -160,11 +192,21 @@ 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 != "" {
|
if a.config.EncryptKey != "" && a.config.DisableKeyring {
|
||||||
key, _ := a.config.EncryptBytes()
|
key, _ := a.config.EncryptBytes()
|
||||||
base.SerfLANConfig.MemberlistConfig.SecretKey = key
|
base.SerfLANConfig.MemberlistConfig.SecretKey = key
|
||||||
base.SerfWANConfig.MemberlistConfig.SecretKey = key
|
base.SerfWANConfig.MemberlistConfig.SecretKey = key
|
||||||
}
|
}
|
||||||
|
if !a.config.DisableKeyring {
|
||||||
|
lanKeyring := filepath.Join(base.DataDir, "serf", "keyring_lan")
|
||||||
|
wanKeyring := filepath.Join(base.DataDir, "serf", "keyring_wan")
|
||||||
|
|
||||||
|
base.SerfLANConfig.KeyringFile = lanKeyring
|
||||||
|
base.SerfWANConfig.KeyringFile = wanKeyring
|
||||||
|
|
||||||
|
base.SerfLANConfig.MemberlistConfig.Keyring = loadKeyringFile(lanKeyring)
|
||||||
|
base.SerfWANConfig.MemberlistConfig.Keyring = loadKeyringFile(wanKeyring)
|
||||||
|
}
|
||||||
if a.config.NodeName != "" {
|
if a.config.NodeName != "" {
|
||||||
base.NodeName = a.config.NodeName
|
base.NodeName = a.config.NodeName
|
||||||
}
|
}
|
||||||
|
@ -253,6 +295,9 @@ func (a *Agent) consulConfig() *consul.Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup gossip keyring configuration
|
||||||
|
base.DisableKeyring = a.config.DisableKeyring
|
||||||
|
|
||||||
// Setup the loggers
|
// Setup the loggers
|
||||||
base.LogOutput = a.logOutput
|
base.LogOutput = a.logOutput
|
||||||
return base
|
return base
|
||||||
|
@ -648,3 +693,41 @@ func (a *Agent) deletePid() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadKeyringFile will load a keyring out of a file
|
||||||
|
func loadKeyringFile(keyringFile string) *memberlist.Keyring {
|
||||||
|
if _, err := os.Stat(keyringFile); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in the keyring file data
|
||||||
|
keyringData, err := ioutil.ReadFile(keyringFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode keyring JSON
|
||||||
|
keys := make([]string, 0)
|
||||||
|
if err := json.Unmarshal(keyringData, &keys); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode base64 values
|
||||||
|
keysDecoded := make([][]byte, len(keys))
|
||||||
|
for i, key := range keys {
|
||||||
|
keyBytes, err := base64.StdEncoding.DecodeString(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
keysDecoded[i] = keyBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the keyring
|
||||||
|
keyring, err := memberlist.NewKeyring(keysDecoded, keysDecoded[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
return keyring
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ func (c *Command) readConfig() *Config {
|
||||||
cmdFlags.StringVar(&cmdConfig.UiDir, "ui-dir", "", "path to the web UI directory")
|
cmdFlags.StringVar(&cmdConfig.UiDir, "ui-dir", "", "path to the web UI directory")
|
||||||
cmdFlags.StringVar(&cmdConfig.PidFile, "pid-file", "", "path to file to store PID")
|
cmdFlags.StringVar(&cmdConfig.PidFile, "pid-file", "", "path to file to store PID")
|
||||||
cmdFlags.StringVar(&cmdConfig.EncryptKey, "encrypt", "", "gossip encryption key")
|
cmdFlags.StringVar(&cmdConfig.EncryptKey, "encrypt", "", "gossip encryption key")
|
||||||
|
cmdFlags.BoolVar(&cmdConfig.DisableKeyring, "disable-keyring", false, "disable use of encryption keyring")
|
||||||
|
|
||||||
cmdFlags.BoolVar(&cmdConfig.Server, "server", false, "run agent as server")
|
cmdFlags.BoolVar(&cmdConfig.Server, "server", false, "run agent as server")
|
||||||
cmdFlags.BoolVar(&cmdConfig.Bootstrap, "bootstrap", false, "enable server bootstrap mode")
|
cmdFlags.BoolVar(&cmdConfig.Bootstrap, "bootstrap", false, "enable server bootstrap mode")
|
||||||
|
@ -143,13 +144,6 @@ func (c *Command) readConfig() *Config {
|
||||||
config.NodeName = hostname
|
config.NodeName = hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.EncryptKey != "" {
|
|
||||||
if _, err := config.EncryptBytes(); err != nil {
|
|
||||||
c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we have a data directory
|
// Ensure we have a data directory
|
||||||
if config.DataDir == "" {
|
if config.DataDir == "" {
|
||||||
c.Ui.Error("Must specify data directory using -data-dir")
|
c.Ui.Error("Must specify data directory using -data-dir")
|
||||||
|
@ -180,6 +174,13 @@ func (c *Command) readConfig() *Config {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.EncryptKey != "" {
|
||||||
|
if _, err := config.EncryptBytes(); err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compile all the watches
|
// Compile all the watches
|
||||||
for _, params := range config.Watches {
|
for _, params := range config.Watches {
|
||||||
// Parse the watches, excluding the handler
|
// Parse the watches, excluding the handler
|
||||||
|
|
|
@ -104,6 +104,9 @@ type Config struct {
|
||||||
// recursors array.
|
// recursors array.
|
||||||
DNSRecursor string `mapstructure:"recursor"`
|
DNSRecursor string `mapstructure:"recursor"`
|
||||||
|
|
||||||
|
// Disable use of an encryption keyring.
|
||||||
|
DisableKeyring bool `mapstructure:"disable_keyring"`
|
||||||
|
|
||||||
// DNSRecursors can be set to allow the DNS servers to recursively
|
// DNSRecursors can be set to allow the DNS servers to recursively
|
||||||
// resolve non-consul domains
|
// resolve non-consul domains
|
||||||
DNSRecursors []string `mapstructure:"recursors"`
|
DNSRecursors []string `mapstructure:"recursors"`
|
||||||
|
@ -676,6 +679,9 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
if b.EncryptKey != "" {
|
if b.EncryptKey != "" {
|
||||||
result.EncryptKey = b.EncryptKey
|
result.EncryptKey = b.EncryptKey
|
||||||
}
|
}
|
||||||
|
if b.DisableKeyring {
|
||||||
|
result.DisableKeyring = true
|
||||||
|
}
|
||||||
if b.LogLevel != "" {
|
if b.LogLevel != "" {
|
||||||
result.LogLevel = b.LogLevel
|
result.LogLevel = b.LogLevel
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,11 @@ type Config struct {
|
||||||
// UserEventHandler callback can be used to handle incoming
|
// UserEventHandler callback can be used to handle incoming
|
||||||
// user events. This function should not block.
|
// user events. This function should not block.
|
||||||
UserEventHandler func(serf.UserEvent)
|
UserEventHandler func(serf.UserEvent)
|
||||||
|
|
||||||
|
// DisableKeyring is used to disable persisting the encryption keyring to
|
||||||
|
// filesystem. By default, if encryption is enabled, Consul will create a
|
||||||
|
// file inside of the DataDir to keep track of changes made to the ring.
|
||||||
|
DisableKeyring bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckVersion is used to check if the ProtocolVersion is valid
|
// CheckVersion is used to check if the ProtocolVersion is valid
|
||||||
|
|
Loading…
Reference in New Issue