storage: transformers: pass a context.Context

When an envelope transformer calls out to KMS (for instance), it will be
very helpful to pass a `context.Context` to allow for cancellation. This
patch does that, while passing the previously-expected additional data
via a context value.

Signed-off-by: Steve Kuznetsov <skuznets@redhat.com>
This commit is contained in:
Steve Kuznetsov 2022-02-17 07:29:44 -08:00
parent aa0e6320d5
commit 27312feb99
No known key found for this signature in database
GPG Key ID: 8821C29EC988D9B4
17 changed files with 180 additions and 150 deletions

View File

@ -18,6 +18,7 @@ package encryptionconfig
import ( import (
"bytes" "bytes"
"context"
"encoding/base64" "encoding/base64"
"errors" "errors"
"io" "io"
@ -184,7 +185,8 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) {
secretboxFirstTransformer := secretboxFirstTransformerOverrides[schema.ParseGroupResource("secrets")] secretboxFirstTransformer := secretboxFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
kmsFirstTransformer := kmsFirstTransformerOverrides[schema.ParseGroupResource("secrets")] kmsFirstTransformer := kmsFirstTransformerOverrides[schema.ParseGroupResource("secrets")]
context := value.DefaultContext([]byte(sampleContextText)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(sampleContextText))
originalText := []byte(sampleText) originalText := []byte(sampleText)
transformers := []struct { transformers := []struct {
@ -199,13 +201,13 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) {
} }
for _, testCase := range transformers { for _, testCase := range transformers {
transformedData, err := testCase.Transformer.TransformToStorage(originalText, context) transformedData, err := testCase.Transformer.TransformToStorage(ctx, originalText, dataCtx)
if err != nil { if err != nil {
t.Fatalf("%s: error while transforming data to storage: %s", testCase.Name, err) t.Fatalf("%s: error while transforming data to storage: %s", testCase.Name, err)
} }
for _, transformer := range transformers { for _, transformer := range transformers {
untransformedData, stale, err := transformer.Transformer.TransformFromStorage(transformedData, context) untransformedData, stale, err := transformer.Transformer.TransformFromStorage(ctx, transformedData, dataCtx)
if err != nil { if err != nil {
t.Fatalf("%s: error while reading using %s transformer: %s", testCase.Name, transformer.Name, err) t.Fatalf("%s: error while reading using %s transformer: %s", testCase.Name, transformer.Name, err)
} }
@ -347,16 +349,17 @@ func TestCBCKeyRotationWithoutOverlappingProviders(t *testing.T) {
func testCBCKeyRotationWithProviders(t *testing.T, firstEncryptionConfig, firstPrefix, secondEncryptionConfig, secondPrefix string) { func testCBCKeyRotationWithProviders(t *testing.T, firstEncryptionConfig, firstPrefix, secondEncryptionConfig, secondPrefix string) {
p := getTransformerFromEncryptionConfig(t, firstEncryptionConfig) p := getTransformerFromEncryptionConfig(t, firstEncryptionConfig)
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
out, err := p.TransformToStorage([]byte("firstvalue"), context) out, err := p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.HasPrefix(out, []byte(firstPrefix)) { if !bytes.HasPrefix(out, []byte(firstPrefix)) {
t.Fatalf("unexpected prefix: %q", out) t.Fatalf("unexpected prefix: %q", out)
} }
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -365,14 +368,14 @@ func testCBCKeyRotationWithProviders(t *testing.T, firstEncryptionConfig, firstP
} }
// verify changing the context fails storage // verify changing the context fails storage
_, _, err = p.TransformFromStorage(out, value.DefaultContext([]byte("incorrect_context"))) _, _, err = p.TransformFromStorage(ctx, out, value.DefaultContext([]byte("incorrect_context")))
if err != nil { if err != nil {
t.Fatalf("CBC mode does not support authentication: %v", err) t.Fatalf("CBC mode does not support authentication: %v", err)
} }
// reverse the order, use the second key // reverse the order, use the second key
p = getTransformerFromEncryptionConfig(t, secondEncryptionConfig) p = getTransformerFromEncryptionConfig(t, secondEncryptionConfig)
from, stale, err = p.TransformFromStorage(out, context) from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -380,14 +383,14 @@ func testCBCKeyRotationWithProviders(t *testing.T, firstEncryptionConfig, firstP
t.Fatalf("unexpected data: %t %q", stale, from) t.Fatalf("unexpected data: %t %q", stale, from)
} }
out, err = p.TransformToStorage([]byte("firstvalue"), context) out, err = p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.HasPrefix(out, []byte(secondPrefix)) { if !bytes.HasPrefix(out, []byte(secondPrefix)) {
t.Fatalf("unexpected prefix: %q", out) t.Fatalf("unexpected prefix: %q", out)
} }
from, stale, err = p.TransformFromStorage(out, context) from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -136,7 +136,7 @@ func (s *store) Get(ctx context.Context, key string, opts storage.GetOptions, ou
} }
kv := getResp.Kvs[0] kv := getResp.Kvs[0]
data, _, err := s.transformer.TransformFromStorage(kv.Value, authenticatedDataString(key)) data, _, err := s.transformer.TransformFromStorage(ctx, kv.Value, authenticatedDataString(key))
if err != nil { if err != nil {
return storage.NewInternalError(err.Error()) return storage.NewInternalError(err.Error())
} }
@ -163,7 +163,7 @@ func (s *store) Create(ctx context.Context, key string, obj, out runtime.Object,
return err return err
} }
newData, err := s.transformer.TransformToStorage(data, authenticatedDataString(key)) newData, err := s.transformer.TransformToStorage(ctx, data, authenticatedDataString(key))
if err != nil { if err != nil {
return storage.NewInternalError(err.Error()) return storage.NewInternalError(err.Error())
} }
@ -211,7 +211,7 @@ func (s *store) conditionalDelete(
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.getState(getResp, key, v, false) return s.getState(ctx, getResp, key, v, false)
} }
var origState *objState var origState *objState
@ -296,7 +296,7 @@ func (s *store) conditionalDelete(
if !txnResp.Succeeded { if !txnResp.Succeeded {
getResp := (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange()) getResp := (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange())
klog.V(4).Infof("deletion of %s failed because of a conflict, going to retry", key) klog.V(4).Infof("deletion of %s failed because of a conflict, going to retry", key)
origState, err = s.getState(getResp, key, v, false) origState, err = s.getState(ctx, getResp, key, v, false)
if err != nil { if err != nil {
return err return err
} }
@ -327,7 +327,7 @@ func (s *store) GuaranteedUpdate(
if err != nil { if err != nil {
return nil, err return nil, err
} }
return s.getState(getResp, key, v, ignoreNotFound) return s.getState(ctx, getResp, key, v, ignoreNotFound)
} }
var origState *objState var origState *objState
@ -415,7 +415,7 @@ func (s *store) GuaranteedUpdate(
} }
} }
newData, err := s.transformer.TransformToStorage(data, transformContext) newData, err := s.transformer.TransformToStorage(ctx, data, transformContext)
if err != nil { if err != nil {
return storage.NewInternalError(err.Error()) return storage.NewInternalError(err.Error())
} }
@ -442,7 +442,7 @@ func (s *store) GuaranteedUpdate(
if !txnResp.Succeeded { if !txnResp.Succeeded {
getResp := (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange()) getResp := (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange())
klog.V(4).Infof("GuaranteedUpdate of %s failed because of a conflict, going to retry", key) klog.V(4).Infof("GuaranteedUpdate of %s failed because of a conflict, going to retry", key)
origState, err = s.getState(getResp, key, v, ignoreNotFound) origState, err = s.getState(ctx, getResp, key, v, ignoreNotFound)
if err != nil { if err != nil {
return err return err
} }
@ -728,7 +728,7 @@ func (s *store) list(ctx context.Context, key string, opts storage.ListOptions,
} }
lastKey = kv.Key lastKey = kv.Key
data, _, err := s.transformer.TransformFromStorage(kv.Value, authenticatedDataString(kv.Key)) data, _, err := s.transformer.TransformFromStorage(ctx, kv.Value, authenticatedDataString(kv.Key))
if err != nil { if err != nil {
return storage.NewInternalErrorf("unable to transform key %q: %v", kv.Key, err) return storage.NewInternalErrorf("unable to transform key %q: %v", kv.Key, err)
} }
@ -828,7 +828,7 @@ func (s *store) Watch(ctx context.Context, key string, opts storage.ListOptions)
return s.watcher.Watch(ctx, key, int64(rev), opts.Recursive, opts.ProgressNotify, opts.Predicate) return s.watcher.Watch(ctx, key, int64(rev), opts.Recursive, opts.ProgressNotify, opts.Predicate)
} }
func (s *store) getState(getResp *clientv3.GetResponse, key string, v reflect.Value, ignoreNotFound bool) (*objState, error) { func (s *store) getState(ctx context.Context, getResp *clientv3.GetResponse, key string, v reflect.Value, ignoreNotFound bool) (*objState, error) {
state := &objState{ state := &objState{
meta: &storage.ResponseMeta{}, meta: &storage.ResponseMeta{},
} }
@ -847,7 +847,7 @@ func (s *store) getState(getResp *clientv3.GetResponse, key string, v reflect.Va
return nil, err return nil, err
} }
} else { } else {
data, stale, err := s.transformer.TransformFromStorage(getResp.Kvs[0].Value, authenticatedDataString(key)) data, stale, err := s.transformer.TransformFromStorage(ctx, getResp.Kvs[0].Value, authenticatedDataString(key))
if err != nil { if err != nil {
return nil, storage.NewInternalError(err.Error()) return nil, storage.NewInternalError(err.Error())
} }

View File

@ -35,7 +35,7 @@ import (
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
apitesting "k8s.io/apimachinery/pkg/api/apitesting" "k8s.io/apimachinery/pkg/api/apitesting"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
@ -79,24 +79,24 @@ type prefixTransformer struct {
reads uint64 reads uint64
} }
func (p *prefixTransformer) TransformFromStorage(b []byte, ctx value.Context) ([]byte, bool, error) { func (p *prefixTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
atomic.AddUint64(&p.reads, 1) atomic.AddUint64(&p.reads, 1)
if ctx == nil { if dataCtx == nil {
panic("no context provided") panic("no context provided")
} }
if !bytes.HasPrefix(b, p.prefix) { if !bytes.HasPrefix(data, p.prefix) {
return nil, false, fmt.Errorf("value does not have expected prefix %q: %s,", p.prefix, string(b)) return nil, false, fmt.Errorf("value does not have expected prefix %q: %s,", p.prefix, string(data))
} }
return bytes.TrimPrefix(b, p.prefix), p.stale, p.err return bytes.TrimPrefix(data, p.prefix), p.stale, p.err
} }
func (p *prefixTransformer) TransformToStorage(b []byte, ctx value.Context) ([]byte, error) { func (p *prefixTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
if ctx == nil { if dataCtx == nil {
panic("no context provided") panic("no context provided")
} }
if len(b) > 0 { if len(data) > 0 {
return append(append([]byte{}, p.prefix...), b...), p.err return append(append([]byte{}, p.prefix...), data...), p.err
} }
return b, p.err return data, p.err
} }
func (p *prefixTransformer) resetReads() { func (p *prefixTransformer) resetReads() {
@ -2210,18 +2210,18 @@ type fancyTransformer struct {
index int index int
} }
func (t *fancyTransformer) TransformFromStorage(b []byte, ctx value.Context) ([]byte, bool, error) { func (t *fancyTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
if err := t.createObject(); err != nil { if err := t.createObject(ctx); err != nil {
return nil, false, err return nil, false, err
} }
return t.transformer.TransformFromStorage(b, ctx) return t.transformer.TransformFromStorage(ctx, data, dataCtx)
} }
func (t *fancyTransformer) TransformToStorage(b []byte, ctx value.Context) ([]byte, error) { func (t *fancyTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
return t.transformer.TransformToStorage(b, ctx) return t.transformer.TransformToStorage(ctx, data, dataCtx)
} }
func (t *fancyTransformer) createObject() error { func (t *fancyTransformer) createObject(ctx context.Context) error {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@ -2236,7 +2236,7 @@ func (t *fancyTransformer) createObject() error {
}, },
} }
out := &example.Pod{} out := &example.Pod{}
return t.store.Create(context.TODO(), key, obj, out, 0) return t.store.Create(ctx, key, obj, out, 0)
} }
func TestConsistentList(t *testing.T) { func TestConsistentList(t *testing.T) {
@ -2250,7 +2250,7 @@ func TestConsistentList(t *testing.T) {
transformer.store = store transformer.store = store
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
if err := transformer.createObject(); err != nil { if err := transformer.createObject(context.TODO()); err != nil {
t.Fatalf("failed to create object: %v", err) t.Fatalf("failed to create object: %v", err)
} }
} }

View File

@ -426,7 +426,7 @@ func (wc *watchChan) prepareObjs(e *event) (curObj runtime.Object, oldObj runtim
} }
if !e.isDeleted { if !e.isDeleted {
data, _, err := wc.watcher.transformer.TransformFromStorage(e.value, authenticatedDataString(e.key)) data, _, err := wc.watcher.transformer.TransformFromStorage(wc.ctx, e.value, authenticatedDataString(e.key))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -441,7 +441,7 @@ func (wc *watchChan) prepareObjs(e *event) (curObj runtime.Object, oldObj runtim
// we need the object only to compute whether it was filtered out // we need the object only to compute whether it was filtered out
// before). // before).
if len(e.prevValue) > 0 && (e.isDeleted || !wc.acceptAll()) { if len(e.prevValue) > 0 && (e.isDeleted || !wc.acceptAll()) {
data, _, err := wc.watcher.transformer.TransformFromStorage(e.prevValue, authenticatedDataString(e.key)) data, _, err := wc.watcher.transformer.TransformFromStorage(wc.ctx, e.prevValue, authenticatedDataString(e.key))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -19,6 +19,7 @@ package aes
import ( import (
"bytes" "bytes"
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
@ -52,7 +53,7 @@ func NewGCMTransformer(block cipher.Block) value.Transformer {
return &gcm{block: block} return &gcm{block: block}
} }
func (t *gcm) TransformFromStorage(data []byte, context value.Context) ([]byte, bool, error) { func (t *gcm) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
aead, err := cipher.NewGCM(t.block) aead, err := cipher.NewGCM(t.block)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
@ -61,11 +62,11 @@ func (t *gcm) TransformFromStorage(data []byte, context value.Context) ([]byte,
if len(data) < nonceSize { if len(data) < nonceSize {
return nil, false, fmt.Errorf("the stored data was shorter than the required size") return nil, false, fmt.Errorf("the stored data was shorter than the required size")
} }
result, err := aead.Open(nil, data[:nonceSize], data[nonceSize:], context.AuthenticatedData()) result, err := aead.Open(nil, data[:nonceSize], data[nonceSize:], dataCtx.AuthenticatedData())
return result, false, err return result, false, err
} }
func (t *gcm) TransformToStorage(data []byte, context value.Context) ([]byte, error) { func (t *gcm) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
aead, err := cipher.NewGCM(t.block) aead, err := cipher.NewGCM(t.block)
if err != nil { if err != nil {
return nil, err return nil, err
@ -79,7 +80,7 @@ func (t *gcm) TransformToStorage(data []byte, context value.Context) ([]byte, er
if n != nonceSize { if n != nonceSize {
return nil, fmt.Errorf("unable to read sufficient random bytes") return nil, fmt.Errorf("unable to read sufficient random bytes")
} }
cipherText := aead.Seal(result[nonceSize:nonceSize], result[:nonceSize], data, context.AuthenticatedData()) cipherText := aead.Seal(result[nonceSize:nonceSize], result[:nonceSize], data, dataCtx.AuthenticatedData())
return result[:nonceSize+len(cipherText)], nil return result[:nonceSize+len(cipherText)], nil
} }
@ -100,7 +101,7 @@ var (
errInvalidPKCS7Padding = errors.New("invalid padding on input") errInvalidPKCS7Padding = errors.New("invalid padding on input")
) )
func (t *cbc) TransformFromStorage(data []byte, context value.Context) ([]byte, bool, error) { func (t *cbc) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
blockSize := aes.BlockSize blockSize := aes.BlockSize
if len(data) < blockSize { if len(data) < blockSize {
return nil, false, fmt.Errorf("the stored data was shorter than the required size") return nil, false, fmt.Errorf("the stored data was shorter than the required size")
@ -133,7 +134,7 @@ func (t *cbc) TransformFromStorage(data []byte, context value.Context) ([]byte,
return result[:size], false, nil return result[:size], false, nil
} }
func (t *cbc) TransformToStorage(data []byte, context value.Context) ([]byte, error) { func (t *cbc) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
blockSize := aes.BlockSize blockSize := aes.BlockSize
paddingSize := blockSize - (len(data) % blockSize) paddingSize := blockSize - (len(data) % blockSize)
result := make([]byte, blockSize+len(data)+paddingSize) result := make([]byte, blockSize+len(data)+paddingSize)

View File

@ -18,6 +18,7 @@ package aes
import ( import (
"bytes" "bytes"
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
@ -56,20 +57,21 @@ func TestGCMKeyRotation(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
p := value.NewPrefixTransformers(testErr, p := value.NewPrefixTransformers(testErr,
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewGCMTransformer(block1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewGCMTransformer(block1)},
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)},
) )
out, err := p.TransformToStorage([]byte("firstvalue"), context) out, err := p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.HasPrefix(out, []byte("first:")) { if !bytes.HasPrefix(out, []byte("first:")) {
t.Fatalf("unexpected prefix: %q", out) t.Fatalf("unexpected prefix: %q", out)
} }
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -78,7 +80,7 @@ func TestGCMKeyRotation(t *testing.T) {
} }
// verify changing the context fails storage // verify changing the context fails storage
_, _, err = p.TransformFromStorage(out, value.DefaultContext([]byte("incorrect_context"))) _, _, err = p.TransformFromStorage(ctx, out, value.DefaultContext([]byte("incorrect_context")))
if err == nil { if err == nil {
t.Fatalf("expected unauthenticated data") t.Fatalf("expected unauthenticated data")
} }
@ -88,7 +90,7 @@ func TestGCMKeyRotation(t *testing.T) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)},
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewGCMTransformer(block1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewGCMTransformer(block1)},
) )
from, stale, err = p.TransformFromStorage(out, context) from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -108,20 +110,21 @@ func TestCBCKeyRotation(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
p := value.NewPrefixTransformers(testErr, p := value.NewPrefixTransformers(testErr,
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewCBCTransformer(block1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewCBCTransformer(block1)},
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)},
) )
out, err := p.TransformToStorage([]byte("firstvalue"), context) out, err := p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.HasPrefix(out, []byte("first:")) { if !bytes.HasPrefix(out, []byte("first:")) {
t.Fatalf("unexpected prefix: %q", out) t.Fatalf("unexpected prefix: %q", out)
} }
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -130,7 +133,7 @@ func TestCBCKeyRotation(t *testing.T) {
} }
// verify changing the context fails storage // verify changing the context fails storage
_, _, err = p.TransformFromStorage(out, value.DefaultContext([]byte("incorrect_context"))) _, _, err = p.TransformFromStorage(ctx, out, value.DefaultContext([]byte("incorrect_context")))
if err != nil { if err != nil {
t.Fatalf("CBC mode does not support authentication: %v", err) t.Fatalf("CBC mode does not support authentication: %v", err)
} }
@ -140,7 +143,7 @@ func TestCBCKeyRotation(t *testing.T) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)},
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewCBCTransformer(block1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewCBCTransformer(block1)},
) )
from, stale, err = p.TransformFromStorage(out, context) from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -199,10 +202,11 @@ func benchmarkGCMRead(b *testing.B, keyLength int, valueLength int, expectStale
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
out, err := p.TransformToStorage(v, context) out, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -216,7 +220,7 @@ func benchmarkGCMRead(b *testing.B, keyLength int, valueLength int, expectStale
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -241,12 +245,13 @@ func benchmarkGCMWrite(b *testing.B, keyLength int, valueLength int) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewGCMTransformer(block2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := p.TransformToStorage(v, context) _, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -302,10 +307,11 @@ func benchmarkCBCRead(b *testing.B, keyLength int, valueLength int, expectStale
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
out, err := p.TransformToStorage(v, context) out, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -319,7 +325,7 @@ func benchmarkCBCRead(b *testing.B, keyLength int, valueLength int, expectStale
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -344,12 +350,13 @@ func benchmarkCBCWrite(b *testing.B, keyLength int, valueLength int) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewCBCTransformer(block2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := p.TransformToStorage(v, context) _, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -373,9 +380,10 @@ func TestRoundTrip(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
ctx := context.Background()
tests := []struct { tests := []struct {
name string name string
context value.Context dataCtx value.Context
t value.Transformer t value.Transformer
}{ }{
{name: "GCM 16 byte key", t: NewGCMTransformer(aes16block)}, {name: "GCM 16 byte key", t: NewGCMTransformer(aes16block)},
@ -385,9 +393,9 @@ func TestRoundTrip(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
context := tt.context dataCtx := tt.dataCtx
if context == nil { if dataCtx == nil {
context = value.DefaultContext("") dataCtx = value.DefaultContext([]byte(""))
} }
for _, l := range lengths { for _, l := range lengths {
data := make([]byte, l) data := make([]byte, l)
@ -396,13 +404,13 @@ func TestRoundTrip(t *testing.T) {
} }
original := append([]byte{}, data...) original := append([]byte{}, data...)
ciphertext, err := tt.t.TransformToStorage(data, context) ciphertext, err := tt.t.TransformToStorage(ctx, data, dataCtx)
if err != nil { if err != nil {
t.Errorf("TransformToStorage error = %v", err) t.Errorf("TransformToStorage error = %v", err)
continue continue
} }
result, stale, err := tt.t.TransformFromStorage(ciphertext, context) result, stale, err := tt.t.TransformFromStorage(ctx, ciphertext, dataCtx)
if err != nil { if err != nil {
t.Errorf("TransformFromStorage error = %v", err) t.Errorf("TransformFromStorage error = %v", err)
continue continue

View File

@ -18,6 +18,7 @@ limitations under the License.
package envelope package envelope
import ( import (
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
@ -79,7 +80,7 @@ func NewEnvelopeTransformer(envelopeService Service, cacheSize int, baseTransfor
} }
// TransformFromStorage decrypts data encrypted by this transformer using envelope encryption. // TransformFromStorage decrypts data encrypted by this transformer using envelope encryption.
func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Context) ([]byte, bool, error) { func (t *envelopeTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
recordArrival(fromStorageLabel, time.Now()) recordArrival(fromStorageLabel, time.Now())
// Read the 16 bit length-of-DEK encoded at the start of the encrypted DEK. 16 bits can // Read the 16 bit length-of-DEK encoded at the start of the encrypted DEK. 16 bits can
@ -113,11 +114,11 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
} }
} }
return transformer.TransformFromStorage(encData, context) return transformer.TransformFromStorage(ctx, encData, dataCtx)
} }
// TransformToStorage encrypts data to be written to disk using envelope encryption. // TransformToStorage encrypts data to be written to disk using envelope encryption.
func (t *envelopeTransformer) TransformToStorage(data []byte, context value.Context) ([]byte, error) { func (t *envelopeTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
recordArrival(toStorageLabel, time.Now()) recordArrival(toStorageLabel, time.Now())
newKey, err := generateKey(32) newKey, err := generateKey(32)
if err != nil { if err != nil {
@ -137,7 +138,7 @@ func (t *envelopeTransformer) TransformToStorage(data []byte, context value.Cont
return nil, err return nil, err
} }
result, err := transformer.TransformToStorage(data, context) result, err := transformer.TransformToStorage(ctx, data, dataCtx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,6 +18,7 @@ package envelope
import ( import (
"bytes" "bytes"
"context"
"crypto/aes" "crypto/aes"
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
@ -101,14 +102,15 @@ func TestEnvelopeCaching(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to initialize envelope transformer: %v", err) t.Fatalf("failed to initialize envelope transformer: %v", err)
} }
context := value.DefaultContext([]byte(testContextText)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(testContextText))
originalText := []byte(testText) originalText := []byte(testText)
transformedData, err := envelopeTransformer.TransformToStorage(originalText, context) transformedData, err := envelopeTransformer.TransformToStorage(ctx, originalText, dataCtx)
if err != nil { if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data to storage: %s", err) t.Fatalf("envelopeTransformer: error while transforming data to storage: %s", err)
} }
untransformedData, _, err := envelopeTransformer.TransformFromStorage(transformedData, context) untransformedData, _, err := envelopeTransformer.TransformFromStorage(ctx, transformedData, dataCtx)
if err != nil { if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err) t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err)
} }
@ -118,7 +120,7 @@ func TestEnvelopeCaching(t *testing.T) {
envelopeService.SetDisabledStatus(tt.simulateKMSPluginFailure) envelopeService.SetDisabledStatus(tt.simulateKMSPluginFailure)
// Subsequent read for the same data should work fine due to caching. // Subsequent read for the same data should work fine due to caching.
untransformedData, _, err = envelopeTransformer.TransformFromStorage(transformedData, context) untransformedData, _, err = envelopeTransformer.TransformFromStorage(ctx, transformedData, dataCtx)
if err != nil { if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data using just cache: %v", err) t.Fatalf("could not decrypt Envelope transformer's encrypted data using just cache: %v", err)
} }
@ -135,7 +137,8 @@ func TestEnvelopeCacheLimit(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to initialize envelope transformer: %v", err) t.Fatalf("failed to initialize envelope transformer: %v", err)
} }
context := value.DefaultContext([]byte(testContextText)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(testContextText))
transformedOutputs := map[int][]byte{} transformedOutputs := map[int][]byte{}
@ -143,7 +146,7 @@ func TestEnvelopeCacheLimit(t *testing.T) {
for i := 0; i < 2*testEnvelopeCacheSize; i++ { for i := 0; i < 2*testEnvelopeCacheSize; i++ {
numberText := []byte(strconv.Itoa(i)) numberText := []byte(strconv.Itoa(i))
res, err := envelopeTransformer.TransformToStorage(numberText, context) res, err := envelopeTransformer.TransformToStorage(ctx, numberText, dataCtx)
transformedOutputs[i] = res transformedOutputs[i] = res
if err != nil { if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data (%v) to storage: %s", numberText, err) t.Fatalf("envelopeTransformer: error while transforming data (%v) to storage: %s", numberText, err)
@ -154,7 +157,7 @@ func TestEnvelopeCacheLimit(t *testing.T) {
for i := 0; i < 2*testEnvelopeCacheSize; i++ { for i := 0; i < 2*testEnvelopeCacheSize; i++ {
numberText := []byte(strconv.Itoa(i)) numberText := []byte(strconv.Itoa(i))
output, _, err := envelopeTransformer.TransformFromStorage(transformedOutputs[i], context) output, _, err := envelopeTransformer.TransformFromStorage(ctx, transformedOutputs[i], dataCtx)
if err != nil { if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data (%v) from storage: %s", transformedOutputs[i], err) t.Fatalf("envelopeTransformer: error while transforming data (%v) from storage: %s", transformedOutputs[i], err)
} }
@ -202,17 +205,18 @@ func BenchmarkAESGCMRead(b *testing.B) {
} }
func benchmarkRead(b *testing.B, transformer value.Transformer, valueLength int) { func benchmarkRead(b *testing.B, transformer value.Transformer, valueLength int) {
context := value.DefaultContext([]byte(testContextText)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(testContextText))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
out, err := transformer.TransformToStorage(v, context) out, err := transformer.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
from, stale, err := transformer.TransformFromStorage(out, context) from, stale, err := transformer.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -230,14 +234,15 @@ func TestBackwardsCompatibility(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to initialize envelope transformer: %v", err) t.Fatalf("failed to initialize envelope transformer: %v", err)
} }
context := value.DefaultContext([]byte(testContextText)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(testContextText))
originalText := []byte(testText) originalText := []byte(testText)
transformedData, err := oldTransformToStorage(envelopeTransformerInst.(*envelopeTransformer), originalText, context) transformedData, err := oldTransformToStorage(ctx, envelopeTransformerInst.(*envelopeTransformer), originalText, dataCtx)
if err != nil { if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data to storage: %s", err) t.Fatalf("envelopeTransformer: error while transforming data to storage: %s", err)
} }
untransformedData, _, err := envelopeTransformerInst.TransformFromStorage(transformedData, context) untransformedData, _, err := envelopeTransformerInst.TransformFromStorage(ctx, transformedData, dataCtx)
if err != nil { if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err) t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err)
} }
@ -247,7 +252,7 @@ func TestBackwardsCompatibility(t *testing.T) {
envelopeService.SetDisabledStatus(true) envelopeService.SetDisabledStatus(true)
// Subsequent read for the same data should work fine due to caching. // Subsequent read for the same data should work fine due to caching.
untransformedData, _, err = envelopeTransformerInst.TransformFromStorage(transformedData, context) untransformedData, _, err = envelopeTransformerInst.TransformFromStorage(ctx, transformedData, dataCtx)
if err != nil { if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data using just cache: %v", err) t.Fatalf("could not decrypt Envelope transformer's encrypted data using just cache: %v", err)
} }
@ -257,7 +262,7 @@ func TestBackwardsCompatibility(t *testing.T) {
} }
// remove after 1.13 // remove after 1.13
func oldTransformToStorage(t *envelopeTransformer, data []byte, context value.Context) ([]byte, error) { func oldTransformToStorage(ctx context.Context, t *envelopeTransformer, data []byte, dataCtx value.Context) ([]byte, error) {
newKey, err := generateKey(32) newKey, err := generateKey(32)
if err != nil { if err != nil {
return nil, err return nil, err
@ -282,7 +287,7 @@ func oldTransformToStorage(t *envelopeTransformer, data []byte, context value.Co
prefixedData := make([]byte, len(prefix), len(data)+len(prefix)) prefixedData := make([]byte, len(prefix), len(data)+len(prefix))
copy(prefixedData, prefix) copy(prefixedData, prefix)
result, err := transformer.TransformToStorage(data, context) result, err := transformer.TransformToStorage(ctx, data, dataCtx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -18,6 +18,7 @@ package identity
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"k8s.io/apiserver/pkg/storage/value" "k8s.io/apiserver/pkg/storage/value"
@ -34,17 +35,17 @@ func NewEncryptCheckTransformer() value.Transformer {
} }
// TransformFromStorage returns the input bytes if the data is not encrypted // TransformFromStorage returns the input bytes if the data is not encrypted
func (identityTransformer) TransformFromStorage(b []byte, context value.Context) ([]byte, bool, error) { func (identityTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
// identityTransformer has to return an error if the data is encoded using another transformer. // identityTransformer has to return an error if the data is encoded using another transformer.
// JSON data starts with '{'. Protobuf data has a prefix 'k8s[\x00-\xFF]'. // JSON data starts with '{'. Protobuf data has a prefix 'k8s[\x00-\xFF]'.
// Prefix 'k8s:enc:' is reserved for encrypted data on disk. // Prefix 'k8s:enc:' is reserved for encrypted data on disk.
if bytes.HasPrefix(b, []byte("k8s:enc:")) { if bytes.HasPrefix(data, []byte("k8s:enc:")) {
return []byte{}, false, fmt.Errorf("identity transformer tried to read encrypted data") return []byte{}, false, fmt.Errorf("identity transformer tried to read encrypted data")
} }
return b, false, nil return data, false, nil
} }
// TransformToStorage implements the Transformer interface for identityTransformer // TransformToStorage implements the Transformer interface for identityTransformer
func (identityTransformer) TransformToStorage(b []byte, context value.Context) ([]byte, error) { func (identityTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
return b, nil return data, nil
} }

View File

@ -18,6 +18,7 @@ limitations under the License.
package secretbox package secretbox
import ( import (
"context"
"crypto/rand" "crypto/rand"
"fmt" "fmt"
@ -41,7 +42,7 @@ func NewSecretboxTransformer(key [32]byte) value.Transformer {
return &secretboxTransformer{key: key} return &secretboxTransformer{key: key}
} }
func (t *secretboxTransformer) TransformFromStorage(data []byte, context value.Context) ([]byte, bool, error) { func (t *secretboxTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) {
if len(data) < (secretbox.Overhead + nonceSize) { if len(data) < (secretbox.Overhead + nonceSize) {
return nil, false, fmt.Errorf("the stored data was shorter than the required size") return nil, false, fmt.Errorf("the stored data was shorter than the required size")
} }
@ -56,7 +57,7 @@ func (t *secretboxTransformer) TransformFromStorage(data []byte, context value.C
return result, false, nil return result, false, nil
} }
func (t *secretboxTransformer) TransformToStorage(data []byte, context value.Context) ([]byte, error) { func (t *secretboxTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) {
var nonce [nonceSize]byte var nonce [nonceSize]byte
n, err := rand.Read(nonce[:]) n, err := rand.Read(nonce[:])
if err != nil { if err != nil {

View File

@ -18,6 +18,7 @@ package secretbox
import ( import (
"bytes" "bytes"
"context"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -35,20 +36,21 @@ var (
func TestSecretboxKeyRotation(t *testing.T) { func TestSecretboxKeyRotation(t *testing.T) {
testErr := fmt.Errorf("test error") testErr := fmt.Errorf("test error")
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
p := value.NewPrefixTransformers(testErr, p := value.NewPrefixTransformers(testErr,
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
) )
out, err := p.TransformToStorage([]byte("firstvalue"), context) out, err := p.TransformToStorage(ctx, []byte("firstvalue"), dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.HasPrefix(out, []byte("first:")) { if !bytes.HasPrefix(out, []byte("first:")) {
t.Fatalf("unexpected prefix: %q", out) t.Fatalf("unexpected prefix: %q", out)
} }
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -58,7 +60,7 @@ func TestSecretboxKeyRotation(t *testing.T) {
// verify changing the context does not fails storage // verify changing the context does not fails storage
// Secretbox is not currently an authenticating store // Secretbox is not currently an authenticating store
_, _, err = p.TransformFromStorage(out, value.DefaultContext([]byte("incorrect_context"))) _, _, err = p.TransformFromStorage(ctx, out, value.DefaultContext([]byte("incorrect_context")))
if err != nil { if err != nil {
t.Fatalf("secretbox is not authenticated") t.Fatalf("secretbox is not authenticated")
} }
@ -68,7 +70,7 @@ func TestSecretboxKeyRotation(t *testing.T) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)}, value.PrefixTransformer{Prefix: []byte("first:"), Transformer: NewSecretboxTransformer(key1)},
) )
from, stale, err = p.TransformFromStorage(out, context) from, stale, err = p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -117,10 +119,11 @@ func benchmarkSecretboxRead(b *testing.B, keyLength int, valueLength int, expect
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
out, err := p.TransformToStorage(v, context) out, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -134,7 +137,7 @@ func benchmarkSecretboxRead(b *testing.B, keyLength int, valueLength int, expect
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
from, stale, err := p.TransformFromStorage(out, context) from, stale, err := p.TransformFromStorage(ctx, out, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -151,12 +154,13 @@ func benchmarkSecretboxWrite(b *testing.B, keyLength int, valueLength int) {
value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)}, value.PrefixTransformer{Prefix: []byte("second:"), Transformer: NewSecretboxTransformer(key2)},
) )
context := value.DefaultContext([]byte("authenticated_data")) ctx := context.Background()
dataCtx := value.DefaultContext([]byte("authenticated_data"))
v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16) v := bytes.Repeat([]byte("0123456789abcdef"), valueLength/16)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := p.TransformToStorage(v, context) _, err := p.TransformToStorage(ctx, v, dataCtx)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -167,18 +171,19 @@ func benchmarkSecretboxWrite(b *testing.B, keyLength int, valueLength int) {
func TestRoundTrip(t *testing.T) { func TestRoundTrip(t *testing.T) {
lengths := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 128, 1024} lengths := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 128, 1024}
ctx := context.Background()
tests := []struct { tests := []struct {
name string name string
context value.Context dataCtx value.Context
t value.Transformer t value.Transformer
}{ }{
{name: "Secretbox 32 byte key", t: NewSecretboxTransformer(key1)}, {name: "Secretbox 32 byte key", t: NewSecretboxTransformer(key1)},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
context := tt.context dataCtx := tt.dataCtx
if context == nil { if dataCtx == nil {
context = value.DefaultContext("") dataCtx = value.DefaultContext([]byte(""))
} }
for _, l := range lengths { for _, l := range lengths {
data := make([]byte, l) data := make([]byte, l)
@ -187,13 +192,13 @@ func TestRoundTrip(t *testing.T) {
} }
original := append([]byte{}, data...) original := append([]byte{}, data...)
ciphertext, err := tt.t.TransformToStorage(data, context) ciphertext, err := tt.t.TransformToStorage(ctx, data, dataCtx)
if err != nil { if err != nil {
t.Errorf("TransformToStorage error = %v", err) t.Errorf("TransformToStorage error = %v", err)
continue continue
} }
result, stale, err := tt.t.TransformFromStorage(ciphertext, context) result, stale, err := tt.t.TransformFromStorage(ctx, ciphertext, dataCtx)
if err != nil { if err != nil {
t.Errorf("TransformFromStorage error = %v", err) t.Errorf("TransformFromStorage error = %v", err)
continue continue

View File

@ -17,6 +17,7 @@ limitations under the License.
package value package value
import ( import (
"context"
"errors" "errors"
"strings" "strings"
"testing" "testing"
@ -102,8 +103,8 @@ func TestTotals(t *testing.T) {
for _, tt := range testCases { for _, tt := range testCases {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
tt.prefix.TransformToStorage([]byte("value"), nil) tt.prefix.TransformToStorage(context.Background(), []byte("value"), nil)
tt.prefix.TransformFromStorage([]byte("k8s:enc:kms:v1:value"), nil) tt.prefix.TransformFromStorage(context.Background(), []byte("k8s:enc:kms:v1:value"), nil)
defer transformerOperationsTotal.Reset() defer transformerOperationsTotal.Reset()
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil { if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -19,6 +19,7 @@ package value
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -45,9 +46,9 @@ type Transformer interface {
// TransformFromStorage may transform the provided data from its underlying storage representation or return an error. // TransformFromStorage may transform the provided data from its underlying storage representation or return an error.
// Stale is true if the object on disk is stale and a write to etcd should be issued, even if the contents of the object // Stale is true if the object on disk is stale and a write to etcd should be issued, even if the contents of the object
// have not changed. // have not changed.
TransformFromStorage(data []byte, context Context) (out []byte, stale bool, err error) TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, stale bool, err error)
// TransformToStorage may transform the provided data into the appropriate form in storage or return an error. // TransformToStorage may transform the provided data into the appropriate form in storage or return an error.
TransformToStorage(data []byte, context Context) (out []byte, err error) TransformToStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, err error)
} }
type identityTransformer struct{} type identityTransformer struct{}
@ -55,11 +56,11 @@ type identityTransformer struct{}
// IdentityTransformer performs no transformation of the provided data. // IdentityTransformer performs no transformation of the provided data.
var IdentityTransformer Transformer = identityTransformer{} var IdentityTransformer Transformer = identityTransformer{}
func (identityTransformer) TransformFromStorage(b []byte, ctx Context) ([]byte, bool, error) { func (identityTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) ([]byte, bool, error) {
return b, false, nil return data, false, nil
} }
func (identityTransformer) TransformToStorage(b []byte, ctx Context) ([]byte, error) { func (identityTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx Context) ([]byte, error) {
return b, nil return data, nil
} }
// DefaultContext is a simple implementation of Context for a slice of bytes. // DefaultContext is a simple implementation of Context for a slice of bytes.
@ -86,17 +87,17 @@ func (t *MutableTransformer) Set(transformer Transformer) {
t.lock.Unlock() t.lock.Unlock()
} }
func (t *MutableTransformer) TransformFromStorage(data []byte, context Context) (out []byte, stale bool, err error) { func (t *MutableTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, stale bool, err error) {
t.lock.RLock() t.lock.RLock()
transformer := t.transformer transformer := t.transformer
t.lock.RUnlock() t.lock.RUnlock()
return transformer.TransformFromStorage(data, context) return transformer.TransformFromStorage(ctx, data, dataCtx)
} }
func (t *MutableTransformer) TransformToStorage(data []byte, context Context) (out []byte, err error) { func (t *MutableTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, err error) {
t.lock.RLock() t.lock.RLock()
transformer := t.transformer transformer := t.transformer
t.lock.RUnlock() t.lock.RUnlock()
return transformer.TransformToStorage(data, context) return transformer.TransformToStorage(ctx, data, dataCtx)
} }
// PrefixTransformer holds a transformer interface and the prefix that the transformation is located under. // PrefixTransformer holds a transformer interface and the prefix that the transformation is located under.
@ -129,12 +130,12 @@ func NewPrefixTransformers(err error, transformers ...PrefixTransformer) Transfo
// TransformFromStorage finds the first transformer with a prefix matching the provided data and returns // TransformFromStorage finds the first transformer with a prefix matching the provided data and returns
// the result of transforming the value. It will always mark any transformation as stale that is not using // the result of transforming the value. It will always mark any transformation as stale that is not using
// the first transformer. // the first transformer.
func (t *prefixTransformers) TransformFromStorage(data []byte, context Context) ([]byte, bool, error) { func (t *prefixTransformers) TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) ([]byte, bool, error) {
start := time.Now() start := time.Now()
var errs []error var errs []error
for i, transformer := range t.transformers { for i, transformer := range t.transformers {
if bytes.HasPrefix(data, transformer.Prefix) { if bytes.HasPrefix(data, transformer.Prefix) {
result, stale, err := transformer.Transformer.TransformFromStorage(data[len(transformer.Prefix):], context) result, stale, err := transformer.Transformer.TransformFromStorage(ctx, data[len(transformer.Prefix):], dataCtx)
// To migrate away from encryption, user can specify an identity transformer higher up // To migrate away from encryption, user can specify an identity transformer higher up
// (in the config file) than the encryption transformer. In that scenario, the identity transformer needs to // (in the config file) than the encryption transformer. In that scenario, the identity transformer needs to
// identify (during reads from disk) whether the data being read is encrypted or not. If the data is encrypted, // identify (during reads from disk) whether the data being read is encrypted or not. If the data is encrypted,
@ -194,12 +195,12 @@ func (t *prefixTransformers) TransformFromStorage(data []byte, context Context)
} }
// TransformToStorage uses the first transformer and adds its prefix to the data. // TransformToStorage uses the first transformer and adds its prefix to the data.
func (t *prefixTransformers) TransformToStorage(data []byte, context Context) ([]byte, error) { func (t *prefixTransformers) TransformToStorage(ctx context.Context, data []byte, dataCtx Context) ([]byte, error) {
start := time.Now() start := time.Now()
transformer := t.transformers[0] transformer := t.transformers[0]
prefixedData := make([]byte, len(transformer.Prefix), len(data)+len(transformer.Prefix)) prefixedData := make([]byte, len(transformer.Prefix), len(data)+len(transformer.Prefix))
copy(prefixedData, transformer.Prefix) copy(prefixedData, transformer.Prefix)
result, err := transformer.Transformer.TransformToStorage(data, context) result, err := transformer.Transformer.TransformToStorage(ctx, data, dataCtx)
RecordTransformation("to_storage", string(transformer.Prefix), start, err) RecordTransformation("to_storage", string(transformer.Prefix), start, err)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -18,6 +18,7 @@ package value
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@ -33,13 +34,13 @@ type testTransformer struct {
receivedFrom, receivedTo []byte receivedFrom, receivedTo []byte
} }
func (t *testTransformer) TransformFromStorage(from []byte, context Context) (data []byte, stale bool, err error) { func (t *testTransformer) TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, stale bool, err error) {
t.receivedFrom = from t.receivedFrom = data
return t.from, t.stale, t.err return t.from, t.stale, t.err
} }
func (t *testTransformer) TransformToStorage(to []byte, context Context) (data []byte, err error) { func (t *testTransformer) TransformToStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, err error) {
t.receivedTo = to t.receivedTo = data
return t.to, t.err return t.to, t.err
} }
@ -68,7 +69,7 @@ func TestPrefixFrom(t *testing.T) {
{[]byte("stale:value"), []byte("value3"), true, nil, 3}, {[]byte("stale:value"), []byte("value3"), true, nil, 3},
} }
for i, test := range testCases { for i, test := range testCases {
got, stale, err := p.TransformFromStorage(test.input, nil) got, stale, err := p.TransformFromStorage(context.Background(), test.input, nil)
if err != test.err || stale != test.stale || !bytes.Equal(got, test.expect) { if err != test.err || stale != test.stale || !bytes.Equal(got, test.expect) {
t.Errorf("%d: unexpected out: %q %t %#v", i, string(got), stale, err) t.Errorf("%d: unexpected out: %q %t %#v", i, string(got), stale, err)
continue continue
@ -93,7 +94,7 @@ func TestPrefixTo(t *testing.T) {
} }
for i, test := range testCases { for i, test := range testCases {
p := NewPrefixTransformers(testErr, test.transformers...) p := NewPrefixTransformers(testErr, test.transformers...)
got, err := p.TransformToStorage([]byte("value"), nil) got, err := p.TransformToStorage(context.Background(), []byte("value"), nil)
if err != test.err || !bytes.Equal(got, test.expect) { if err != test.err || !bytes.Equal(got, test.expect) {
t.Errorf("%d: unexpected out: %q %#v", i, string(got), err) t.Errorf("%d: unexpected out: %q %#v", i, string(got), err)
continue continue
@ -183,7 +184,7 @@ func TestPrefixFromMetrics(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) { t.Run(tc.desc, func(t *testing.T) {
tc.prefix.TransformFromStorage(tc.input, nil) tc.prefix.TransformFromStorage(context.Background(), tc.input, nil)
defer transformerOperationsTotal.Reset() defer transformerOperationsTotal.Reset()
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil { if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil {
t.Fatal(err) t.Fatal(err)
@ -241,7 +242,7 @@ func TestPrefixToMetrics(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) { t.Run(tc.desc, func(t *testing.T) {
tc.prefix.TransformToStorage(tc.input, nil) tc.prefix.TransformToStorage(context.Background(), tc.input, nil)
defer transformerOperationsTotal.Reset() defer transformerOperationsTotal.Reset()
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil { if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -24,7 +24,6 @@ import (
"context" "context"
"crypto/aes" "crypto/aes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
@ -83,9 +82,10 @@ func (r envelope) plainTextPayload(secretETCDPath string) ([]byte, error) {
return nil, fmt.Errorf("failed to initialize AES Cipher: %v", err) return nil, fmt.Errorf("failed to initialize AES Cipher: %v", err)
} }
// etcd path of the key is used as the authenticated context - need to pass it to decrypt // etcd path of the key is used as the authenticated context - need to pass it to decrypt
ctx := value.DefaultContext([]byte(secretETCDPath)) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(secretETCDPath))
aescbcTransformer := aestransformer.NewCBCTransformer(block) aescbcTransformer := aestransformer.NewCBCTransformer(block)
plainSecret, _, err := aescbcTransformer.TransformFromStorage(r.cipherTextPayload(), ctx) plainSecret, _, err := aescbcTransformer.TransformFromStorage(ctx, r.cipherTextPayload(), dataCtx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to transform from storage via AESCBC, err: %v", err) return nil, fmt.Errorf("failed to transform from storage via AESCBC, err: %v", err)
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
package controlplane package controlplane
import ( import (
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"encoding/base64" "encoding/base64"
@ -131,7 +132,7 @@ func runBenchmark(b *testing.B, transformerConfig string) {
test.printMetrics() test.printMetrics()
} }
func unSealWithGCMTransformer(cipherText []byte, ctx value.Context, func unSealWithGCMTransformer(ctx context.Context, cipherText []byte, dataCtx value.Context,
transformerConfig apiserverconfigv1.ProviderConfiguration) ([]byte, error) { transformerConfig apiserverconfigv1.ProviderConfiguration) ([]byte, error) {
block, err := newAESCipher(transformerConfig.AESGCM.Keys[0].Secret) block, err := newAESCipher(transformerConfig.AESGCM.Keys[0].Secret)
@ -141,7 +142,7 @@ func unSealWithGCMTransformer(cipherText []byte, ctx value.Context,
gcmTransformer := aestransformer.NewGCMTransformer(block) gcmTransformer := aestransformer.NewGCMTransformer(block)
clearText, _, err := gcmTransformer.TransformFromStorage(cipherText, ctx) clearText, _, err := gcmTransformer.TransformFromStorage(ctx, cipherText, dataCtx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decypt secret: %v", err) return nil, fmt.Errorf("failed to decypt secret: %v", err)
} }
@ -149,7 +150,7 @@ func unSealWithGCMTransformer(cipherText []byte, ctx value.Context,
return clearText, nil return clearText, nil
} }
func unSealWithCBCTransformer(cipherText []byte, ctx value.Context, func unSealWithCBCTransformer(ctx context.Context, cipherText []byte, dataCtx value.Context,
transformerConfig apiserverconfigv1.ProviderConfiguration) ([]byte, error) { transformerConfig apiserverconfigv1.ProviderConfiguration) ([]byte, error) {
block, err := newAESCipher(transformerConfig.AESCBC.Keys[0].Secret) block, err := newAESCipher(transformerConfig.AESCBC.Keys[0].Secret)
@ -159,7 +160,7 @@ func unSealWithCBCTransformer(cipherText []byte, ctx value.Context,
cbcTransformer := aestransformer.NewCBCTransformer(block) cbcTransformer := aestransformer.NewCBCTransformer(block)
clearText, _, err := cbcTransformer.TransformFromStorage(cipherText, ctx) clearText, _, err := cbcTransformer.TransformFromStorage(ctx, cipherText, dataCtx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decypt secret: %v", err) return nil, fmt.Errorf("failed to decypt secret: %v", err)
} }

View File

@ -52,7 +52,7 @@ const (
metricsPrefix = "apiserver_storage_" metricsPrefix = "apiserver_storage_"
) )
type unSealSecret func(cipherText []byte, ctx value.Context, config apiserverconfigv1.ProviderConfiguration) ([]byte, error) type unSealSecret func(ctx context.Context, cipherText []byte, dataCtx value.Context, config apiserverconfigv1.ProviderConfiguration) ([]byte, error)
type transformTest struct { type transformTest struct {
logger kubeapiservertesting.Logger logger kubeapiservertesting.Logger
@ -115,14 +115,15 @@ func (e *transformTest) run(unSealSecretFunc unSealSecret, expectedEnvelopePrefi
} }
// etcd path of the key is used as the authenticated context - need to pass it to decrypt // etcd path of the key is used as the authenticated context - need to pass it to decrypt
ctx := value.DefaultContext([]byte(e.getETCDPath())) ctx := context.Background()
dataCtx := value.DefaultContext([]byte(e.getETCDPath()))
// Envelope header precedes the cipherTextPayload // Envelope header precedes the cipherTextPayload
sealedData := response.Kvs[0].Value[len(expectedEnvelopePrefix):] sealedData := response.Kvs[0].Value[len(expectedEnvelopePrefix):]
transformerConfig, err := e.getEncryptionConfig() transformerConfig, err := e.getEncryptionConfig()
if err != nil { if err != nil {
e.logger.Errorf("failed to parse transformer config: %v", err) e.logger.Errorf("failed to parse transformer config: %v", err)
} }
v, err := unSealSecretFunc(sealedData, ctx, *transformerConfig) v, err := unSealSecretFunc(ctx, sealedData, dataCtx, *transformerConfig)
if err != nil { if err != nil {
e.logger.Errorf("failed to unseal secret: %v", err) e.logger.Errorf("failed to unseal secret: %v", err)
return return