Merge pull request #116055 from aramase/aramase/f/kubernetes#111923

[KMSv2] log request metadata as part of read/write
This commit is contained in:
Kubernetes Prow Robot 2023-02-26 17:02:17 -08:00 committed by GitHub
commit 53b8170b97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 2 deletions

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/storage/value" "k8s.io/apiserver/pkg/storage/value"
kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1" kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics" "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
@ -107,8 +108,12 @@ func (t *envelopeTransformer) TransformFromStorage(ctx context.Context, data []b
if transformer == nil { if transformer == nil {
value.RecordCacheMiss() value.RecordCacheMiss()
requestInfo := getRequestInfoFromContext(ctx)
uid := string(uuid.NewUUID()) uid := string(uuid.NewUUID())
klog.V(6).InfoS("Decrypting content using envelope service", "uid", uid, "key", string(dataCtx.AuthenticatedData())) klog.V(6).InfoS("decrypting content using envelope service", "uid", uid, "key", string(dataCtx.AuthenticatedData()),
"group", requestInfo.APIGroup, "version", requestInfo.APIVersion, "resource", requestInfo.Resource, "subresource", requestInfo.Subresource,
"verb", requestInfo.Verb, "namespace", requestInfo.Namespace, "name", requestInfo.Name)
key, err := t.envelopeService.Decrypt(ctx, uid, &kmsservice.DecryptRequest{ key, err := t.envelopeService.Decrypt(ctx, uid, &kmsservice.DecryptRequest{
Ciphertext: encryptedObject.EncryptedDEK, Ciphertext: encryptedObject.EncryptedDEK,
KeyID: encryptedObject.KeyID, KeyID: encryptedObject.KeyID,
@ -151,8 +156,11 @@ func (t *envelopeTransformer) TransformToStorage(ctx context.Context, data []byt
return nil, err return nil, err
} }
requestInfo := getRequestInfoFromContext(ctx)
uid := string(uuid.NewUUID()) uid := string(uuid.NewUUID())
klog.V(6).InfoS("encrypting content using envelope service", "uid", uid, "key", string(dataCtx.AuthenticatedData())) klog.V(6).InfoS("encrypting content using envelope service", "uid", uid, "key", string(dataCtx.AuthenticatedData()),
"group", requestInfo.APIGroup, "version", requestInfo.APIVersion, "resource", requestInfo.Resource, "subresource", requestInfo.Subresource,
"verb", requestInfo.Verb, "namespace", requestInfo.Namespace, "name", requestInfo.Name)
resp, err := t.envelopeService.Encrypt(ctx, uid, newKey) resp, err := t.envelopeService.Encrypt(ctx, uid, newKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to encrypt DEK, error: %w", err) return nil, fmt.Errorf("failed to encrypt DEK, error: %w", err)
@ -301,3 +309,10 @@ func ValidateKeyID(keyID string) (ErrCodeKeyID, error) {
} }
return errKeyIDOKCode, nil return errKeyIDOKCode, nil
} }
func getRequestInfoFromContext(ctx context.Context) *genericapirequest.RequestInfo {
if reqInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
return reqInfo
}
return &genericapirequest.RequestInfo{}
}

View File

@ -21,19 +21,23 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"flag"
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/storage/value" "k8s.io/apiserver/pkg/storage/value"
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes" aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1" kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2alpha1"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics" "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
"k8s.io/component-base/metrics/legacyregistry" "k8s.io/component-base/metrics/legacyregistry"
"k8s.io/component-base/metrics/testutil" "k8s.io/component-base/metrics/testutil"
"k8s.io/klog/v2"
kmsservice "k8s.io/kms/pkg/service" kmsservice "k8s.io/kms/pkg/service"
testingclock "k8s.io/utils/clock/testing" testingclock "k8s.io/utils/clock/testing"
) )
@ -659,3 +663,90 @@ func TestEnvelopeMetrics(t *testing.T) {
}) })
} }
} }
func TestEnvelopeLogging(t *testing.T) {
klog.InitFlags(nil)
flag.Set("v", "6")
flag.Parse()
testCases := []struct {
desc string
ctx context.Context
wantLogs []string
}{
{
desc: "no request info in context",
ctx: testContext(t),
wantLogs: []string{
`"encrypting content using envelope service" uid="UID" key="0123456789" group="" version="" resource="" subresource="" verb="" namespace="" name=""`,
`"decrypting content using envelope service" uid="UID" key="0123456789" group="" version="" resource="" subresource="" verb="" namespace="" name=""`,
},
},
{
desc: "request info in context",
ctx: genericapirequest.WithRequestInfo(testContext(t), &genericapirequest.RequestInfo{
APIGroup: "awesome.bears.com",
APIVersion: "v1",
Resource: "pandas",
Subresource: "status",
Namespace: "kube-system",
Name: "panda",
Verb: "update",
}),
wantLogs: []string{
`"encrypting content using envelope service" uid="UID" key="0123456789" group="awesome.bears.com" version="v1" resource="pandas" subresource="status" verb="update" namespace="kube-system" name="panda"`,
`"decrypting content using envelope service" uid="UID" key="0123456789" group="awesome.bears.com" version="v1" resource="pandas" subresource="status" verb="update" namespace="kube-system" name="panda"`,
},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.desc, func(t *testing.T) {
var buf bytes.Buffer
klog.SetOutput(&buf)
klog.LogToStderr(false)
defer klog.LogToStderr(true)
envelopeService := newTestEnvelopeService()
fakeClock := testingclock.NewFakeClock(time.Now())
envelopeTransformer := newEnvelopeTransformerWithClock(envelopeService, testProviderName,
func(ctx context.Context) (string, error) {
return "1", nil
},
func(ctx context.Context) error {
return nil
},
aestransformer.NewGCMTransformer, 1*time.Second, fakeClock)
dataCtx := value.DefaultContext([]byte(testContextText))
originalText := []byte(testText)
transformedData, err := envelopeTransformer.TransformToStorage(tc.ctx, originalText, dataCtx)
if err != nil {
t.Fatalf("envelopeTransformer: error while transforming data to storage: %v", err)
}
// advance the clock to trigger cache to expire, so we make a decrypt call that will log
fakeClock.Step(2 * time.Second)
_, _, err = envelopeTransformer.TransformFromStorage(tc.ctx, transformedData, dataCtx)
if err != nil {
t.Fatalf("could not decrypt Envelope transformer's encrypted data even once: %v", err)
}
klog.Flush()
klog.SetOutput(&bytes.Buffer{}) // prevent further writes into buf
capturedOutput := buf.String()
// replace the uid with a constant to make the test output stable and assertable
capturedOutput = regexp.MustCompile(`uid="[^"]+"`).ReplaceAllString(capturedOutput, `uid="UID"`)
for _, wantLog := range tc.wantLogs {
if !strings.Contains(capturedOutput, wantLog) {
t.Errorf("expected log %q, got %q", wantLog, capturedOutput)
}
}
})
}
}