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

     1  package manager
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"encoding/base64"
     6  	"fmt"
     7  
     8  	"github.com/docker/swarmkit/ca"
     9  	"github.com/docker/swarmkit/manager/encryption"
    10  	"github.com/docker/swarmkit/manager/state/raft"
    11  )
    12  
    13  // This module contains the data structures and control flow to manage rotating the raft
    14  // DEK and also for interacting with KeyReadWriter to maintain the raft DEK information in
    15  // the PEM headers fo the TLS key for the node.
    16  
    17  const (
    18  	// the raft DEK (data encryption key) is stored in the TLS key as a header
    19  	// these are the header values
    20  	pemHeaderRaftDEK              = "raft-dek"
    21  	pemHeaderRaftPendingDEK       = "raft-dek-pending"
    22  	pemHeaderRaftDEKNeedsRotation = "raft-dek-needs-rotation"
    23  )
    24  
    25  // RaftDEKData contains all the data stored in TLS pem headers.
    26  type RaftDEKData struct {
    27  
    28  	// EncryptionKeys contain the current and pending raft DEKs
    29  	raft.EncryptionKeys
    30  
    31  	// NeedsRotation indicates whether another rotation needs to be happen after
    32  	// the current one.
    33  	NeedsRotation bool
    34  
    35  	// The FIPS boolean is not serialized, but is internal state which indicates how
    36  	// the raft DEK headers should be encrypted (e.g. using FIPS compliant algorithms)
    37  	FIPS bool
    38  }
    39  
    40  // RaftDEKData should implement the PEMKeyHeaders interface
    41  var _ ca.PEMKeyHeaders = RaftDEKData{}
    42  
    43  // UnmarshalHeaders loads the current state of the DEKs into a new RaftDEKData object (which is returned) given the
    44  // current TLS headers and the current KEK.
    45  func (r RaftDEKData) UnmarshalHeaders(headers map[string]string, kekData ca.KEKData) (ca.PEMKeyHeaders, error) {
    46  	var (
    47  		currentDEK, pendingDEK []byte
    48  		err                    error
    49  	)
    50  
    51  	if currentDEKStr, ok := headers[pemHeaderRaftDEK]; ok {
    52  		currentDEK, err = decodePEMHeaderValue(currentDEKStr, kekData.KEK, r.FIPS)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  	}
    57  	if pendingDEKStr, ok := headers[pemHeaderRaftPendingDEK]; ok {
    58  		pendingDEK, err = decodePEMHeaderValue(pendingDEKStr, kekData.KEK, r.FIPS)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  	}
    63  
    64  	if pendingDEK != nil && currentDEK == nil {
    65  		return nil, fmt.Errorf("there is a pending DEK, but no current DEK")
    66  	}
    67  
    68  	_, ok := headers[pemHeaderRaftDEKNeedsRotation]
    69  	return RaftDEKData{
    70  		NeedsRotation: ok,
    71  		EncryptionKeys: raft.EncryptionKeys{
    72  			CurrentDEK: currentDEK,
    73  			PendingDEK: pendingDEK,
    74  		},
    75  		FIPS: r.FIPS,
    76  	}, nil
    77  }
    78  
    79  // MarshalHeaders returns new PEM headers given the current KEK - it uses the current KEK to
    80  // serialize/encrypt the current DEK state that is maintained in the current RaftDEKData object.
    81  func (r RaftDEKData) MarshalHeaders(kekData ca.KEKData) (map[string]string, error) {
    82  	headers := make(map[string]string)
    83  	for headerKey, contents := range map[string][]byte{
    84  		pemHeaderRaftDEK:        r.CurrentDEK,
    85  		pemHeaderRaftPendingDEK: r.PendingDEK,
    86  	} {
    87  		if contents != nil {
    88  			dekStr, err := encodePEMHeaderValue(contents, kekData.KEK, r.FIPS)
    89  			if err != nil {
    90  				return nil, err
    91  			}
    92  			headers[headerKey] = dekStr
    93  		}
    94  	}
    95  
    96  	if r.NeedsRotation {
    97  		headers[pemHeaderRaftDEKNeedsRotation] = "true"
    98  	}
    99  
   100  	// return a function that updates the dek data on write success
   101  	return headers, nil
   102  }
   103  
   104  // UpdateKEK sets NeedRotation to true if we go from unlocked to locked.
   105  func (r RaftDEKData) UpdateKEK(oldKEK, candidateKEK ca.KEKData) ca.PEMKeyHeaders {
   106  	if _, unlockedToLocked, err := compareKEKs(oldKEK, candidateKEK); err == nil && unlockedToLocked {
   107  		return RaftDEKData{
   108  			EncryptionKeys: r.EncryptionKeys,
   109  			NeedsRotation:  true,
   110  			FIPS:           r.FIPS,
   111  		}
   112  	}
   113  	return r
   114  }
   115  
   116  // Returns whether the old KEK should be replaced with the new KEK, whether we went from
   117  // unlocked to locked, and whether there was an error (the versions are the same, but the
   118  // keks are different)
   119  func compareKEKs(oldKEK, candidateKEK ca.KEKData) (bool, bool, error) {
   120  	keksEqual := subtle.ConstantTimeCompare(oldKEK.KEK, candidateKEK.KEK) == 1
   121  	switch {
   122  	case oldKEK.Version == candidateKEK.Version && !keksEqual:
   123  		return false, false, fmt.Errorf("candidate KEK has the same version as the current KEK, but a different KEK value")
   124  	case oldKEK.Version >= candidateKEK.Version || keksEqual:
   125  		return false, false, nil
   126  	default:
   127  		return true, oldKEK.KEK == nil, nil
   128  	}
   129  }
   130  
   131  // RaftDEKManager manages the raft DEK keys by interacting with KeyReadWriter, calling the necessary functions
   132  // to update the TLS headers when the raft DEK needs to change, or to re-encrypt everything when the KEK changes.
   133  type RaftDEKManager struct {
   134  	kw         ca.KeyWriter
   135  	rotationCh chan struct{}
   136  	FIPS       bool
   137  }
   138  
   139  var errNoUpdateNeeded = fmt.Errorf("don't need to rotate or update")
   140  
   141  // this error is returned if the KeyReadWriter's PEMKeyHeaders object is no longer a RaftDEKData object -
   142  // this can happen if the node is no longer a manager, for example
   143  var errNotUsingRaftDEKData = fmt.Errorf("RaftDEKManager can no longer store and manage TLS key headers")
   144  
   145  // NewRaftDEKManager returns a RaftDEKManager that uses the current key writer
   146  // and header manager
   147  func NewRaftDEKManager(kw ca.KeyWriter, fips bool) (*RaftDEKManager, error) {
   148  	// If there is no current DEK, generate one and write it to disk
   149  	err := kw.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
   150  		dekData, ok := h.(RaftDEKData)
   151  		// it wasn't a raft DEK manager before - just replace it
   152  		if !ok || dekData.CurrentDEK == nil {
   153  			return RaftDEKData{
   154  				EncryptionKeys: raft.EncryptionKeys{
   155  					CurrentDEK: encryption.GenerateSecretKey(),
   156  				},
   157  				FIPS: fips,
   158  			}, nil
   159  		}
   160  		return nil, errNoUpdateNeeded
   161  	})
   162  	if err != nil && err != errNoUpdateNeeded {
   163  		return nil, err
   164  	}
   165  	return &RaftDEKManager{
   166  		kw:         kw,
   167  		FIPS:       fips,
   168  		rotationCh: make(chan struct{}, 1),
   169  	}, nil
   170  }
   171  
   172  // NeedsRotation returns a boolean about whether we should do a rotation
   173  func (r *RaftDEKManager) NeedsRotation() bool {
   174  	h, _ := r.kw.GetCurrentState()
   175  	data, ok := h.(RaftDEKData)
   176  	if !ok {
   177  		return false
   178  	}
   179  	return data.NeedsRotation || data.EncryptionKeys.PendingDEK != nil
   180  }
   181  
   182  // GetKeys returns the current set of DEKs.  If NeedsRotation is true, and there
   183  // is no existing PendingDEK, it will try to create one.  If it successfully creates
   184  // and writes a PendingDEK, it sets NeedRotation to false.  If there are any errors
   185  // doing so, just return the original set of keys.
   186  func (r *RaftDEKManager) GetKeys() raft.EncryptionKeys {
   187  	var newKeys, originalKeys raft.EncryptionKeys
   188  	err := r.kw.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
   189  		data, ok := h.(RaftDEKData)
   190  		if !ok {
   191  			return nil, errNotUsingRaftDEKData
   192  		}
   193  		originalKeys = data.EncryptionKeys
   194  		if !data.NeedsRotation || data.PendingDEK != nil {
   195  			return nil, errNoUpdateNeeded
   196  		}
   197  		newKeys = raft.EncryptionKeys{
   198  			CurrentDEK: data.CurrentDEK,
   199  			PendingDEK: encryption.GenerateSecretKey(),
   200  		}
   201  		return RaftDEKData{
   202  			EncryptionKeys: newKeys,
   203  			FIPS:           data.FIPS,
   204  		}, nil
   205  	})
   206  	if err != nil {
   207  		return originalKeys
   208  	}
   209  	return newKeys
   210  }
   211  
   212  // RotationNotify the channel used to notify subscribers as to whether there
   213  // should be a rotation done
   214  func (r *RaftDEKManager) RotationNotify() chan struct{} {
   215  	return r.rotationCh
   216  }
   217  
   218  // UpdateKeys will set the updated encryption keys in the headers.  This finishes
   219  // a rotation, and is expected to set the CurrentDEK to the previous PendingDEK.
   220  func (r *RaftDEKManager) UpdateKeys(newKeys raft.EncryptionKeys) error {
   221  	return r.kw.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
   222  		data, ok := h.(RaftDEKData)
   223  		if !ok {
   224  			return nil, errNotUsingRaftDEKData
   225  		}
   226  		// If there is no current DEK, we are basically wiping out all DEKs (no header object)
   227  		if newKeys.CurrentDEK == nil {
   228  			return nil, nil
   229  		}
   230  		return RaftDEKData{
   231  			EncryptionKeys: newKeys,
   232  			NeedsRotation:  data.NeedsRotation,
   233  			FIPS:           data.FIPS,
   234  		}, nil
   235  	})
   236  }
   237  
   238  // MaybeUpdateKEK does a KEK rotation if one is required.  Returns whether
   239  // the kek was updated, whether it went from unlocked to locked, and any errors.
   240  func (r *RaftDEKManager) MaybeUpdateKEK(candidateKEK ca.KEKData) (bool, bool, error) {
   241  	var updated, unlockedToLocked bool
   242  	err := r.kw.ViewAndRotateKEK(func(currentKEK ca.KEKData, h ca.PEMKeyHeaders) (ca.KEKData, ca.PEMKeyHeaders, error) {
   243  		var err error
   244  		updated, unlockedToLocked, err = compareKEKs(currentKEK, candidateKEK)
   245  		if err == nil && !updated { // if we don't need to rotate the KEK, don't bother updating
   246  			err = errNoUpdateNeeded
   247  		}
   248  		if err != nil {
   249  			return ca.KEKData{}, nil, err
   250  		}
   251  
   252  		data, ok := h.(RaftDEKData)
   253  		if !ok {
   254  			return ca.KEKData{}, nil, errNotUsingRaftDEKData
   255  		}
   256  
   257  		if unlockedToLocked {
   258  			data.NeedsRotation = true
   259  		}
   260  		return candidateKEK, data, nil
   261  	})
   262  	if err == errNoUpdateNeeded {
   263  		err = nil
   264  	}
   265  
   266  	if err == nil && unlockedToLocked {
   267  		r.rotationCh <- struct{}{}
   268  	}
   269  	return updated, unlockedToLocked, err
   270  }
   271  
   272  func decodePEMHeaderValue(headerValue string, kek []byte, fips bool) ([]byte, error) {
   273  	var decrypter encryption.Decrypter = encryption.NoopCrypter
   274  	if kek != nil {
   275  		_, decrypter = encryption.Defaults(kek, fips)
   276  	}
   277  	valueBytes, err := base64.StdEncoding.DecodeString(headerValue)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	result, err := encryption.Decrypt(valueBytes, decrypter)
   282  	if err != nil {
   283  		return nil, ca.ErrInvalidKEK{Wrapped: err}
   284  	}
   285  	return result, nil
   286  }
   287  
   288  func encodePEMHeaderValue(headerValue []byte, kek []byte, fips bool) (string, error) {
   289  	var encrypter encryption.Encrypter = encryption.NoopCrypter
   290  	if kek != nil {
   291  		encrypter, _ = encryption.Defaults(kek, fips)
   292  	}
   293  	encrypted, err := encryption.Encrypt(headerValue, encrypter)
   294  	if err != nil {
   295  		return "", err
   296  	}
   297  	return base64.StdEncoding.EncodeToString(encrypted), nil
   298  }