From fe53db0dbdc25c9b2f87adbd53f1ebe4b6c1169d Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 8 Nov 2023 15:38:11 -0800 Subject: [PATCH 1/3] authz: add benchmark for webhook authorizer Signed-off-by: Rita Zhang --- .../pkg/authorizer/webhook/webhook_v1_test.go | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go index 4cdfd1643dc..2baf2457ff0 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go @@ -782,6 +782,111 @@ func TestStructuredAuthzConfigFeatureEnablement(t *testing.T) { } } +func BenchmarkNoCELExpressionFeatureOff(b *testing.B) { + benchmarkWebhookAuthorizer(b, []apiserver.WebhookMatchCondition{}, false) +} + +func BenchmarkNoCELExpressionFeatureOn(b *testing.B) { + benchmarkWebhookAuthorizer(b, []apiserver.WebhookMatchCondition{}, true) +} +func BenchmarkWithOneCELExpressions(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice'", + }, + } + benchmarkWebhookAuthorizer(b, expressions, true) +} +func BenchmarkWithTwoCELExpressions(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice'", + }, + { + Expression: "request.uid == '1'", + }, + } + benchmarkWebhookAuthorizer(b, expressions, true) +} +func BenchmarkWithTwoComplexCELExpressions(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice'", + }, + { + Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies'", + }, + } + benchmarkWebhookAuthorizer(b, expressions, true) +} +func BenchmarkWithManyCELExpressions(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice'", + }, + { + Expression: "request.uid == '1'", + }, + { + Expression: "('group1' in request.groups)", + }, + { + Expression: "('key1' in request.extra)", + }, + { + Expression: "!('key2' in request.extra)", + }, + { + Expression: "('a' in request.extra['key1'])", + }, + { + Expression: "!('z' in request.extra['key1'])", + }, + { + Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies'", + }, + } + benchmarkWebhookAuthorizer(b, expressions, true) +} + +func benchmarkWebhookAuthorizer(b *testing.B, expressions []apiserver.WebhookMatchCondition, featureEnabled bool) { + attr := authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "alice", + UID: "1", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{"key1": {"a", "b", "c"}}, + }, + ResourceRequest: true, + Namespace: "kittensandponies", + Verb: "get", + } + service := new(mockV1Service) + service.statusCode = 200 + service.Allow() + s, err := NewV1TestServer(service, serverCert, serverKey, caCert) + if err != nil { + b.Fatal(err) + } + defer s.Close() + defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, featureEnabled)() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Create an authorizer with or without expressions to compile + wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions) + if err != nil { + b.Fatal(err) + } + // Call authorize may or may not require cel evaluations + _, _, err = wh.Authorize(context.Background(), attr) + if err != nil { + b.Fatal(err) + } + } + b.StopTimer() +} + // TestV1WebhookMatchConditions verifies cel expressions are compiled and evaluated correctly func TestV1WebhookMatchConditions(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, true)() From 11cdb8fd011a931d34506ade65e966f7c5208ae7 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 8 Nov 2023 16:37:10 -0800 Subject: [PATCH 2/3] split compile and eval Signed-off-by: Rita Zhang --- .../pkg/authorizer/webhook/webhook_v1_test.go | 78 ++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go index 2baf2457ff0..f86c856420e 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go @@ -783,11 +783,23 @@ func TestStructuredAuthzConfigFeatureEnablement(t *testing.T) { } func BenchmarkNoCELExpressionFeatureOff(b *testing.B) { - benchmarkWebhookAuthorizer(b, []apiserver.WebhookMatchCondition{}, false) + expressions := []apiserver.WebhookMatchCondition{} + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, false) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, false) + }) } func BenchmarkNoCELExpressionFeatureOn(b *testing.B) { - benchmarkWebhookAuthorizer(b, []apiserver.WebhookMatchCondition{}, true) + expressions := []apiserver.WebhookMatchCondition{} + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) } func BenchmarkWithOneCELExpressions(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ @@ -795,7 +807,12 @@ func BenchmarkWithOneCELExpressions(b *testing.B) { Expression: "request.user == 'alice'", }, } - benchmarkWebhookAuthorizer(b, expressions, true) + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) } func BenchmarkWithTwoCELExpressions(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ @@ -806,7 +823,12 @@ func BenchmarkWithTwoCELExpressions(b *testing.B) { Expression: "request.uid == '1'", }, } - benchmarkWebhookAuthorizer(b, expressions, true) + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) } func BenchmarkWithTwoComplexCELExpressions(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ @@ -817,7 +839,12 @@ func BenchmarkWithTwoComplexCELExpressions(b *testing.B) { Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies'", }, } - benchmarkWebhookAuthorizer(b, expressions, true) + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) } func BenchmarkWithManyCELExpressions(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ @@ -846,10 +873,37 @@ func BenchmarkWithManyCELExpressions(b *testing.B) { Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies'", }, } - benchmarkWebhookAuthorizer(b, expressions, true) + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) } -func benchmarkWebhookAuthorizer(b *testing.B, expressions []apiserver.WebhookMatchCondition, featureEnabled bool) { +func benchmarkNewWebhookAuthorizer(b *testing.B, expressions []apiserver.WebhookMatchCondition, featureEnabled bool) { + service := new(mockV1Service) + service.statusCode = 200 + service.Allow() + s, err := NewV1TestServer(service, serverCert, serverKey, caCert) + if err != nil { + b.Fatal(err) + } + defer s.Close() + defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, featureEnabled)() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Create an authorizer with or without expressions to compile + _, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions) + if err != nil { + b.Fatal(err) + } + } + b.StopTimer() +} + +func benchmarkWebhookAuthorize(b *testing.B, expressions []apiserver.WebhookMatchCondition, featureEnabled bool) { attr := authorizer.AttributesRecord{ User: &user.DefaultInfo{ Name: "alice", @@ -870,14 +924,14 @@ func benchmarkWebhookAuthorizer(b *testing.B, expressions []apiserver.WebhookMat } defer s.Close() defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, featureEnabled)() + // Create an authorizer with or without expressions to compile + wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions) + if err != nil { + b.Fatal(err) + } b.ResetTimer() for i := 0; i < b.N; i++ { - // Create an authorizer with or without expressions to compile - wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions) - if err != nil { - b.Fatal(err) - } // Call authorize may or may not require cel evaluations _, _, err = wh.Authorize(context.Background(), attr) if err != nil { From 7c5dfceff8a4de3387b48e941d098a3957de2870 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 13 Nov 2023 09:22:24 -0800 Subject: [PATCH 3/3] add false matchCondition benchmark Signed-off-by: Rita Zhang --- .../pkg/authorizer/webhook/webhook_v1_test.go | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go index f86c856420e..e57dd05099a 100644 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go +++ b/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook_v1_test.go @@ -814,6 +814,19 @@ func BenchmarkWithOneCELExpressions(b *testing.B) { benchmarkWebhookAuthorize(b, expressions, true) }) } +func BenchmarkWithOneCELExpressionsFalse(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice2'", + }, + } + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) +} func BenchmarkWithTwoCELExpressions(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ { @@ -830,13 +843,13 @@ func BenchmarkWithTwoCELExpressions(b *testing.B) { benchmarkWebhookAuthorize(b, expressions, true) }) } -func BenchmarkWithTwoComplexCELExpressions(b *testing.B) { +func BenchmarkWithTwoCELExpressionsFalse(b *testing.B) { expressions := []apiserver.WebhookMatchCondition{ { Expression: "request.user == 'alice'", }, { - Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies'", + Expression: "request.uid == '2'", }, } b.Run("compile", func(b *testing.B) { @@ -880,6 +893,40 @@ func BenchmarkWithManyCELExpressions(b *testing.B) { benchmarkWebhookAuthorize(b, expressions, true) }) } +func BenchmarkWithManyCELExpressionsFalse(b *testing.B) { + expressions := []apiserver.WebhookMatchCondition{ + { + Expression: "request.user == 'alice'", + }, + { + Expression: "request.uid == '1'", + }, + { + Expression: "('group1' in request.groups)", + }, + { + Expression: "('key1' in request.extra)", + }, + { + Expression: "!('key2' in request.extra)", + }, + { + Expression: "('a' in request.extra['key1'])", + }, + { + Expression: "!('z' in request.extra['key1'])", + }, + { + Expression: "has(request.resourceAttributes) && request.resourceAttributes.namespace == 'kittensandponies1'", + }, + } + b.Run("compile", func(b *testing.B) { + benchmarkNewWebhookAuthorizer(b, expressions, true) + }) + b.Run("authorize", func(b *testing.B) { + benchmarkWebhookAuthorize(b, expressions, true) + }) +} func benchmarkNewWebhookAuthorizer(b *testing.B, expressions []apiserver.WebhookMatchCondition, featureEnabled bool) { service := new(mockV1Service)