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 }