k8s.io/apiserver@v0.31.1/pkg/storage/value/encrypt/envelope/envelope.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package envelope transforms values for storage at rest using a Envelope provider 18 package envelope 19 20 import ( 21 "context" 22 "crypto/aes" 23 "crypto/cipher" 24 "crypto/rand" 25 "encoding/base64" 26 "fmt" 27 "time" 28 29 "k8s.io/apiserver/pkg/storage/value" 30 "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics" 31 "k8s.io/utils/lru" 32 33 "golang.org/x/crypto/cryptobyte" 34 ) 35 36 func init() { 37 value.RegisterMetrics() 38 metrics.RegisterMetrics() 39 } 40 41 // Service allows encrypting and decrypting data using an external Key Management Service. 42 type Service interface { 43 // Decrypt a given bytearray to obtain the original data as bytes. 44 Decrypt(data []byte) ([]byte, error) 45 // Encrypt bytes to a ciphertext. 46 Encrypt(data []byte) ([]byte, error) 47 } 48 49 type envelopeTransformer struct { 50 envelopeService Service 51 52 // transformers is a thread-safe LRU cache which caches decrypted DEKs indexed by their encrypted form. 53 transformers *lru.Cache 54 55 // baseTransformerFunc creates a new transformer for encrypting the data with the DEK. 56 baseTransformerFunc func(cipher.Block) (value.Transformer, error) 57 58 cacheSize int 59 cacheEnabled bool 60 } 61 62 // NewEnvelopeTransformer returns a transformer which implements a KEK-DEK based envelope encryption scheme. 63 // It uses envelopeService to encrypt and decrypt DEKs. Respective DEKs (in encrypted form) are prepended to 64 // the data items they encrypt. A cache (of size cacheSize) is maintained to store the most recently 65 // used decrypted DEKs in memory. 66 func NewEnvelopeTransformer(envelopeService Service, cacheSize int, baseTransformerFunc func(cipher.Block) (value.Transformer, error)) value.Transformer { 67 var ( 68 cache *lru.Cache 69 ) 70 71 if cacheSize > 0 { 72 cache = lru.New(cacheSize) 73 } 74 return &envelopeTransformer{ 75 envelopeService: envelopeService, 76 transformers: cache, 77 baseTransformerFunc: baseTransformerFunc, 78 cacheEnabled: cacheSize > 0, 79 cacheSize: cacheSize, 80 } 81 } 82 83 // TransformFromStorage decrypts data encrypted by this transformer using envelope encryption. 84 func (t *envelopeTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) { 85 metrics.RecordArrival(metrics.FromStorageLabel, time.Now()) 86 87 // Read the 16 bit length-of-DEK encoded at the start of the encrypted DEK. 16 bits can 88 // represent a maximum key length of 65536 bytes. We are using a 256 bit key, whose 89 // length cannot fit in 8 bits (1 byte). Thus, we use 16 bits (2 bytes) to store the length. 90 var encKey cryptobyte.String 91 s := cryptobyte.String(data) 92 if ok := s.ReadUint16LengthPrefixed(&encKey); !ok { 93 return nil, false, fmt.Errorf("invalid data encountered by envelope transformer: failed to read uint16 length prefixed data") 94 } 95 96 encData := []byte(s) 97 98 // Look up the decrypted DEK from cache or Envelope. 99 transformer := t.getTransformer(encKey) 100 if transformer == nil { 101 if t.cacheEnabled { 102 value.RecordCacheMiss() 103 } 104 key, err := t.envelopeService.Decrypt(encKey) 105 if err != nil { 106 // Do NOT wrap this err using fmt.Errorf() or similar functions 107 // because this gRPC status error has useful error code when 108 // record the metric. 109 return nil, false, err 110 } 111 112 transformer, err = t.addTransformer(encKey, key) 113 if err != nil { 114 return nil, false, err 115 } 116 } 117 118 return transformer.TransformFromStorage(ctx, encData, dataCtx) 119 } 120 121 // TransformToStorage encrypts data to be written to disk using envelope encryption. 122 func (t *envelopeTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) { 123 metrics.RecordArrival(metrics.ToStorageLabel, time.Now()) 124 newKey, err := generateKey(32) 125 if err != nil { 126 return nil, err 127 } 128 129 encKey, err := t.envelopeService.Encrypt(newKey) 130 if err != nil { 131 // Do NOT wrap this err using fmt.Errorf() or similar functions 132 // because this gRPC status error has useful error code when 133 // record the metric. 134 return nil, err 135 } 136 137 transformer, err := t.addTransformer(encKey, newKey) 138 if err != nil { 139 return nil, err 140 } 141 142 result, err := transformer.TransformToStorage(ctx, data, dataCtx) 143 if err != nil { 144 return nil, err 145 } 146 // Append the length of the encrypted DEK as the first 2 bytes. 147 b := cryptobyte.NewBuilder(nil) 148 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { 149 b.AddBytes([]byte(encKey)) 150 }) 151 b.AddBytes(result) 152 153 return b.Bytes() 154 } 155 156 var _ value.Transformer = &envelopeTransformer{} 157 158 // addTransformer inserts a new transformer to the Envelope cache of DEKs for future reads. 159 func (t *envelopeTransformer) addTransformer(encKey []byte, key []byte) (value.Transformer, error) { 160 block, err := aes.NewCipher(key) 161 if err != nil { 162 return nil, err 163 } 164 transformer, err := t.baseTransformerFunc(block) 165 if err != nil { 166 return nil, err 167 } 168 169 // Use base64 of encKey as the key into the cache because hashicorp/golang-lru 170 // cannot hash []uint8. 171 if t.cacheEnabled { 172 t.transformers.Add(base64.StdEncoding.EncodeToString(encKey), transformer) 173 metrics.RecordDekCacheFillPercent(float64(t.transformers.Len()) / float64(t.cacheSize)) 174 } 175 return transformer, nil 176 } 177 178 // getTransformer fetches the transformer corresponding to encKey from cache, if it exists. 179 func (t *envelopeTransformer) getTransformer(encKey []byte) value.Transformer { 180 if !t.cacheEnabled { 181 return nil 182 } 183 184 _transformer, found := t.transformers.Get(base64.StdEncoding.EncodeToString(encKey)) 185 if found { 186 return _transformer.(value.Transformer) 187 } 188 return nil 189 } 190 191 // generateKey generates a random key using system randomness. 192 func generateKey(length int) (key []byte, err error) { 193 defer func(start time.Time) { 194 value.RecordDataKeyGeneration(start, err) 195 }(time.Now()) 196 key = make([]byte, length) 197 if _, err = rand.Read(key); err != nil { 198 return nil, err 199 } 200 201 return key, nil 202 }