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  }