Add settings for upshifting to encrypted gossip (#3079)
This commit is contained in:
parent
14d5a0dfeb
commit
e196576c07
|
@ -376,6 +376,14 @@ func (a *Agent) consulConfig() (*consul.Config, error) {
|
|||
if a.config.ReconnectTimeoutWan != 0 {
|
||||
base.SerfWANConfig.ReconnectTimeout = a.config.ReconnectTimeoutWan
|
||||
}
|
||||
if a.config.EncryptVerifyIncoming != nil {
|
||||
base.SerfWANConfig.MemberlistConfig.GossipVerifyIncoming = *a.config.EncryptVerifyIncoming
|
||||
base.SerfLANConfig.MemberlistConfig.GossipVerifyIncoming = *a.config.EncryptVerifyIncoming
|
||||
}
|
||||
if a.config.EncryptVerifyOutgoing != nil {
|
||||
base.SerfWANConfig.MemberlistConfig.GossipVerifyOutgoing = *a.config.EncryptVerifyOutgoing
|
||||
base.SerfLANConfig.MemberlistConfig.GossipVerifyOutgoing = *a.config.EncryptVerifyOutgoing
|
||||
}
|
||||
if a.config.AdvertiseAddrs.RPC != nil {
|
||||
base.RPCAdvertise = a.config.AdvertiseAddrs.RPC
|
||||
}
|
||||
|
|
|
@ -365,6 +365,12 @@ type Config struct {
|
|||
// Encryption key to use for the Serf communication
|
||||
EncryptKey string `mapstructure:"encrypt" json:"-"`
|
||||
|
||||
// EncryptVerifyIncoming and EncryptVerifyOutgoing are used to enforce
|
||||
// incoming/outgoing gossip encryption and can be used to upshift to
|
||||
// encrypted gossip on a running cluster.
|
||||
EncryptVerifyIncoming *bool `mapstructure:"encrypt_verify_incoming"`
|
||||
EncryptVerifyOutgoing *bool `mapstructure:"encrypt_verify_outgoing"`
|
||||
|
||||
// LogLevel is the level of the logs to putout
|
||||
LogLevel string `mapstructure:"log_level"`
|
||||
|
||||
|
@ -864,6 +870,9 @@ func DefaultConfig() *Config {
|
|||
RetryIntervalWan: 30 * time.Second,
|
||||
|
||||
TLSMinVersion: "tls10",
|
||||
|
||||
EncryptVerifyIncoming: Bool(true),
|
||||
EncryptVerifyOutgoing: Bool(true),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1477,6 +1486,12 @@ func MergeConfig(a, b *Config) *Config {
|
|||
if b.EncryptKey != "" {
|
||||
result.EncryptKey = b.EncryptKey
|
||||
}
|
||||
if b.EncryptVerifyIncoming != nil {
|
||||
result.EncryptVerifyIncoming = b.EncryptVerifyIncoming
|
||||
}
|
||||
if b.EncryptVerifyOutgoing != nil {
|
||||
result.EncryptVerifyOutgoing = b.EncryptVerifyOutgoing
|
||||
}
|
||||
if b.LogLevel != "" {
|
||||
result.LogLevel = b.LogLevel
|
||||
}
|
||||
|
|
|
@ -123,6 +123,18 @@ func TestDecodeConfig(t *testing.T) {
|
|||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
|
||||
input = `{"encrypt_verify_incoming":true, "encrypt_verify_outgoing":true}`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if config.EncryptVerifyIncoming == nil || !*config.EncryptVerifyIncoming {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
if config.EncryptVerifyOutgoing == nil || !*config.EncryptVerifyOutgoing {
|
||||
t.Fatalf("bad: %#v", config)
|
||||
}
|
||||
|
||||
// DNS setup
|
||||
input = `{"ports": {"dns": 8500}, "recursors": ["8.8.8.8","8.8.4.4"], "recursor":"127.0.0.1", "domain": "foobar"}`
|
||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||
|
|
|
@ -141,6 +141,16 @@ type Config struct {
|
|||
GossipNodes int
|
||||
GossipToTheDeadTime time.Duration
|
||||
|
||||
// GossipVerifyIncoming controls whether to enforce encryption for incoming
|
||||
// gossip. It is used for upshifting from unencrypted to encrypted gossip on
|
||||
// a running cluster.
|
||||
GossipVerifyIncoming bool
|
||||
|
||||
// GossipVerifyOutgoing controls whether to enforce encryption for outgoing
|
||||
// gossip. It is used for upshifting from unencrypted to encrypted gossip on
|
||||
// a running cluster.
|
||||
GossipVerifyOutgoing bool
|
||||
|
||||
// EnableCompression is used to control message compression. This can
|
||||
// be used to reduce bandwidth usage at the cost of slightly more CPU
|
||||
// utilization. This is only available starting at protocol version 1.
|
||||
|
@ -236,6 +246,8 @@ func DefaultLANConfig() *Config {
|
|||
GossipNodes: 3, // Gossip to 3 nodes
|
||||
GossipInterval: 200 * time.Millisecond, // Gossip more rapidly
|
||||
GossipToTheDeadTime: 30 * time.Second, // Same as push/pull
|
||||
GossipVerifyIncoming: true,
|
||||
GossipVerifyOutgoing: true,
|
||||
|
||||
EnableCompression: true, // Enable compression by default
|
||||
|
||||
|
|
|
@ -334,7 +334,7 @@ func (m *Memberlist) setAlive() error {
|
|||
addr, port, err := m.transport.FinalAdvertiseAddr(
|
||||
m.config.AdvertiseAddr, m.config.AdvertisePort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get final advertise address: %v")
|
||||
return fmt.Errorf("Failed to get final advertise address: %v", err)
|
||||
}
|
||||
|
||||
// Check if this is a public address without encryption
|
||||
|
|
|
@ -283,9 +283,14 @@ func (m *Memberlist) ingestPacket(buf []byte, from net.Addr, timestamp time.Time
|
|||
// Decrypt the payload
|
||||
plain, err := decryptPayload(m.config.Keyring.GetKeys(), buf, nil)
|
||||
if err != nil {
|
||||
if !m.config.GossipVerifyIncoming {
|
||||
// Treat the message as plaintext
|
||||
plain = buf
|
||||
} else {
|
||||
m.logger.Printf("[ERR] memberlist: Decrypt packet failed: %v %s", err, LogAddress(from))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Continue processing the plaintext buffer
|
||||
buf = plain
|
||||
|
@ -557,7 +562,7 @@ func (m *Memberlist) encodeAndSendMsg(addr string, msgType messageType, msg inte
|
|||
func (m *Memberlist) sendMsg(addr string, msg []byte) error {
|
||||
// Check if we can piggy back any messages
|
||||
bytesAvail := m.config.UDPBufferSize - len(msg) - compoundHeaderOverhead
|
||||
if m.config.EncryptionEnabled() {
|
||||
if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
|
||||
bytesAvail -= encryptOverhead(m.encryptionVersion())
|
||||
}
|
||||
extra := m.getBroadcasts(compoundOverhead, bytesAvail)
|
||||
|
@ -621,7 +626,7 @@ func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error
|
|||
}
|
||||
|
||||
// Check if we have encryption enabled
|
||||
if m.config.EncryptionEnabled() {
|
||||
if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
|
||||
// Encrypt the payload
|
||||
var buf bytes.Buffer
|
||||
primaryKey := m.config.Keyring.GetPrimaryKey()
|
||||
|
@ -652,7 +657,7 @@ func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte) error {
|
|||
}
|
||||
|
||||
// Check if encryption is enabled
|
||||
if m.config.EncryptionEnabled() {
|
||||
if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing {
|
||||
crypt, err := m.encryptLocalState(sendBuf)
|
||||
if err != nil {
|
||||
m.logger.Printf("[ERROR] memberlist: Failed to encrypt local state: %v", err)
|
||||
|
@ -876,7 +881,7 @@ func (m *Memberlist) readStream(conn net.Conn) (messageType, io.Reader, *codec.D
|
|||
// Reset message type and bufConn
|
||||
msgType = messageType(plain[0])
|
||||
bufConn = bytes.NewReader(plain[1:])
|
||||
} else if m.config.EncryptionEnabled() {
|
||||
} else if m.config.EncryptionEnabled() && m.config.GossipVerifyIncoming {
|
||||
return 0, nil, nil,
|
||||
fmt.Errorf("Encryption is configured but remote state is not encrypted")
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ func (n *Node) Address() string {
|
|||
return joinHostPort(n.Addr.String(), n.Port)
|
||||
}
|
||||
|
||||
// String returns the node name
|
||||
func (n *Node) String() string {
|
||||
return n.Name
|
||||
}
|
||||
|
||||
// NodeState is used to manage our state view of another node
|
||||
type nodeState struct {
|
||||
Node
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# The version must be supplied from the environment. Do not include the
|
||||
# leading "v".
|
||||
if [ -z $VERSION ]; then
|
||||
echo "Please specify a version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate the tag.
|
||||
echo "==> Tagging version $VERSION..."
|
||||
git commit --allow-empty -a --gpg-sign=348FFC4C -m "Release v$VERSION"
|
||||
git tag -a -m "Version $VERSION" -s -u 348FFC4C "v${VERSION}" master
|
||||
|
||||
exit 0
|
|
@ -642,10 +642,10 @@
|
|||
"revisionTime": "2015-06-09T07:04:31Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "JJsKjmgNTUTaEHEEAQgb9jCGGiM=",
|
||||
"checksumSHA1": "AoIvQFHycqypYK57ZjiWzlQmdwk=",
|
||||
"path": "github.com/hashicorp/memberlist",
|
||||
"revision": "6cc6075ba9fba1915fa0416f00d2b4efa9dc2262",
|
||||
"revisionTime": "2017-03-17T22:24:04Z"
|
||||
"revision": "16fe34d996eba2b68f6f46f26c51c617c6bc1bf0",
|
||||
"revisionTime": "2017-05-26T19:17:51Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "qnlqWJYV81ENr61SZk9c65R1mDo=",
|
||||
|
|
|
@ -52,6 +52,24 @@ $ consul agent -data-dir=/tmp/consul -config-file=encrypt.json
|
|||
All nodes within a Consul cluster must share the same encryption key in
|
||||
order to send and receive cluster information.
|
||||
|
||||
## Configuring Gossip Encryption on an existing cluster
|
||||
|
||||
As of version 0.8.4, Consul supports upshifting to encrypted gossip on a running cluster
|
||||
through the following process.
|
||||
|
||||
1. Generate an encryption key using [`consul keygen`](/docs/commands/keygen.html)
|
||||
2. Set the [`encrypt`](/docs/agent/options.html#_encrypt) key in the agent configuration and set
|
||||
[`encrypt_verify_incoming`](/docs/agent/options.html#encrypt_verify_incoming) and
|
||||
[`encrypt_verify_outgoing`](/docs/agent/options.html#encrypt_verify_outgoing) to `false`, doing a
|
||||
rolling update of the cluster with these new values. After this step, the agents will be able to
|
||||
decrypt gossip but will not yet be sending encrypted traffic.
|
||||
3. Remove the [`encrypt_verify_outgoing`](/docs/agent/options.html#encrypt_verify_outgoing) setting
|
||||
to change it back to false (the default) and perform another rolling update of the cluster. The
|
||||
agents will now be sending encrypted gossip but will still allow incoming unencrypted traffic.
|
||||
4. Remove the [`encrypt_verify_incoming`](/docs/agent/options.html#encrypt_verify_incoming) setting
|
||||
to change it back to false (the default) and perform a final rolling update of the cluster. All the
|
||||
agents will now be strictly enforcing encrypted gossip.
|
||||
|
||||
## RPC Encryption with TLS
|
||||
|
||||
Consul supports using TLS to verify the authenticity of servers and clients. To enable this,
|
||||
|
|
|
@ -708,6 +708,18 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
|
|||
* <a name="encrypt"></a><a href="#encrypt">`encrypt`</a> Equivalent to the
|
||||
[`-encrypt` command-line flag](#_encrypt).
|
||||
|
||||
* <a name="encrypt_verify_incoming"></a><a href="#encrypt_verify_incoming">`encrypt_verify_incoming`</a> -
|
||||
This is an optional parameter that can be used to disable enforcing encryption for incoming gossip in order
|
||||
to upshift from unencrypted to encrypted gossip on a running cluster. See [this section]
|
||||
(/docs/agent/encryption.html#configuring-gossip-encryption-on-an-existing-cluster) for more information.
|
||||
Defaults to true.
|
||||
|
||||
* <a name="encrypt_verify_outgoing"></a><a href="#encrypt_verify_outgoing">`encrypt_verify_outgoing`</a> -
|
||||
This is an optional parameter that can be used to disable enforcing encryption for outgoing gossip in order
|
||||
to upshift from unencrypted to encrypted gossip on a running cluster. See [this section]
|
||||
(/docs/agent/encryption.html#configuring-gossip-encryption-on-an-existing-cluster) for more information.
|
||||
Defaults to true.
|
||||
|
||||
* <a name="key_file"></a><a href="#key_file">`key_file`</a> This provides a the file path to a
|
||||
PEM-encoded private key. The key is used with the certificate to verify the agent's authenticity.
|
||||
This must be provided along with [`cert_file`](#cert_file).
|
||||
|
|
Loading…
Reference in New Issue