From 8ded762a0b22cb505d5f21310f79895238a74eb5 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Sat, 11 Jun 2016 04:50:25 -0700 Subject: [PATCH] Update key handling logic to process keyring with 3 keys Signed-off-by: Santhosh Manohar --- libnetwork/agent.go | 171 ++++++++++++++++++----- libnetwork/controller.go | 3 + libnetwork/discoverapi/discoverapi.go | 16 +-- libnetwork/drivers/overlay/encryption.go | 25 +--- libnetwork/drivers/overlay/overlay.go | 30 ++-- 5 files changed, 170 insertions(+), 75 deletions(-) diff --git a/libnetwork/agent.go b/libnetwork/agent.go index 6215459d8d..eaab2893c0 100644 --- a/libnetwork/agent.go +++ b/libnetwork/agent.go @@ -3,12 +3,10 @@ package libnetwork //go:generate protoc -I.:Godeps/_workspace/src/github.com/gogo/protobuf --gogo_out=import_path=github.com/docker/libnetwork,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto:. agent.proto import ( - "encoding/hex" "fmt" "net" "os" "sort" - "strconv" "github.com/Sirupsen/logrus" "github.com/docker/go-events" @@ -20,6 +18,12 @@ import ( "github.com/gogo/protobuf/proto" ) +const ( + subsysGossip = "networking:gossip" + subsysIPSec = "networking:ipsec" + keyringSize = 3 +) + // ByTime implements sort.Interface for []*types.EncryptionKey based on // the LamportTime field. type ByTime []*types.EncryptionKey @@ -80,6 +84,82 @@ func resolveAddr(addrOrInterface string) (string, error) { func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { drvEnc := discoverapi.DriverEncryptionUpdate{} + a := c.agent + // 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{} + j := len(c.keys) + for i := 0; i < j; { + same := false + for _, key := range keys { + if same = key.LamportTime == c.keys[i].LamportTime; same { + break + } + } + if !same { + cKey := c.keys[i] + if cKey.Subsystem == subsysGossip { + deleted = cKey.Key + } + + if cKey.Subsystem == subsysGossip /* subsysIPSec */ { + drvEnc.Prune = cKey.Key + drvEnc.PruneTag = cKey.LamportTime + } + c.keys[i], c.keys[j-1] = c.keys[j-1], c.keys[i] + c.keys[j-1] = nil + j-- + } + i++ + } + c.keys = c.keys[:j] + + // Find the new key and add it to the key ring + for _, key := range keys { + same := false + for _, cKey := range c.keys { + if same = cKey.LamportTime == key.LamportTime; same { + break + } + } + if !same { + c.keys = append(c.keys, key) + if key.Subsystem == subsysGossip { + a.networkDB.SetKey(key.Key) + } + + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Key = key.Key + drvEnc.Tag = key.LamportTime + } + } + } + + key, tag := c.getPrimaryKeyTag(subsysGossip) + a.networkDB.SetPrimaryKey(key) + + //key, tag = c.getPrimaryKeyTag(subsysIPSec) + drvEnc.Primary = key + drvEnc.PrimaryTag = tag + + if len(deleted) > 0 { + a.networkDB.RemoveKey(deleted) + } + + c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { + err := driver.DiscoverNew(discoverapi.EncryptionKeysUpdate, drvEnc) + if err != nil { + logrus.Warnf("Failed to update datapath keys in driver %s: %v", name, err) + } + return false + }) + + return nil +} + +func (c *controller) handleKeyChangeV1(keys []*types.EncryptionKey) error { + drvEnc := discoverapi.DriverEncryptionUpdate{} + // Find the new key and add it to the key ring a := c.agent for _, key := range keys { @@ -91,12 +171,12 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } if !same { c.keys = append(c.keys, key) - if key.Subsystem == "networking:gossip" { + if key.Subsystem == subsysGossip { a.networkDB.SetKey(key.Key) } - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Key = hex.EncodeToString(key.Key) - drvEnc.Tag = strconv.FormatUint(key.LamportTime, 10) + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Key = key.Key + drvEnc.Tag = key.LamportTime } break } @@ -112,12 +192,12 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } } if !same { - if cKey.Subsystem == "networking:gossip" { + if cKey.Subsystem == subsysGossip { deleted = cKey.Key } - if cKey.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Prune = hex.EncodeToString(cKey.Key) - drvEnc.PruneTag = strconv.FormatUint(cKey.LamportTime, 10) + if cKey.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Prune = cKey.Key + drvEnc.PruneTag = cKey.LamportTime } c.keys = append(c.keys[:i], c.keys[i+1:]...) break @@ -126,15 +206,15 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { sort.Sort(ByTime(c.keys)) for _, key := range c.keys { - if key.Subsystem == "networking:gossip" { + if key.Subsystem == subsysGossip { a.networkDB.SetPrimaryKey(key.Key) break } } for _, key := range c.keys { - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Primary = hex.EncodeToString(key.Key) - drvEnc.PrimaryTag = strconv.FormatUint(key.LamportTime, 10) + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Primary = key.Key + drvEnc.PrimaryTag = key.LamportTime break } } @@ -197,6 +277,41 @@ func (c *controller) agentSetup() error { return nil } +// For a given subsystem getKeys sorts the keys by lamport time and returns +// slice of keys and lamport time which can used as a unique tag for the keys +func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { + sort.Sort(ByTime(c.keys)) + + keys := [][]byte{} + tags := []uint64{} + for _, key := range c.keys { + if key.Subsystem == subsys { + keys = append(keys, key.Key) + tags = append(tags, key.LamportTime) + } + } + + if len(keys) < keyringSize { + return keys, tags + } + keys[0], keys[1] = keys[1], keys[0] + tags[0], tags[1] = tags[1], tags[0] + return keys, tags +} + +// getPrimaryKeyTag returns the primary key for a given subsytem from the +// list of sorted key and the associated tag +func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64) { + sort.Sort(ByTime(c.keys)) + keys := []*types.EncryptionKey{} + for _, key := range c.keys { + if key.Subsystem == subsys { + keys = append(keys, key) + } + } + return keys[1].Key, keys[1].LamportTime +} + func (c *controller) agentInit(bindAddrOrInterface string) error { if !c.isAgent() { return nil @@ -204,19 +319,9 @@ func (c *controller) agentInit(bindAddrOrInterface string) error { drvEnc := discoverapi.DriverEncryptionConfig{} - // sort the keys by lamport time - sort.Sort(ByTime(c.keys)) - - gossipkey := [][]byte{} - for _, key := range c.keys { - if key.Subsystem == "networking:gossip" { - gossipkey = append(gossipkey, key.Key) - } - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Keys = append(drvEnc.Keys, hex.EncodeToString(key.Key)) - drvEnc.Tags = append(drvEnc.Tags, strconv.FormatUint(key.LamportTime, 10)) - } - } + keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) + drvEnc.Keys = keys + drvEnc.Tags = tags bindAddr, err := resolveAddr(bindAddrOrInterface) if err != nil { @@ -227,7 +332,7 @@ func (c *controller) agentInit(bindAddrOrInterface string) error { nDB, err := networkdb.New(&networkdb.Config{ BindAddr: bindAddr, NodeName: hostname, - Keys: gossipkey, + Keys: keys, }) if err != nil { @@ -275,12 +380,10 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) { }) drvEnc := discoverapi.DriverEncryptionConfig{} - for _, key := range c.keys { - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Keys = append(drvEnc.Keys, hex.EncodeToString(key.Key)) - drvEnc.Tags = append(drvEnc.Tags, strconv.FormatUint(key.LamportTime, 10)) - } - } + keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) + drvEnc.Keys = keys + drvEnc.Tags = tags + c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc) if err != nil { diff --git a/libnetwork/controller.go b/libnetwork/controller.go index 1646568f27..80ccf6e6e2 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -264,6 +264,9 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { c.Unlock() return nil } + if len(keys) < keyringSize { + return c.handleKeyChangeV1(keys) + } return c.handleKeyChange(keys) } diff --git a/libnetwork/discoverapi/discoverapi.go b/libnetwork/discoverapi/discoverapi.go index 080424a182..bee7ad1837 100644 --- a/libnetwork/discoverapi/discoverapi.go +++ b/libnetwork/discoverapi/discoverapi.go @@ -42,18 +42,18 @@ type DatastoreConfigData struct { // Key in first position is the primary key, the one to be used in tx. // Original key and tag types are []byte and uint64 type DriverEncryptionConfig struct { - Keys []string - Tags []string + Keys [][]byte + Tags []uint64 } // DriverEncryptionUpdate carries an update to the encryption key(s) as: // a new key and/or set a primary key and/or a removal of an existing key. // Original key and tag types are []byte and uint64 type DriverEncryptionUpdate struct { - Key string - Tag string - Primary string - PrimaryTag string - Prune string - PruneTag string + Key []byte + Tag uint64 + Primary []byte + PrimaryTag uint64 + Prune []byte + PruneTag uint64 } diff --git a/libnetwork/drivers/overlay/encryption.go b/libnetwork/drivers/overlay/encryption.go index f27f86004d..36d2a2f2b7 100644 --- a/libnetwork/drivers/overlay/encryption.go +++ b/libnetwork/drivers/overlay/encryption.go @@ -33,7 +33,10 @@ type key struct { } func (k *key) String() string { - return fmt.Sprintf("(key: %s, tag: 0x%x)", hex.EncodeToString(k.value)[0:5], k.tag) + if k != nil { + return fmt.Sprintf("(key: %s, tag: 0x%x)", hex.EncodeToString(k.value)[0:5], k.tag) + } + return "" } type spi struct { @@ -557,23 +560,3 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, return spis } - -func parseEncryptionKey(value, tag string) (*key, error) { - var ( - k *key - err error - ) - if value == "" { - return nil, nil - } - k = &key{} - if k.value, err = hex.DecodeString(value); err != nil { - return nil, types.BadRequestErrorf("failed to decode key (%s): %v", value, err) - } - t, err := strconv.ParseUint(tag, 10, 64) - if err != nil { - return nil, types.BadRequestErrorf("failed to decode tag (%s): %v", tag, err) - } - k.tag = uint32(t) - return k, nil -} diff --git a/libnetwork/drivers/overlay/overlay.go b/libnetwork/drivers/overlay/overlay.go index 7c5d6d548b..f7e1ccc77a 100644 --- a/libnetwork/drivers/overlay/overlay.go +++ b/libnetwork/drivers/overlay/overlay.go @@ -306,9 +306,9 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) } keys := make([]*key, 0, len(encrData.Keys)) for i := 0; i < len(encrData.Keys); i++ { - k, err := parseEncryptionKey(encrData.Keys[i], encrData.Tags[i]) - if err != nil { - return err + k := &key{ + value: encrData.Keys[i], + tag: uint32(encrData.Tags[i]), } keys = append(keys, k) } @@ -319,17 +319,23 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) if !ok { return fmt.Errorf("invalid encryption key notification data") } - newKey, err = parseEncryptionKey(encrData.Key, encrData.Tag) - if err != nil { - return err + if encrData.Key != nil { + newKey = &key{ + value: encrData.Key, + tag: uint32(encrData.Tag), + } } - priKey, err = parseEncryptionKey(encrData.Primary, encrData.PrimaryTag) - if err != nil { - return err + if encrData.Primary != nil { + priKey = &key{ + value: encrData.Primary, + tag: uint32(encrData.PrimaryTag), + } } - delKey, err = parseEncryptionKey(encrData.Prune, encrData.PruneTag) - if err != nil { - return err + if encrData.Prune != nil { + delKey = &key{ + value: encrData.Prune, + tag: uint32(encrData.PruneTag), + } } d.updateKeys(newKey, priKey, delKey) default: