Skip to content

Commit

Permalink
kmsv2: reload metrics bug fix backport
Browse files Browse the repository at this point in the history
Signed-off-by: Rita Zhang <rita.z.zhang@gmail.com>
  • Loading branch information
ritazh committed Sep 10, 2023
1 parent 1467b58 commit 2480fce
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
Expand Up @@ -43,12 +43,13 @@ import (
"k8s.io/apiserver/pkg/apis/config/validation"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/apiserver/pkg/server/options/encryptionconfig/metrics"
storagevalue "k8s.io/apiserver/pkg/storage/value"
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope"
envelopekmsv2 "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2"
kmstypes "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/v2"
"k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
envelopemetrics "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/metrics"
"k8s.io/apiserver/pkg/storage/value/encrypt/identity"
"k8s.io/apiserver/pkg/storage/value/encrypt/secretbox"
utilfeature "k8s.io/apiserver/pkg/util/feature"
Expand Down Expand Up @@ -104,6 +105,12 @@ const (
kmsReloadHealthCheckName = "kms-providers"
)

func init() {
metrics.RegisterMetrics()
storagevalue.RegisterMetrics()
envelopemetrics.RegisterMetrics()
}

type kmsPluginHealthzResponse struct {
err error
received time.Time
Expand Down Expand Up @@ -445,10 +452,10 @@ func (h *kmsv2PluginProbe) isKMSv2ProviderHealthyAndMaybeRotateDEK(ctx context.C
}

if errCode, err := envelopekmsv2.ValidateKeyID(response.KeyID); err != nil {
metrics.RecordInvalidKeyIDFromStatus(h.name, string(errCode))
envelopemetrics.RecordInvalidKeyIDFromStatus(h.name, string(errCode))
errs = append(errs, fmt.Errorf("got invalid KMSv2 KeyID hash %q: %w", envelopekmsv2.GetHashIfNotEmpty(response.KeyID), err))
} else {
metrics.RecordKeyIDFromStatus(h.name, response.KeyID)
envelopemetrics.RecordKeyIDFromStatus(h.name, response.KeyID)
// unconditionally append as we filter out nil errors below
errs = append(errs, h.rotateDEKOnKeyIDChange(ctx, response.KeyID, string(uuid.NewUUID())))
}
Expand Down
Expand Up @@ -29,21 +29,26 @@ import (
"math/rand"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"

"github.com/google/go-cmp/cmp"
clientv3 "go.etcd.io/etcd/client/v3"
"golang.org/x/crypto/cryptobyte"

"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/storage/value"
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
mock "k8s.io/apiserver/pkg/storage/value/encrypt/envelope/testing/v1beta1"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
featuregatetesting "k8s.io/component-base/featuregate/testing"
kmsapi "k8s.io/kms/apis/v1beta1"
"k8s.io/kubernetes/test/integration"
Expand Down Expand Up @@ -319,6 +324,26 @@ resources:
test.cleanUp()
}
}()
ctx := testContext(t)
// the global metrics registry persists across test runs - reset it here so we can make assertions
copyConfig := rest.CopyConfig(test.kubeAPIServer.ClientConfig)
copyConfig.GroupVersion = &schema.GroupVersion{}
copyConfig.NegotiatedSerializer = unstructuredscheme.NewUnstructuredNegotiatedSerializer()
rc, err := rest.RESTClientFor(copyConfig)
if err != nil {
t.Fatal(err)
}
if err := rc.Delete().AbsPath("/metrics").Do(ctx).Error(); err != nil {
t.Fatal(err)
}

// assert that the metrics we collect during the test run match expectations
// NOTE: 2 successful automatic reload resulted from 2 config file updates
wantMetricStrings := []string{
`apiserver_encryption_config_controller_automatic_reload_failures_total 0`,
`apiserver_encryption_config_controller_automatic_reload_last_timestamp_seconds{status="success"} FP`,
`apiserver_encryption_config_controller_automatic_reload_success_total 2`,
}

test.secret, err = test.createSecret(testSecret, testNamespace)
if err != nil {
Expand Down Expand Up @@ -378,7 +403,6 @@ resources:

// run storage migration
// get secrets
ctx := testContext(t)
secretsList, err := test.restClient.CoreV1().Secrets("").List(
ctx,
metav1.ListOptions{},
Expand Down Expand Up @@ -522,6 +546,33 @@ resources:
if _, err = test.restClient.CoreV1().ConfigMaps("").List(ctx, metav1.ListOptions{}); err != nil {
t.Fatalf("failed to list configmaps, err: %v", err)
}
// recreate rest client with the new transformTest
copyConfig = rest.CopyConfig(test.kubeAPIServer.ClientConfig)
copyConfig.GroupVersion = &schema.GroupVersion{}
copyConfig.NegotiatedSerializer = unstructuredscheme.NewUnstructuredNegotiatedSerializer()
rc, err = rest.RESTClientFor(copyConfig)
if err != nil {
t.Fatal(err)
}
defer func() {
body, err := rc.Get().AbsPath("/metrics").DoRaw(ctx)
if err != nil {
t.Fatal(err)
}
var gotMetricStrings []string
trimFP := regexp.MustCompile(`(.*)(} \d+\.\d+.*)`)
for _, line := range strings.Split(string(body), "\n") {
if strings.HasPrefix(line, "apiserver_encryption_config_controller_") {
if strings.Contains(line, "_seconds") {
line = trimFP.ReplaceAllString(line, `$1`) + "} FP" // ignore floating point metric values
}
gotMetricStrings = append(gotMetricStrings, line)
}
}
if diff := cmp.Diff(wantMetricStrings, gotMetricStrings); diff != "" {
t.Errorf("unexpected metrics diff (-want +got): %s", diff)
}
}()
}

func TestEncryptAll(t *testing.T) {
Expand Down

0 comments on commit 2480fce

Please sign in to comment.