mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
kmsv2: add metrics for invalid_key_id_from_status_total
Signed-off-by: Rita Zhang <rita.z.zhang@gmail.com>
This commit is contained in:
parent
908803081f
commit
5292542b72
@ -278,9 +278,11 @@ func (h *kmsv2PluginProbe) check(ctx context.Context) error {
|
|||||||
return fmt.Errorf("failed to perform status section of the healthz check for KMS Provider %s, error: %w", h.name, err)
|
return fmt.Errorf("failed to perform status section of the healthz check for KMS Provider %s, error: %w", h.name, err)
|
||||||
}
|
}
|
||||||
// we coast on the last valid key ID that we have observed
|
// we coast on the last valid key ID that we have observed
|
||||||
if err := envelopekmsv2.ValidateKeyID(p.KeyID); err == nil {
|
if errCode, err := envelopekmsv2.ValidateKeyID(p.KeyID); err == nil {
|
||||||
h.keyID.Store(&p.KeyID)
|
h.keyID.Store(&p.KeyID)
|
||||||
metrics.RecordKeyIDFromStatus(h.name, p.KeyID)
|
metrics.RecordKeyIDFromStatus(h.name, p.KeyID)
|
||||||
|
} else {
|
||||||
|
metrics.RecordInvalidKeyIDFromStatus(h.name, string(errCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := isKMSv2ProviderHealthy(h.name, p); err != nil {
|
if err := isKMSv2ProviderHealthy(h.name, p); err != nil {
|
||||||
@ -312,7 +314,7 @@ func isKMSv2ProviderHealthy(name string, response *kmsservice.StatusResponse) er
|
|||||||
if response.Version != envelopekmsv2.KMSAPIVersion {
|
if response.Version != envelopekmsv2.KMSAPIVersion {
|
||||||
errs = append(errs, fmt.Errorf("expected KMSv2 API version %s, got %s", envelopekmsv2.KMSAPIVersion, response.Version))
|
errs = append(errs, fmt.Errorf("expected KMSv2 API version %s, got %s", envelopekmsv2.KMSAPIVersion, response.Version))
|
||||||
}
|
}
|
||||||
if err := envelopekmsv2.ValidateKeyID(response.KeyID); err != nil {
|
if _, err := envelopekmsv2.ValidateKeyID(response.KeyID); err != nil {
|
||||||
errs = append(errs, fmt.Errorf("expected KMSv2 KeyID to be set, got %s", response.KeyID))
|
errs = append(errs, fmt.Errorf("expected KMSv2 KeyID to be set, got %s", response.KeyID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -33,8 +34,12 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/apiserver/pkg/storage/value"
|
"k8s.io/apiserver/pkg/storage/value"
|
||||||
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
|
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
|
||||||
|
envelopekmsv2 "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2"
|
||||||
|
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/component-base/metrics/legacyregistry"
|
||||||
|
"k8s.io/component-base/metrics/testutil"
|
||||||
kmsservice "k8s.io/kms/service"
|
kmsservice "k8s.io/kms/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +48,10 @@ const (
|
|||||||
sampleContextText = "0123456789"
|
sampleContextText = "0123456789"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sampleInvalidKeyID = string(make([]byte, envelopekmsv2.KeyIDMaxSize+1))
|
||||||
|
)
|
||||||
|
|
||||||
// testEnvelopeService is a mock envelope service which can be used to simulate remote Envelope services
|
// testEnvelopeService is a mock envelope service which can be used to simulate remote Envelope services
|
||||||
// for testing of the envelope transformer with other transformers.
|
// for testing of the envelope transformer with other transformers.
|
||||||
type testEnvelopeService struct {
|
type testEnvelopeService struct {
|
||||||
@ -67,6 +76,7 @@ func (t *testEnvelopeService) Encrypt(data []byte) ([]byte, error) {
|
|||||||
// for testing of the envelope transformer with other transformers.
|
// for testing of the envelope transformer with other transformers.
|
||||||
type testKMSv2EnvelopeService struct {
|
type testKMSv2EnvelopeService struct {
|
||||||
err error
|
err error
|
||||||
|
keyID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testKMSv2EnvelopeService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
|
func (t *testKMSv2EnvelopeService) Decrypt(ctx context.Context, uid string, req *kmsservice.DecryptRequest) ([]byte, error) {
|
||||||
@ -82,7 +92,7 @@ func (t *testKMSv2EnvelopeService) Encrypt(ctx context.Context, uid string, data
|
|||||||
}
|
}
|
||||||
return &kmsservice.EncryptResponse{
|
return &kmsservice.EncryptResponse{
|
||||||
Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)),
|
Ciphertext: []byte(base64.StdEncoding.EncodeToString(data)),
|
||||||
KeyID: "1",
|
KeyID: t.keyID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +100,7 @@ func (t *testKMSv2EnvelopeService) Status(ctx context.Context) (*kmsservice.Stat
|
|||||||
if t.err != nil {
|
if t.err != nil {
|
||||||
return nil, t.err
|
return nil, t.err
|
||||||
}
|
}
|
||||||
return &kmsservice.StatusResponse{Healthz: "ok", KeyID: "1", Version: "v2alpha1"}, nil
|
return &kmsservice.StatusResponse{Healthz: "ok", KeyID: t.keyID, Version: "v2alpha1"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The factory method to create mock envelope service.
|
// The factory method to create mock envelope service.
|
||||||
@ -105,12 +115,17 @@ func newMockErrorEnvelopeService(endpoint string, timeout time.Duration) (envelo
|
|||||||
|
|
||||||
// The factory method to create mock envelope kmsv2 service.
|
// The factory method to create mock envelope kmsv2 service.
|
||||||
func newMockEnvelopeKMSv2Service(ctx context.Context, endpoint, providerName string, timeout time.Duration) (kmsservice.Service, error) {
|
func newMockEnvelopeKMSv2Service(ctx context.Context, endpoint, providerName string, timeout time.Duration) (kmsservice.Service, error) {
|
||||||
return &testKMSv2EnvelopeService{nil}, nil
|
return &testKMSv2EnvelopeService{nil, "1"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The factory method to create mock envelope kmsv2 service which always returns error.
|
// The factory method to create mock envelope kmsv2 service which always returns error.
|
||||||
func newMockErrorEnvelopeKMSv2Service(endpoint string, timeout time.Duration) (kmsservice.Service, error) {
|
func newMockErrorEnvelopeKMSv2Service(endpoint string, timeout time.Duration) (kmsservice.Service, error) {
|
||||||
return &testKMSv2EnvelopeService{errors.New("test")}, nil
|
return &testKMSv2EnvelopeService{errors.New("test"), "1"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The factory method to create mock envelope kmsv2 service that always returns invalid keyID.
|
||||||
|
func newMockInvalidKeyIDEnvelopeKMSv2Service(ctx context.Context, endpoint string, timeout time.Duration, keyID string) (kmsservice.Service, error) {
|
||||||
|
return &testKMSv2EnvelopeService{nil, keyID}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLegacyConfig(t *testing.T) {
|
func TestLegacyConfig(t *testing.T) {
|
||||||
@ -721,6 +736,84 @@ func TestKMSv2PluginHealthzTTL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKMSv2InvalidKeyID(t *testing.T) {
|
||||||
|
ctx := testContext(t)
|
||||||
|
invalidKeyIDService, _ := newMockInvalidKeyIDEnvelopeKMSv2Service(ctx, "unix:///tmp/testprovider.sock", 3*time.Second, "")
|
||||||
|
invalidLongKeyIDService, _ := newMockInvalidKeyIDEnvelopeKMSv2Service(ctx, "unix:///tmp/testprovider.sock", 3*time.Second, sampleInvalidKeyID)
|
||||||
|
service, _ := newMockInvalidKeyIDEnvelopeKMSv2Service(ctx, "unix:///tmp/testprovider.sock", 3*time.Second, "1")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
probe *kmsv2PluginProbe
|
||||||
|
metrics []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "kmsv2 provider returns an invalid empty keyID",
|
||||||
|
probe: &kmsv2PluginProbe{
|
||||||
|
name: "test",
|
||||||
|
ttl: kmsPluginHealthzNegativeTTL,
|
||||||
|
service: invalidKeyIDService,
|
||||||
|
l: &sync.Mutex{},
|
||||||
|
lastResponse: &kmsPluginHealthzResponse{},
|
||||||
|
},
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
|
||||||
|
# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
|
||||||
|
apiserver_envelope_encryption_invalid_key_id_from_status_total{error="empty",provider_name="test"} 1
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "kmsv2 provider returns a valid keyID",
|
||||||
|
probe: &kmsv2PluginProbe{
|
||||||
|
name: "test",
|
||||||
|
ttl: kmsPluginHealthzNegativeTTL,
|
||||||
|
service: service,
|
||||||
|
l: &sync.Mutex{},
|
||||||
|
lastResponse: &kmsPluginHealthzResponse{},
|
||||||
|
},
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
want: ``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "kmsv2 provider returns an invalid long keyID",
|
||||||
|
probe: &kmsv2PluginProbe{
|
||||||
|
name: "test",
|
||||||
|
ttl: kmsPluginHealthzNegativeTTL,
|
||||||
|
service: invalidLongKeyIDService,
|
||||||
|
l: &sync.Mutex{},
|
||||||
|
lastResponse: &kmsPluginHealthzResponse{},
|
||||||
|
},
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
want: `
|
||||||
|
# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
|
||||||
|
# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
|
||||||
|
apiserver_envelope_encryption_invalid_key_id_from_status_total{error="too_long",provider_name="test"} 1
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.InvalidKeyIDFromStatusTotal.Reset()
|
||||||
|
metrics.RegisterMetrics()
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
defer metrics.InvalidKeyIDFromStatusTotal.Reset()
|
||||||
|
_ = tt.probe.check(ctx)
|
||||||
|
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCBCKeyRotationWithOverlappingProviders(t *testing.T) {
|
func TestCBCKeyRotationWithOverlappingProviders(t *testing.T) {
|
||||||
testCBCKeyRotationWithProviders(
|
testCBCKeyRotationWithProviders(
|
||||||
t,
|
t,
|
||||||
|
@ -48,16 +48,21 @@ const (
|
|||||||
KMSAPIVersion = "v2alpha1"
|
KMSAPIVersion = "v2alpha1"
|
||||||
// annotationsMaxSize is the maximum size of the annotations.
|
// annotationsMaxSize is the maximum size of the annotations.
|
||||||
annotationsMaxSize = 32 * 1024 // 32 kB
|
annotationsMaxSize = 32 * 1024 // 32 kB
|
||||||
// keyIDMaxSize is the maximum size of the keyID.
|
// KeyIDMaxSize is the maximum size of the keyID.
|
||||||
keyIDMaxSize = 1 * 1024 // 1 kB
|
KeyIDMaxSize = 1 * 1024 // 1 kB
|
||||||
// encryptedDEKMaxSize is the maximum size of the encrypted DEK.
|
// encryptedDEKMaxSize is the maximum size of the encrypted DEK.
|
||||||
encryptedDEKMaxSize = 1 * 1024 // 1 kB
|
encryptedDEKMaxSize = 1 * 1024 // 1 kB
|
||||||
// cacheTTL is the default time-to-live for the cache entry.
|
// cacheTTL is the default time-to-live for the cache entry.
|
||||||
cacheTTL = 1 * time.Hour
|
cacheTTL = 1 * time.Hour
|
||||||
|
// error code
|
||||||
|
errKeyIDOKCode ErrCodeKeyID = "ok"
|
||||||
|
errKeyIDEmptyCode ErrCodeKeyID = "empty"
|
||||||
|
errKeyIDTooLongCode ErrCodeKeyID = "too_long"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeyIDGetterFunc func(context.Context) (keyID string, err error)
|
type KeyIDGetterFunc func(context.Context) (keyID string, err error)
|
||||||
type ProbeHealthzCheckFunc func(context.Context) (err error)
|
type ProbeHealthzCheckFunc func(context.Context) (err error)
|
||||||
|
type ErrCodeKeyID string
|
||||||
|
|
||||||
type envelopeTransformer struct {
|
type envelopeTransformer struct {
|
||||||
envelopeService kmsservice.Service
|
envelopeService kmsservice.Service
|
||||||
@ -247,7 +252,7 @@ func validateEncryptedObject(o *kmstypes.EncryptedObject) error {
|
|||||||
if err := validateEncryptedDEK(o.EncryptedDEK); err != nil {
|
if err := validateEncryptedDEK(o.EncryptedDEK); err != nil {
|
||||||
return fmt.Errorf("failed to validate encrypted DEK: %w", err)
|
return fmt.Errorf("failed to validate encrypted DEK: %w", err)
|
||||||
}
|
}
|
||||||
if err := ValidateKeyID(o.KeyID); err != nil {
|
if _, err := ValidateKeyID(o.KeyID); err != nil {
|
||||||
return fmt.Errorf("failed to validate key id: %w", err)
|
return fmt.Errorf("failed to validate key id: %w", err)
|
||||||
}
|
}
|
||||||
if err := validateAnnotations(o.Annotations); err != nil {
|
if err := validateAnnotations(o.Annotations); err != nil {
|
||||||
@ -290,12 +295,12 @@ func validateAnnotations(annotations map[string][]byte) error {
|
|||||||
// ValidateKeyID tests the following:
|
// ValidateKeyID tests the following:
|
||||||
// 1. The keyID is not empty.
|
// 1. The keyID is not empty.
|
||||||
// 2. The size of keyID is less than 1 kB.
|
// 2. The size of keyID is less than 1 kB.
|
||||||
func ValidateKeyID(keyID string) error {
|
func ValidateKeyID(keyID string) (ErrCodeKeyID, error) {
|
||||||
if len(keyID) == 0 {
|
if len(keyID) == 0 {
|
||||||
return fmt.Errorf("keyID is empty")
|
return errKeyIDEmptyCode, fmt.Errorf("keyID is empty")
|
||||||
}
|
}
|
||||||
if len(keyID) > keyIDMaxSize {
|
if len(keyID) > KeyIDMaxSize {
|
||||||
return fmt.Errorf("keyID is %d bytes, which exceeds the max size of %d", len(keyID), keyIDMaxSize)
|
return errKeyIDTooLongCode, fmt.Errorf("keyID is %d bytes, which exceeds the max size of %d", len(keyID), KeyIDMaxSize)
|
||||||
}
|
}
|
||||||
return nil
|
return errKeyIDOKCode, nil
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,10 @@ const (
|
|||||||
testCacheTTL = 10 * time.Second
|
testCacheTTL = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errCode = "empty"
|
||||||
|
)
|
||||||
|
|
||||||
// testEnvelopeService is a mock Envelope service which can be used to simulate remote Envelope services
|
// testEnvelopeService is a mock Envelope service which can be used to simulate remote Envelope services
|
||||||
// for testing of Envelope based encryption providers.
|
// for testing of Envelope based encryption providers.
|
||||||
type testEnvelopeService struct {
|
type testEnvelopeService struct {
|
||||||
@ -481,21 +485,25 @@ func TestValidateKeyID(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
keyID string
|
keyID string
|
||||||
expectedError string
|
expectedError string
|
||||||
|
expectedErrorCode string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid key ID",
|
name: "valid key ID",
|
||||||
keyID: "1234",
|
keyID: "1234",
|
||||||
expectedError: "",
|
expectedError: "",
|
||||||
|
expectedErrorCode: "ok",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty key ID",
|
name: "empty key ID",
|
||||||
keyID: "",
|
keyID: "",
|
||||||
expectedError: "keyID is empty",
|
expectedError: "keyID is empty",
|
||||||
|
expectedErrorCode: "empty",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "keyID size is greater than 1 kB",
|
name: "keyID size is greater than 1 kB",
|
||||||
keyID: strings.Repeat("a", 1024+1),
|
keyID: strings.Repeat("a", 1024+1),
|
||||||
expectedError: "which exceeds the max size of",
|
expectedError: "which exceeds the max size of",
|
||||||
|
expectedErrorCode: "too_long",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +511,7 @@ func TestValidateKeyID(t *testing.T) {
|
|||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
err := ValidateKeyID(tt.keyID)
|
errCode, err := ValidateKeyID(tt.keyID)
|
||||||
if tt.expectedError != "" {
|
if tt.expectedError != "" {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error %q, got nil", tt.expectedError)
|
t.Fatalf("expected error %q, got nil", tt.expectedError)
|
||||||
@ -516,6 +524,9 @@ func TestValidateKeyID(t *testing.T) {
|
|||||||
t.Fatalf("expected no error, got %q", err)
|
t.Fatalf("expected no error, got %q", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if tt.expectedErrorCode != string(errCode) {
|
||||||
|
t.Fatalf("expected %s errCode, got %s", tt.expectedErrorCode, string(errCode))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -576,8 +587,10 @@ func TestEnvelopeMetrics(t *testing.T) {
|
|||||||
func(ctx context.Context) (string, error) {
|
func(ctx context.Context) (string, error) {
|
||||||
return testKeyVersion, nil
|
return testKeyVersion, nil
|
||||||
},
|
},
|
||||||
|
// health probe check to ensure keyID freshness
|
||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
return fmt.Errorf("health check probe called when encryption keyID is different")
|
metrics.RecordInvalidKeyIDFromStatus(testProviderName, errCode)
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
aestransformer.NewGCMTransformer)
|
aestransformer.NewGCMTransformer)
|
||||||
|
|
||||||
@ -606,15 +619,34 @@ func TestEnvelopeMetrics(t *testing.T) {
|
|||||||
apiserver_envelope_encryption_key_id_hash_total{key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
|
apiserver_envelope_encryption_key_id_hash_total{key_id_hash="%s",provider_name="%s",transformation_type="%s"} 1
|
||||||
`, testKeyHash, testProviderName, metrics.FromStorageLabel, testKeyHash, testProviderName, metrics.ToStorageLabel),
|
`, testKeyHash, testProviderName, metrics.FromStorageLabel, testKeyHash, testProviderName, metrics.ToStorageLabel),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// keyVersionFromEncrypt is returned from kms v2 envelope service
|
||||||
|
// when it is different from the key ID returned from last status call
|
||||||
|
// it will trigger health probe check immediately to ensure keyID freshness
|
||||||
|
// during probe check above, it will call RecordInvalidKeyIDFromStatus
|
||||||
|
desc: "invalid KeyID From Status Total",
|
||||||
|
keyVersionFromEncrypt: "2",
|
||||||
|
prefix: value.NewPrefixTransformers(nil, kmsv2Transformer),
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
want: fmt.Sprintf(`
|
||||||
|
# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
|
||||||
|
# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
|
||||||
|
apiserver_envelope_encryption_invalid_key_id_from_status_total{error="%s",provider_name="%s"} 1
|
||||||
|
`, errCode, testProviderName),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics.DekCacheInterArrivals.Reset()
|
metrics.DekCacheInterArrivals.Reset()
|
||||||
metrics.KeyIDHashTotal.Reset()
|
metrics.KeyIDHashTotal.Reset()
|
||||||
|
metrics.InvalidKeyIDFromStatusTotal.Reset()
|
||||||
|
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
defer metrics.DekCacheInterArrivals.Reset()
|
defer metrics.DekCacheInterArrivals.Reset()
|
||||||
defer metrics.KeyIDHashTotal.Reset()
|
defer metrics.KeyIDHashTotal.Reset()
|
||||||
|
defer metrics.InvalidKeyIDFromStatusTotal.Reset()
|
||||||
ctx := testContext(t)
|
ctx := testContext(t)
|
||||||
envelopeService.keyVersion = tt.keyVersionFromEncrypt
|
envelopeService.keyVersion = tt.keyVersionFromEncrypt
|
||||||
transformedData, err := tt.prefix.TransformToStorage(ctx, []byte(testText), dataCtx)
|
transformedData, err := tt.prefix.TransformToStorage(ctx, []byte(testText), dataCtx)
|
||||||
|
@ -142,6 +142,17 @@ var (
|
|||||||
},
|
},
|
||||||
[]string{"provider_name", "key_id_hash"},
|
[]string{"provider_name", "key_id_hash"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
InvalidKeyIDFromStatusTotal = metrics.NewCounterVec(
|
||||||
|
&metrics.CounterOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "invalid_key_id_from_status_total",
|
||||||
|
Help: "Number of times an invalid keyID is returned by the Status RPC call split by error.",
|
||||||
|
StabilityLevel: metrics.ALPHA,
|
||||||
|
},
|
||||||
|
[]string{"provider_name", "error"},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
var registerMetricsFunc sync.Once
|
var registerMetricsFunc sync.Once
|
||||||
@ -186,6 +197,7 @@ func RegisterMetrics() {
|
|||||||
legacyregistry.MustRegister(KeyIDHashTotal)
|
legacyregistry.MustRegister(KeyIDHashTotal)
|
||||||
legacyregistry.MustRegister(KeyIDHashLastTimestampSeconds)
|
legacyregistry.MustRegister(KeyIDHashLastTimestampSeconds)
|
||||||
legacyregistry.MustRegister(KeyIDHashStatusLastTimestampSeconds)
|
legacyregistry.MustRegister(KeyIDHashStatusLastTimestampSeconds)
|
||||||
|
legacyregistry.MustRegister(InvalidKeyIDFromStatusTotal)
|
||||||
legacyregistry.MustRegister(KMSOperationsLatencyMetric)
|
legacyregistry.MustRegister(KMSOperationsLatencyMetric)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -209,6 +221,10 @@ func RecordKeyIDFromStatus(providerName, keyID string) {
|
|||||||
KeyIDHashStatusLastTimestampSeconds.WithLabelValues(providerName, keyIDHash).SetToCurrentTime()
|
KeyIDHashStatusLastTimestampSeconds.WithLabelValues(providerName, keyIDHash).SetToCurrentTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RecordInvalidKeyIDFromStatus(providerName, errCode string) {
|
||||||
|
InvalidKeyIDFromStatusTotal.WithLabelValues(providerName, errCode).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
func RecordArrival(transformationType string, start time.Time) {
|
func RecordArrival(transformationType string, start time.Time) {
|
||||||
switch transformationType {
|
switch transformationType {
|
||||||
case FromStorageLabel:
|
case FromStorageLabel:
|
||||||
|
@ -38,6 +38,10 @@ const (
|
|||||||
testProviderNameForMetric = "providerName"
|
testProviderNameForMetric = "providerName"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errCode = "empty"
|
||||||
|
)
|
||||||
|
|
||||||
func TestRecordKMSOperationLatency(t *testing.T) {
|
func TestRecordKMSOperationLatency(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@ -185,7 +189,7 @@ func TestRecordKMSOperationLatency(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvelopeMetrics_Serial(t *testing.T) {
|
func TestRecordKeyID_Serial(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
keyID string
|
keyID string
|
||||||
@ -287,7 +291,7 @@ func TestEnvelopeMetrics_Serial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvelopeMetricsLRUKey(t *testing.T) {
|
func TestRecordKeyIDLRUKey(t *testing.T) {
|
||||||
RegisterMetrics()
|
RegisterMetrics()
|
||||||
|
|
||||||
cacheSize = 3
|
cacheSize = 3
|
||||||
@ -332,3 +336,62 @@ func TestEnvelopeMetricsLRUKey(t *testing.T) {
|
|||||||
t.Fatalf("expected total valid metrics to be the same as cacheSize %d, got %d", cacheSize, validMetrics)
|
t.Fatalf("expected total valid metrics to be the same as cacheSize %d, got %d", cacheSize, validMetrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecordInvalidKeyIDFromStatus(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
count int
|
||||||
|
metrics []string
|
||||||
|
providerName string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "invalid KeyID From Status Total 3",
|
||||||
|
count: 3,
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
providerName: testProviderNameForMetric,
|
||||||
|
want: fmt.Sprintf(`
|
||||||
|
# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
|
||||||
|
# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
|
||||||
|
apiserver_envelope_encryption_invalid_key_id_from_status_total{error="%s",provider_name="%s"} %d
|
||||||
|
`, errCode, testProviderNameForMetric, 3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid KeyID From Status Total 10",
|
||||||
|
count: 10,
|
||||||
|
metrics: []string{
|
||||||
|
"apiserver_envelope_encryption_invalid_key_id_from_status_total",
|
||||||
|
},
|
||||||
|
providerName: testProviderNameForMetric,
|
||||||
|
want: fmt.Sprintf(`
|
||||||
|
# HELP apiserver_envelope_encryption_invalid_key_id_from_status_total [ALPHA] Number of times an invalid keyID is returned by the Status RPC call split by error.
|
||||||
|
# TYPE apiserver_envelope_encryption_invalid_key_id_from_status_total counter
|
||||||
|
apiserver_envelope_encryption_invalid_key_id_from_status_total{error="%s",provider_name="%s"} %d
|
||||||
|
`, errCode, testProviderNameForMetric, 10),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidKeyIDFromStatusTotal.Reset()
|
||||||
|
RegisterMetrics()
|
||||||
|
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
defer InvalidKeyIDFromStatusTotal.Reset()
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < tt.count; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
RecordInvalidKeyIDFromStatus(tt.providerName, errCode)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), tt.metrics...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user