mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add support for encrypting gossip traffic
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
This commit is contained in:
parent
c2662da3e9
commit
b2b87577d4
7 changed files with 159 additions and 3 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/go-events"
|
||||
|
@ -13,14 +14,24 @@ import (
|
|||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/networkdb"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// ByTime implements sort.Interface for []*types.EncryptionKey based on
|
||||
// the LamportTime field.
|
||||
type ByTime []*types.EncryptionKey
|
||||
|
||||
func (b ByTime) Len() int { return len(b) }
|
||||
func (b ByTime) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
func (b ByTime) Less(i, j int) bool { return b[i].LamportTime < b[j].LamportTime }
|
||||
|
||||
type agent struct {
|
||||
networkDB *networkdb.NetworkDB
|
||||
bindAddr string
|
||||
epTblCancel func()
|
||||
driverCancelFuncs map[string][]func()
|
||||
keys []*types.EncryptionKey
|
||||
}
|
||||
|
||||
func getBindAddr(ifaceName string) (string, error) {
|
||||
|
@ -61,11 +72,71 @@ func resolveAddr(addrOrInterface string) (string, error) {
|
|||
return getBindAddr(addrOrInterface)
|
||||
}
|
||||
|
||||
func (c *controller) agentInit(bindAddrOrInterface string) error {
|
||||
func (c *controller) agentHandleKeys(keys []*types.EncryptionKey) error {
|
||||
// Find the new key and add it to the key ring
|
||||
a := c.agent
|
||||
for _, key := range keys {
|
||||
same := false
|
||||
for _, aKey := range a.keys {
|
||||
if same = aKey.LamportTime == key.LamportTime; same {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !same {
|
||||
a.keys = append(a.keys, key)
|
||||
if key.Subsystem == "networking:gossip" {
|
||||
a.networkDB.SetKey(key.Key)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
// Find the deleted key. If the deleted key was the primary key,
|
||||
// a new primary key should be set before removing if from keyring.
|
||||
deleted := []byte{}
|
||||
for i, aKey := range a.keys {
|
||||
same := false
|
||||
for _, key := range keys {
|
||||
if same = key.LamportTime == aKey.LamportTime; same {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !same {
|
||||
if aKey.Subsystem == "networking:gossip" {
|
||||
deleted = aKey.Key
|
||||
}
|
||||
a.keys = append(a.keys[:i], a.keys[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(ByTime(a.keys))
|
||||
for _, key := range a.keys {
|
||||
if key.Subsystem == "networking:gossip" {
|
||||
a.networkDB.SetPrimaryKey(key.Key)
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(deleted) > 0 {
|
||||
a.networkDB.RemoveKey(deleted)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) agentInit(bindAddrOrInterface string, keys []*types.EncryptionKey) error {
|
||||
if !c.isAgent() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sort the keys by lamport time
|
||||
sort.Sort(ByTime(keys))
|
||||
|
||||
gossipkey := [][]byte{}
|
||||
for _, key := range keys {
|
||||
if key.Subsystem == "networking:gossip" {
|
||||
gossipkey = append(gossipkey, key.Key)
|
||||
}
|
||||
}
|
||||
|
||||
bindAddr, err := resolveAddr(bindAddrOrInterface)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -75,6 +146,7 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
|
|||
nDB, err := networkdb.New(&networkdb.Config{
|
||||
BindAddr: bindAddr,
|
||||
NodeName: hostname,
|
||||
Keys: gossipkey,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
@ -88,6 +160,7 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
|
|||
bindAddr: bindAddr,
|
||||
epTblCancel: cancel,
|
||||
driverCancelFuncs: make(map[string][]func()),
|
||||
keys: keys,
|
||||
}
|
||||
|
||||
go c.handleTableEvents(ch, c.handleEpTableEvent)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package cluster
|
||||
|
||||
import "github.com/docker/libnetwork/types"
|
||||
|
||||
// Provider provides clustering config details
|
||||
type Provider interface {
|
||||
IsManager() bool
|
||||
|
@ -7,4 +9,6 @@ type Provider interface {
|
|||
GetListenAddress() string
|
||||
GetRemoteAddress() string
|
||||
ListenClusterEvents() <-chan struct{}
|
||||
GetNetworkKeys() []*types.EncryptionKey
|
||||
SetNetworkKeys([]*types.EncryptionKey)
|
||||
}
|
||||
|
|
|
@ -314,6 +314,13 @@ func (d *dnetConnection) GetRemoteAddress() string {
|
|||
return d.Orchestration.Peer
|
||||
}
|
||||
|
||||
func (d *dnetConnection) GetNetworkKeys() []*types.EncryptionKey {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dnetConnection) SetNetworkKeys([]*types.EncryptionKey) {
|
||||
}
|
||||
|
||||
func (d *dnetConnection) ListenClusterEvents() <-chan struct{} {
|
||||
return d.configEvent
|
||||
}
|
||||
|
|
|
@ -226,6 +226,12 @@ func (c *controller) clusterAgentInit() {
|
|||
select {
|
||||
case <-clusterProvider.ListenClusterEvents():
|
||||
if !c.isDistributedControl() {
|
||||
keys := clusterProvider.GetNetworkKeys()
|
||||
// If the agent is already setup this could be a key change notificaiton
|
||||
if c.agent != nil {
|
||||
c.agentHandleKeys(keys)
|
||||
}
|
||||
|
||||
bindAddr, _, _ := net.SplitHostPort(clusterProvider.GetListenAddress())
|
||||
remote := clusterProvider.GetRemoteAddress()
|
||||
remoteAddr, _, _ := net.SplitHostPort(remote)
|
||||
|
@ -243,8 +249,8 @@ func (c *controller) clusterAgentInit() {
|
|||
}
|
||||
}
|
||||
|
||||
if bindAddr != "" && c.agent == nil {
|
||||
if err := c.agentInit(bindAddr); err != nil {
|
||||
if bindAddr != "" && len(keys) > 0 && c.agent == nil {
|
||||
if err := c.agentInit(bindAddr, keys); err != nil {
|
||||
log.Errorf("Error in agentInit : %v", err)
|
||||
} else {
|
||||
c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package networkdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -33,6 +34,46 @@ func (l *logWriter) Write(p []byte) (int, error) {
|
|||
return len(p), nil
|
||||
}
|
||||
|
||||
// SetKey adds a new key to the key ring
|
||||
func (nDB *NetworkDB) SetKey(key []byte) {
|
||||
for _, dbKey := range nDB.config.Keys {
|
||||
if bytes.Equal(key, dbKey) {
|
||||
return
|
||||
}
|
||||
}
|
||||
nDB.config.Keys = append(nDB.config.Keys, key)
|
||||
if nDB.keyring != nil {
|
||||
nDB.keyring.AddKey(key)
|
||||
}
|
||||
}
|
||||
|
||||
// SetPrimaryKey sets the given key as the primary key. This should have
|
||||
// been added apriori through SetKey
|
||||
func (nDB *NetworkDB) SetPrimaryKey(key []byte) {
|
||||
for _, dbKey := range nDB.config.Keys {
|
||||
if bytes.Equal(key, dbKey) {
|
||||
if nDB.keyring != nil {
|
||||
nDB.keyring.UseKey(dbKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveKey removes a key from the key ring. The key being removed
|
||||
// can't be the primary key
|
||||
func (nDB *NetworkDB) RemoveKey(key []byte) {
|
||||
for i, dbKey := range nDB.config.Keys {
|
||||
if bytes.Equal(key, dbKey) {
|
||||
nDB.config.Keys = append(nDB.config.Keys[:i], nDB.config.Keys[i+1:]...)
|
||||
if nDB.keyring != nil {
|
||||
nDB.keyring.RemoveKey(dbKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (nDB *NetworkDB) clusterInit() error {
|
||||
config := memberlist.DefaultLANConfig()
|
||||
config.Name = nDB.config.NodeName
|
||||
|
@ -47,6 +88,15 @@ func (nDB *NetworkDB) clusterInit() error {
|
|||
config.Events = &eventDelegate{nDB: nDB}
|
||||
config.LogOutput = &logWriter{}
|
||||
|
||||
var err error
|
||||
if len(nDB.config.Keys) > 0 {
|
||||
nDB.keyring, err = memberlist.NewKeyring(nDB.config.Keys, nDB.config.Keys[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Keyring = nDB.keyring
|
||||
}
|
||||
|
||||
nDB.networkBroadcasts = &memberlist.TransmitLimitedQueue{
|
||||
NumNodes: func() int {
|
||||
return len(nDB.nodes)
|
||||
|
|
|
@ -77,6 +77,9 @@ type NetworkDB struct {
|
|||
// List of all tickers which needed to be stopped when
|
||||
// cleaning up.
|
||||
tickers []*time.Ticker
|
||||
|
||||
// Reference to the memberlist's keyring to add & remove keys
|
||||
keyring *memberlist.Keyring
|
||||
}
|
||||
|
||||
// network describes the node/network attachment.
|
||||
|
@ -111,6 +114,10 @@ type Config struct {
|
|||
// BindPort is the local node's port to which we bind to for
|
||||
// cluster communication.
|
||||
BindPort int
|
||||
|
||||
// Keys to be added to the Keyring of the memberlist. Key at index
|
||||
// 0 is the primary key
|
||||
Keys [][]byte
|
||||
}
|
||||
|
||||
// entry defines a table entry
|
||||
|
|
|
@ -16,6 +16,15 @@ const (
|
|||
IPv6
|
||||
)
|
||||
|
||||
// EncryptionKey is the libnetwork representation of the key distributed by the lead
|
||||
// manager.
|
||||
type EncryptionKey struct {
|
||||
Subsystem string
|
||||
Algorithm int32
|
||||
Key []byte
|
||||
LamportTime uint64
|
||||
}
|
||||
|
||||
// UUID represents a globally unique ID of various resources like network and endpoint
|
||||
type UUID string
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue