github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/keymanager/keymanager.go (about)

     1  package keymanager
     2  
     3  // keymanager does the allocation, rotation and distribution of symmetric
     4  // keys to the agents. This is to securely bootstrap network communication
     5  // between agents. It can be used for encrypting gossip between the agents
     6  // which is used to exchange service discovery and overlay network control
     7  // plane information. It can also be used to encrypt overlay data traffic.
     8  import (
     9  	"context"
    10  	cryptorand "crypto/rand"
    11  	"encoding/binary"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/docker/swarmkit/api"
    16  	"github.com/docker/swarmkit/log"
    17  	"github.com/docker/swarmkit/manager/state/store"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  const (
    22  	// DefaultKeyLen is the default length (in bytes) of the key allocated
    23  	DefaultKeyLen = 16
    24  
    25  	// DefaultKeyRotationInterval used by key manager
    26  	DefaultKeyRotationInterval = 12 * time.Hour
    27  
    28  	// SubsystemGossip handles gossip protocol between the agents
    29  	SubsystemGossip = "networking:gossip"
    30  
    31  	// SubsystemIPSec is overlay network data encryption subsystem
    32  	SubsystemIPSec = "networking:ipsec"
    33  
    34  	// DefaultSubsystem is gossip
    35  	DefaultSubsystem = SubsystemGossip
    36  	// number of keys to mainrain in the key ring.
    37  	keyringSize = 3
    38  )
    39  
    40  // map of subsystems and corresponding encryption algorithm. Initially only
    41  // AES_128 in GCM mode is supported.
    42  var subsysToAlgo = map[string]api.EncryptionKey_Algorithm{
    43  	SubsystemGossip: api.AES_128_GCM,
    44  	SubsystemIPSec:  api.AES_128_GCM,
    45  }
    46  
    47  type keyRing struct {
    48  	lClock uint64
    49  	keys   []*api.EncryptionKey
    50  }
    51  
    52  // Config for the keymanager that can be modified
    53  type Config struct {
    54  	ClusterName      string
    55  	Keylen           int
    56  	RotationInterval time.Duration
    57  	Subsystems       []string
    58  }
    59  
    60  // KeyManager handles key allocation, rotation & distribution
    61  type KeyManager struct {
    62  	config  *Config
    63  	store   *store.MemoryStore
    64  	keyRing *keyRing
    65  	ctx     context.Context
    66  	cancel  context.CancelFunc
    67  
    68  	mu sync.Mutex
    69  }
    70  
    71  // DefaultConfig provides the default config for keymanager
    72  func DefaultConfig() *Config {
    73  	return &Config{
    74  		ClusterName:      store.DefaultClusterName,
    75  		Keylen:           DefaultKeyLen,
    76  		RotationInterval: DefaultKeyRotationInterval,
    77  		Subsystems:       []string{SubsystemGossip, SubsystemIPSec},
    78  	}
    79  }
    80  
    81  // New creates an instance of keymanager with the given config
    82  func New(store *store.MemoryStore, config *Config) *KeyManager {
    83  	for _, subsys := range config.Subsystems {
    84  		if subsys != SubsystemGossip && subsys != SubsystemIPSec {
    85  			return nil
    86  		}
    87  	}
    88  	return &KeyManager{
    89  		config:  config,
    90  		store:   store,
    91  		keyRing: &keyRing{lClock: genSkew()},
    92  	}
    93  }
    94  
    95  func (k *KeyManager) allocateKey(ctx context.Context, subsys string) *api.EncryptionKey {
    96  	key := make([]byte, k.config.Keylen)
    97  
    98  	_, err := cryptorand.Read(key)
    99  	if err != nil {
   100  		panic(errors.Wrap(err, "key generated failed"))
   101  	}
   102  	k.keyRing.lClock++
   103  
   104  	return &api.EncryptionKey{
   105  		Subsystem:   subsys,
   106  		Algorithm:   subsysToAlgo[subsys],
   107  		Key:         key,
   108  		LamportTime: k.keyRing.lClock,
   109  	}
   110  }
   111  
   112  func (k *KeyManager) updateKey(cluster *api.Cluster) error {
   113  	return k.store.Update(func(tx store.Tx) error {
   114  		cluster = store.GetCluster(tx, cluster.ID)
   115  		if cluster == nil {
   116  			return nil
   117  		}
   118  		cluster.EncryptionKeyLamportClock = k.keyRing.lClock
   119  		cluster.NetworkBootstrapKeys = k.keyRing.keys
   120  		return store.UpdateCluster(tx, cluster)
   121  	})
   122  }
   123  
   124  func (k *KeyManager) rotateKey(ctx context.Context) error {
   125  	var (
   126  		clusters []*api.Cluster
   127  		err      error
   128  	)
   129  	k.store.View(func(readTx store.ReadTx) {
   130  		clusters, err = store.FindClusters(readTx, store.ByName(k.config.ClusterName))
   131  	})
   132  
   133  	if err != nil {
   134  		log.G(ctx).Errorf("reading cluster config failed, %v", err)
   135  		return err
   136  	}
   137  
   138  	cluster := clusters[0]
   139  	if len(cluster.NetworkBootstrapKeys) == 0 {
   140  		panic(errors.New("no key in the cluster config"))
   141  	}
   142  
   143  	subsysKeys := map[string][]*api.EncryptionKey{}
   144  	for _, key := range k.keyRing.keys {
   145  		subsysKeys[key.Subsystem] = append(subsysKeys[key.Subsystem], key)
   146  	}
   147  	k.keyRing.keys = []*api.EncryptionKey{}
   148  
   149  	// We maintain the latest key and the one before in the key ring to allow
   150  	// agents to communicate without disruption on key change.
   151  	for subsys, keys := range subsysKeys {
   152  		if len(keys) == keyringSize {
   153  			min := 0
   154  			for i, key := range keys[1:] {
   155  				if key.LamportTime < keys[min].LamportTime {
   156  					min = i
   157  				}
   158  			}
   159  			keys = append(keys[0:min], keys[min+1:]...)
   160  		}
   161  		keys = append(keys, k.allocateKey(ctx, subsys))
   162  		subsysKeys[subsys] = keys
   163  	}
   164  
   165  	for _, keys := range subsysKeys {
   166  		k.keyRing.keys = append(k.keyRing.keys, keys...)
   167  	}
   168  
   169  	return k.updateKey(cluster)
   170  }
   171  
   172  // Run starts the keymanager, it doesn't return
   173  func (k *KeyManager) Run(ctx context.Context) error {
   174  	k.mu.Lock()
   175  	ctx = log.WithModule(ctx, "keymanager")
   176  	var (
   177  		clusters []*api.Cluster
   178  		err      error
   179  	)
   180  	k.store.View(func(readTx store.ReadTx) {
   181  		clusters, err = store.FindClusters(readTx, store.ByName(k.config.ClusterName))
   182  	})
   183  
   184  	if err != nil {
   185  		log.G(ctx).Errorf("reading cluster config failed, %v", err)
   186  		k.mu.Unlock()
   187  		return err
   188  	}
   189  
   190  	cluster := clusters[0]
   191  	if len(cluster.NetworkBootstrapKeys) == 0 {
   192  		for _, subsys := range k.config.Subsystems {
   193  			for i := 0; i < keyringSize; i++ {
   194  				k.keyRing.keys = append(k.keyRing.keys, k.allocateKey(ctx, subsys))
   195  			}
   196  		}
   197  		if err := k.updateKey(cluster); err != nil {
   198  			log.G(ctx).Errorf("store update failed %v", err)
   199  		}
   200  	} else {
   201  		k.keyRing.lClock = cluster.EncryptionKeyLamportClock
   202  		k.keyRing.keys = cluster.NetworkBootstrapKeys
   203  	}
   204  
   205  	ticker := time.NewTicker(k.config.RotationInterval)
   206  	defer ticker.Stop()
   207  
   208  	k.ctx, k.cancel = context.WithCancel(ctx)
   209  	k.mu.Unlock()
   210  
   211  	for {
   212  		select {
   213  		case <-ticker.C:
   214  			k.rotateKey(ctx)
   215  		case <-k.ctx.Done():
   216  			return nil
   217  		}
   218  	}
   219  }
   220  
   221  // Stop stops the running instance of key manager
   222  func (k *KeyManager) Stop() error {
   223  	k.mu.Lock()
   224  	defer k.mu.Unlock()
   225  	if k.cancel == nil {
   226  		return errors.New("keymanager is not started")
   227  	}
   228  	k.cancel()
   229  	return nil
   230  }
   231  
   232  // genSkew generates a random uint64 number between 0 and 65535
   233  func genSkew() uint64 {
   234  	b := make([]byte, 2)
   235  	if _, err := cryptorand.Read(b); err != nil {
   236  		panic(err)
   237  	}
   238  	return uint64(binary.BigEndian.Uint16(b))
   239  }