mirror of https://github.com/hashicorp/consul
command: remove -init argument from keyring, auto-persist keyrings when using agent -encrypt
parent
1f9d13dc73
commit
7a74f559b9
|
@ -264,17 +264,18 @@ func (a *Agent) setupServer() error {
|
|||
config := a.consulConfig()
|
||||
|
||||
// Load a keyring file, if present
|
||||
keyfileLAN := filepath.Join(config.DataDir, SerfLANKeyring)
|
||||
keyfileLAN := filepath.Join(config.DataDir, serfLANKeyring)
|
||||
if _, err := os.Stat(keyfileLAN); err == nil {
|
||||
config.SerfLANConfig.KeyringFile = keyfileLAN
|
||||
}
|
||||
keyfileWAN := filepath.Join(config.DataDir, SerfWANKeyring)
|
||||
if _, err := os.Stat(keyfileWAN); err == nil {
|
||||
config.SerfWANConfig.KeyringFile = keyfileWAN
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -292,7 +293,7 @@ func (a *Agent) setupClient() error {
|
|||
config := a.consulConfig()
|
||||
|
||||
// Load a keyring file, if present
|
||||
keyfileLAN := filepath.Join(config.DataDir, SerfLANKeyring)
|
||||
keyfileLAN := filepath.Join(config.DataDir, serfLANKeyring)
|
||||
if _, err := os.Stat(keyfileLAN); err == nil {
|
||||
config.SerfLANConfig.KeyringFile = keyfileLAN
|
||||
}
|
||||
|
|
|
@ -143,17 +143,35 @@ func (c *Command) readConfig() *Config {
|
|||
config.NodeName = hostname
|
||||
}
|
||||
|
||||
// Ensure we have a data directory
|
||||
if config.DataDir == "" {
|
||||
c.Ui.Error("Must specify data directory using -data-dir")
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
if config.DataDir == "" {
|
||||
c.Ui.Error("Must specify data directory using -data-dir")
|
||||
return nil
|
||||
fileLAN := filepath.Join(config.DataDir, serfLANKeyring)
|
||||
if _, err := os.Stat(fileLAN); err != nil {
|
||||
initKeyring(fileLAN, config.EncryptKey)
|
||||
} else {
|
||||
c.Ui.Error(fmt.Sprintf("WARNING: %s exists, not using key: %s",
|
||||
fileLAN, config.EncryptKey))
|
||||
}
|
||||
|
||||
if config.Server {
|
||||
fileWAN := filepath.Join(config.DataDir, serfWANKeyring)
|
||||
if _, err := os.Stat(fileWAN); err != nil {
|
||||
initKeyring(fileWAN, config.EncryptKey)
|
||||
} else {
|
||||
c.Ui.Error(fmt.Sprintf("WARNING: %s exists, not using key: %s",
|
||||
fileWAN, config.EncryptKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify data center is valid
|
||||
|
@ -218,12 +236,6 @@ func (c *Command) readConfig() *Config {
|
|||
c.Ui.Error("WARNING: Windows is not recommended as a Consul server. Do not use in production.")
|
||||
}
|
||||
|
||||
// Error if an encryption key is passed while a keyring already exists
|
||||
if config.EncryptKey != "" && config.keyringFileExists() {
|
||||
c.Ui.Error(fmt.Sprintf("Error: -encrypt specified but keyring files exist"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the version info
|
||||
config.Revision = c.Revision
|
||||
config.Version = c.Version
|
||||
|
@ -465,6 +477,22 @@ func (c *Command) retryJoinWan(config *Config, errCh chan<- struct{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// gossipEncrypted determines if the consul instance is using symmetric
|
||||
// encryption keys to protect gossip protocol messages.
|
||||
func (c *Command) gossipEncrypted() bool {
|
||||
if c.agent.config.EncryptKey != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
server := c.agent.server
|
||||
if server != nil {
|
||||
return server.KeyManagerLAN() != nil || server.KeyManagerWAN() != nil
|
||||
}
|
||||
|
||||
client := c.agent.client
|
||||
return client != nil && client.KeyManagerLAN() != nil
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
c.Ui = &cli.PrefixedUi{
|
||||
OutputPrefix: "==> ",
|
||||
|
@ -591,9 +619,6 @@ func (c *Command) Run(args []string) int {
|
|||
}(wp)
|
||||
}
|
||||
|
||||
// Determine if gossip is encrypted
|
||||
gossipEncrypted := config.EncryptKey != "" || config.keyringFileExists()
|
||||
|
||||
// Let the agent know we've finished registration
|
||||
c.agent.StartSync()
|
||||
|
||||
|
@ -606,7 +631,7 @@ func (c *Command) Run(args []string) int {
|
|||
c.Ui.Info(fmt.Sprintf(" Cluster Addr: %v (LAN: %d, WAN: %d)", config.AdvertiseAddr,
|
||||
config.Ports.SerfLan, config.Ports.SerfWan))
|
||||
c.Ui.Info(fmt.Sprintf("Gossip encrypt: %v, RPC-TLS: %v, TLS-Incoming: %v",
|
||||
gossipEncrypted, config.VerifyOutgoing, config.VerifyIncoming))
|
||||
c.gossipEncrypted(), config.VerifyOutgoing, config.VerifyIncoming))
|
||||
|
||||
// Enable log streaming
|
||||
c.Ui.Info("")
|
||||
|
|
|
@ -411,25 +411,6 @@ func (c *Config) ClientListenerAddr(override string, port int) (string, error) {
|
|||
return addr.String(), nil
|
||||
}
|
||||
|
||||
// keyringFileExists determines if there are encryption key files present
|
||||
// in the data directory. On client nodes, this returns true if a LAN keyring
|
||||
// is present. On server nodes, it returns true if either keyring file exists.
|
||||
func (c *Config) keyringFileExists() bool {
|
||||
fileLAN := filepath.Join(c.DataDir, SerfLANKeyring)
|
||||
fileWAN := filepath.Join(c.DataDir, SerfWANKeyring)
|
||||
|
||||
if _, err := os.Stat(fileLAN); err == nil {
|
||||
return true
|
||||
}
|
||||
if !c.Server {
|
||||
return false
|
||||
}
|
||||
if _, err := os.Stat(fileWAN); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DecodeConfig reads the configuration from the given reader in JSON
|
||||
// format and decodes it into a proper Config structure.
|
||||
func DecodeConfig(r io.Reader) (*Config, error) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/consul/consul/structs"
|
||||
"github.com/hashicorp/memberlist"
|
||||
|
@ -13,10 +14,44 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
SerfLANKeyring = "serf/local.keyring"
|
||||
SerfWANKeyring = "serf/remote.keyring"
|
||||
serfLANKeyring = "serf/local.keyring"
|
||||
serfWANKeyring = "serf/remote.keyring"
|
||||
)
|
||||
|
||||
// initKeyring will create a keyring file at a given path.
|
||||
func initKeyring(path, key string) error {
|
||||
if _, err := base64.StdEncoding.DecodeString(key); err != nil {
|
||||
return fmt.Errorf("Invalid key: %s", err)
|
||||
}
|
||||
|
||||
keys := []string{key}
|
||||
keyringBytes, err := json.Marshal(keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return fmt.Errorf("File already exists: %s", path)
|
||||
}
|
||||
|
||||
fh, err := os.OpenFile(path, 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(path)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadKeyringFile will load a gossip encryption keyring out of a file. The file
|
||||
// must be in JSON format and contain a list of encryption key strings.
|
||||
func loadKeyringFile(c *serf.Config) error {
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/consul/command/agent"
|
||||
|
@ -20,7 +16,7 @@ type KeyringCommand struct {
|
|||
}
|
||||
|
||||
func (c *KeyringCommand) Run(args []string) int {
|
||||
var installKey, useKey, removeKey, init, dataDir string
|
||||
var installKey, useKey, removeKey string
|
||||
var listKeys bool
|
||||
|
||||
cmdFlags := flag.NewFlagSet("keys", flag.ContinueOnError)
|
||||
|
@ -30,8 +26,6 @@ func (c *KeyringCommand) Run(args []string) int {
|
|||
cmdFlags.StringVar(&useKey, "use", "", "use key")
|
||||
cmdFlags.StringVar(&removeKey, "remove", "", "remove key")
|
||||
cmdFlags.BoolVar(&listKeys, "list", false, "list keys")
|
||||
cmdFlags.StringVar(&init, "init", "", "initialize keyring")
|
||||
cmdFlags.StringVar(&dataDir, "data-dir", "", "data directory")
|
||||
|
||||
rpcAddr := RPCAddrFlag(cmdFlags)
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
|
@ -47,7 +41,7 @@ func (c *KeyringCommand) Run(args []string) int {
|
|||
|
||||
// Only accept a single argument
|
||||
found := listKeys
|
||||
for _, arg := range []string{installKey, useKey, removeKey, init} {
|
||||
for _, arg := range []string{installKey, useKey, removeKey} {
|
||||
if found && len(arg) > 0 {
|
||||
c.Ui.Error("Only a single action is allowed")
|
||||
return 1
|
||||
|
@ -61,26 +55,6 @@ func (c *KeyringCommand) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
if init != "" {
|
||||
if dataDir == "" {
|
||||
c.Ui.Error("Must provide -data-dir")
|
||||
return 1
|
||||
}
|
||||
|
||||
fileLAN := filepath.Join(dataDir, agent.SerfLANKeyring)
|
||||
if err := initKeyring(fileLAN, init); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error: %s", err))
|
||||
return 1
|
||||
}
|
||||
fileWAN := filepath.Join(dataDir, agent.SerfWANKeyring)
|
||||
if err := initKeyring(fileWAN, init); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// All other operations will require a client connection
|
||||
client, err := RPCClient(*rpcAddr)
|
||||
if err != nil {
|
||||
|
@ -204,40 +178,6 @@ func (c *KeyringCommand) handleList(
|
|||
}
|
||||
}
|
||||
|
||||
// initKeyring will create a keyring file at a given path.
|
||||
func initKeyring(path, key string) error {
|
||||
if _, err := base64.StdEncoding.DecodeString(key); err != nil {
|
||||
return fmt.Errorf("Invalid key: %s", err)
|
||||
}
|
||||
|
||||
keys := []string{key}
|
||||
keyringBytes, err := json.Marshal(keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return fmt.Errorf("File already exists: %s", path)
|
||||
}
|
||||
|
||||
fh, err := os.OpenFile(path, 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(path)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *KeyringCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: consul keyring [options]
|
||||
|
@ -263,11 +203,6 @@ Options:
|
|||
operation may only be performed on keys which are
|
||||
not currently the primary key.
|
||||
-list List all keys currently in use within the cluster.
|
||||
-init=<key> Create the initial keyring files for Consul to use
|
||||
containing the provided key. The -data-dir argument
|
||||
is required with this option.
|
||||
-data-dir=<path> The path to the Consul agent's data directory. This
|
||||
argument is only needed for keyring initialization.
|
||||
-rpc-addr=127.0.0.1:8400 RPC address of the Consul agent.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
|
|
|
@ -19,34 +19,23 @@ responsibility of the operator to ensure that only the required encryption keys
|
|||
are installed on the cluster. You can review the installed keys using the
|
||||
`-list` argument, and remove unneeded keys with `-remove`.
|
||||
|
||||
With the exception of the `-init` argument, all operations performed by this
|
||||
command can only be run against server nodes, and affect both the LAN and
|
||||
WAN keyrings in lock-step.
|
||||
All operations performed by this command can only be run against server nodes,
|
||||
and affect both the LAN and WAN keyrings in lock-step.
|
||||
|
||||
All variations of the `keyring` command, unless otherwise specified below, will
|
||||
return 0 if all nodes reply and there are no errors. If any node fails to reply
|
||||
or reports failure, the exit code will be 1.
|
||||
All variations of the `keyring` command return 0 if all nodes reply and there
|
||||
are no errors. If any node fails to reply or reports failure, the exit code
|
||||
will be 1.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage: `consul keyring [options]`
|
||||
|
||||
Only one actionable argument may be specified per run, including `-init`,
|
||||
`-list`, `-install`, `-remove`, and `-use`.
|
||||
Only one actionable argument may be specified per run, including `-list`,
|
||||
`-install`, `-remove`, and `-use`.
|
||||
|
||||
The list of available flags are:
|
||||
|
||||
* `-init` - Creates the keyring file(s). This is useful to configure initial
|
||||
encryption keyrings, which can later be mutated using the other arguments in
|
||||
this command. This argument accepts an ASCII key, which can be generated using
|
||||
the [keygen command](/docs/commands/keygen.html). Requires the `-data-dir`
|
||||
argument.
|
||||
|
||||
This operation can be run on both client and server nodes and requires no
|
||||
network connectivity.
|
||||
|
||||
Returns 0 if the key is successfully configured, or 1 if there were any
|
||||
problems.
|
||||
* `-list` - List all keys currently in use within the cluster.
|
||||
|
||||
* `-install` - Install a new encryption key. This will broadcast the new key to
|
||||
all members in the cluster.
|
||||
|
@ -57,10 +46,6 @@ The list of available flags are:
|
|||
* `-remove` - Remove the given key from the cluster. This operation may only be
|
||||
performed on keys which are not currently the primary key.
|
||||
|
||||
* `-list` - List all keys currently in use within the cluster.
|
||||
|
||||
* `-data-dir` - The path to Consul's data directory. Used with `-init` only.
|
||||
|
||||
* `-rpc-addr` - RPC address of the Consul agent.
|
||||
|
||||
## Output
|
||||
|
|
Loading…
Reference in New Issue