Skip to content

Commit 377d5c3

Browse files
authored
Refactor: Improve OPA authorization filter benchmarks (#3391)
- Move benchmarks to a separate file - Add parallel execution to benchmarks - Includ benchmarks for minimal policy with/without decision logging - Add reference benchmark running with a policy bundle Signed-off-by: Farasath Ahamed <[email protected]>
1 parent 28e76bf commit 377d5c3

File tree

8 files changed

+570
-242
lines changed

8 files changed

+570
-242
lines changed

filters/openpolicyagent/opaauthorizerequest/benchmark_test.go

+450
Large diffs are not rendered by default.

filters/openpolicyagent/opaauthorizerequest/opaauthorizerequest_test.go

+6-242
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,20 @@ package opaauthorizerequest
22

33
import (
44
"fmt"
5+
opasdktest "github.com/open-policy-agent/opa/sdk/test"
6+
"github.com/stretchr/testify/assert"
57
"github.com/stretchr/testify/require"
8+
"github.com/zalando/skipper/eskip"
9+
"github.com/zalando/skipper/filters"
610
"github.com/zalando/skipper/filters/builtin"
11+
"github.com/zalando/skipper/proxy/proxytest"
12+
"github.com/zalando/skipper/tracing/tracingtest"
713
"io"
8-
"log"
914
"net/http"
1015
"net/http/httptest"
11-
"net/url"
12-
"os"
1316
"strings"
1417
"testing"
15-
"time"
16-
17-
"github.com/golang-jwt/jwt/v4"
18-
opasdktest "github.com/open-policy-agent/opa/sdk/test"
19-
"github.com/stretchr/testify/assert"
20-
"github.com/zalando/skipper/eskip"
21-
"github.com/zalando/skipper/filters"
22-
"github.com/zalando/skipper/metrics/metricstest"
23-
"github.com/zalando/skipper/proxy/proxytest"
24-
"github.com/zalando/skipper/tracing/tracingtest"
2518

26-
"github.com/zalando/skipper/filters/filtertest"
2719
"github.com/zalando/skipper/filters/openpolicyagent"
2820
)
2921

@@ -791,231 +783,3 @@ func isHeadersAbsent(t *testing.T, unwantedHeaders http.Header, headers http.Hea
791783
}
792784
return true
793785
}
794-
795-
const (
796-
tokenExp = 2 * time.Hour
797-
798-
certPath = "../../../skptesting/cert.pem"
799-
keyPath = "../../../skptesting/key.pem"
800-
)
801-
802-
func BenchmarkAuthorizeRequest(b *testing.B) {
803-
b.Run("authorize-request-minimal", func(b *testing.B) {
804-
opaControlPlane := opasdktest.MustNewServer(
805-
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
806-
"main.rego": `
807-
package envoy.authz
808-
809-
default allow = false
810-
811-
allow {
812-
input.parsed_path = [ "allow" ]
813-
}
814-
`,
815-
}),
816-
)
817-
818-
f, err := createOpaFilter(opaControlPlane)
819-
assert.NoError(b, err)
820-
821-
url, err := url.Parse("http://opa-authorized.test/somepath")
822-
assert.NoError(b, err)
823-
824-
ctx := &filtertest.Context{
825-
FStateBag: map[string]interface{}{},
826-
FResponse: &http.Response{},
827-
FRequest: &http.Request{
828-
Header: map[string][]string{
829-
"Authorization": {"Bearer FOOBAR"},
830-
},
831-
URL: url,
832-
},
833-
FMetrics: &metricstest.MockMetrics{},
834-
}
835-
836-
b.ResetTimer()
837-
b.ReportAllocs()
838-
839-
for i := 0; i < b.N; i++ {
840-
f.Request(ctx)
841-
}
842-
})
843-
844-
b.Run("authorize-request-with-body", func(b *testing.B) {
845-
opaControlPlane := opasdktest.MustNewServer(
846-
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
847-
"main.rego": `
848-
package envoy.authz
849-
850-
import rego.v1
851-
852-
default allow = false
853-
854-
allow if {
855-
endswith(input.parsed_body.email, "@zalando.de")
856-
}
857-
`,
858-
}),
859-
)
860-
861-
f, err := createBodyBasedOpaFilter(opaControlPlane)
862-
assert.NoError(b, err)
863-
864-
url, err := url.Parse("http://opa-authorized.test/somepath")
865-
assert.NoError(b, err)
866-
867-
body := `{"email": "[email protected]"}`
868-
ctx := &filtertest.Context{
869-
FStateBag: map[string]interface{}{},
870-
FResponse: &http.Response{},
871-
FRequest: &http.Request{
872-
Method: "POST",
873-
Header: map[string][]string{
874-
"Authorization": {"Bearer FOOBAR"},
875-
"Content-Type": {"application/json"},
876-
},
877-
URL: url,
878-
Body: io.NopCloser(strings.NewReader(body)),
879-
ContentLength: int64(len(body)),
880-
},
881-
FMetrics: &metricstest.MockMetrics{},
882-
}
883-
884-
b.ResetTimer()
885-
b.ReportAllocs()
886-
887-
for i := 0; i < b.N; i++ {
888-
f.Request(ctx)
889-
}
890-
})
891-
892-
b.Run("authorize-request-jwt-validation", func(b *testing.B) {
893-
894-
publicKey, err := os.ReadFile(certPath)
895-
if err != nil {
896-
log.Fatalf("Failed to read public key: %v", err)
897-
}
898-
899-
opaControlPlane := opasdktest.MustNewServer(
900-
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
901-
"main.rego": fmt.Sprintf(`
902-
package envoy.authz
903-
904-
import future.keywords.if
905-
906-
default allow = false
907-
908-
public_key_cert := %q
909-
910-
bearer_token := t if {
911-
v := input.attributes.request.http.headers.authorization
912-
startswith(v, "Bearer ")
913-
t := substring(v, count("Bearer "), -1)
914-
}
915-
916-
allow if {
917-
[valid, _, payload] := io.jwt.decode_verify(bearer_token, {
918-
"cert": public_key_cert,
919-
"aud": "nqz3xhorr5"
920-
})
921-
922-
valid
923-
924-
payload.sub == "5974934733"
925-
}
926-
`, publicKey),
927-
}),
928-
)
929-
930-
f, err := createOpaFilter(opaControlPlane)
931-
assert.NoError(b, err)
932-
933-
url, err := url.Parse("http://opa-authorized.test/somepath")
934-
assert.NoError(b, err)
935-
936-
claims := jwt.MapClaims{
937-
"iss": "https://some.identity.acme.com",
938-
"sub": "5974934733",
939-
"aud": "nqz3xhorr5",
940-
"iat": time.Now().Add(-time.Minute).UTC().Unix(),
941-
"exp": time.Now().Add(tokenExp).UTC().Unix(),
942-
"email": "[email protected]",
943-
}
944-
945-
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
946-
947-
privKey, err := os.ReadFile(keyPath)
948-
if err != nil {
949-
log.Fatalf("Failed to read priv key: %v", err)
950-
}
951-
952-
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privKey))
953-
if err != nil {
954-
log.Fatalf("Failed to parse RSA PEM: %v", err)
955-
}
956-
957-
// Sign and get the complete encoded token as a string using the secret
958-
signedToken, err := token.SignedString(key)
959-
if err != nil {
960-
log.Fatalf("Failed to sign token: %v", err)
961-
}
962-
963-
ctx := &filtertest.Context{
964-
FStateBag: map[string]interface{}{},
965-
FResponse: &http.Response{},
966-
FRequest: &http.Request{
967-
Header: map[string][]string{
968-
"Authorization": {fmt.Sprintf("Bearer %s", signedToken)},
969-
},
970-
URL: url,
971-
},
972-
FMetrics: &metricstest.MockMetrics{},
973-
}
974-
975-
b.ResetTimer()
976-
b.ReportAllocs()
977-
978-
for i := 0; i < b.N; i++ {
979-
f.Request(ctx)
980-
assert.False(b, ctx.FServed)
981-
}
982-
})
983-
}
984-
985-
func createOpaFilter(opaControlPlane *opasdktest.Server) (filters.Filter, error) {
986-
config := generateConfig(opaControlPlane, "envoy/authz/allow")
987-
opaFactory := openpolicyagent.NewOpenPolicyAgentRegistry()
988-
spec := NewOpaAuthorizeRequestSpec(opaFactory, openpolicyagent.WithConfigTemplate(config))
989-
return spec.CreateFilter([]interface{}{"somebundle.tar.gz"})
990-
}
991-
992-
func createBodyBasedOpaFilter(opaControlPlane *opasdktest.Server) (filters.Filter, error) {
993-
config := generateConfig(opaControlPlane, "envoy/authz/allow")
994-
opaFactory := openpolicyagent.NewOpenPolicyAgentRegistry()
995-
spec := NewOpaAuthorizeRequestWithBodySpec(opaFactory, openpolicyagent.WithConfigTemplate(config))
996-
return spec.CreateFilter([]interface{}{"somebundle.tar.gz"})
997-
}
998-
999-
func generateConfig(opaControlPlane *opasdktest.Server, path string) []byte {
1000-
return []byte(fmt.Sprintf(`{
1001-
"services": {
1002-
"test": {
1003-
"url": %q
1004-
}
1005-
},
1006-
"bundles": {
1007-
"test": {
1008-
"resource": "/bundles/{{ .bundlename }}"
1009-
}
1010-
},
1011-
"labels": {
1012-
"environment": "test"
1013-
},
1014-
"plugins": {
1015-
"envoy_ext_authz_grpc": {
1016-
"path": %q,
1017-
"dry-run": false
1018-
}
1019-
}
1020-
}`, opaControlPlane.URL(), path))
1021-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDkzCCAnugAwIBAgIJAKjOTehGhMMYMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
3+
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
4+
aWRnaXRzIFB0eSBMdGQxGTAXBgNVBAMMEGxvY2FsZXhhbXBsZS5vcmcwHhcNMTkw
5+
MTE4MTYzNzI3WhcNMTkwMTI3MTYzNzI3WjBgMQswCQYDVQQGEwJBVTETMBEGA1UE
6+
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
7+
MRkwFwYDVQQDDBBsb2NhbGV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
8+
AQ8AMIIBCgKCAQEA42H1BFt2/ZZuqNCl+VVG99sfRO4r5FXcJccUmHajLDIYdudA
9+
jWLXMG9jhc+HfOLIKYWd5NGAJKAHVzNVbGgEDGG8icy83ShTkmMISEnyYqqDH6wf
10+
qkxMwZ6hYQnJUveRPOejcfGVUNh8XNu7WC228qyWd+0JaVVxVU7F3ks2q/eRxKQM
11+
fOZYh4gY5d4gt/JbAU8VNgWo9jCEuK+026CkpTyGVYa2iCLjOiKjjnKpixgSXhUU
12+
kQsHITp2yTULHC9Wqn92VLCi1al/CCtpZExwO+jq5sihCCfE/Erq+wesnC+vFalE
13+
BmV7K9qe+k0SGyM1O7yFLClCfbuuIEwguhCNVwIDAQABo1AwTjAdBgNVHQ4EFgQU
14+
gJB4kmWERbmiOj3FQULuMtowTpswHwYDVR0jBBgwFoAUgJB4kmWERbmiOj3FQULu
15+
MtowTpswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAk2FmuKemxfNF
16+
b0Aeoph/KEXekzM2YSsMjAlXiIt7SidNEy5XWLE30RKY1TXpYg3kB5qihLT7S0VB
17+
UVV3vQwvc8htnuAJB+tukBcQzIFPHWFxdv69j+iRTVjf/zPXTS4CeoHujAVRlFuc
18+
wbEumkxyT/MX4XfhBHPjhe7fy5MMULESAmWPHrOm5HO+HUVYt8OzBpYG2o3izJ+I
19+
NFy9rAjfgbakvv0D2XnNl01n9gycLag6m6UVnXyvisiiNmFhobYlryM/O8T4uEo1
20+
rU62hJKI6iN3S9wtRDvNk6PwXIwJ0kGJkjFXR/K84ViN6DaQULwZDWyaytfvJKtY
21+
2IZhpkvX0Q==
22+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDjYfUEW3b9lm6o
3+
0KX5VUb32x9E7ivkVdwlxxSYdqMsMhh250CNYtcwb2OFz4d84sgphZ3k0YAkoAdX
4+
M1VsaAQMYbyJzLzdKFOSYwhISfJiqoMfrB+qTEzBnqFhCclS95E856Nx8ZVQ2Hxc
5+
27tYLbbyrJZ37QlpVXFVTsXeSzar95HEpAx85liHiBjl3iC38lsBTxU2Baj2MIS4
6+
r7TboKSlPIZVhraIIuM6IqOOcqmLGBJeFRSRCwchOnbJNQscL1aqf3ZUsKLVqX8I
7+
K2lkTHA76OrmyKEIJ8T8Sur7B6ycL68VqUQGZXsr2p76TRIbIzU7vIUsKUJ9u64g
8+
TCC6EI1XAgMBAAECggEARNs3HVitUeGqJQj6GeUPFqOOdotBU2YEwpPk0r6qbwnE
9+
is1AqRATZiF1G+JafyEVyC0kQVSH349uaaOr7KYbA7zdIUWUs8wwcpX2vh1WfzZv
10+
erne5O0yGTf2WrJh+vPpUW47+pdTxiWok14e/3bofdhxwGNRhEpRhanTFZvlNHGz
11+
0p9SY8AyBbpNFEl0TkwLP+hcyKqz91jgOnE98MnUYKh6ZG3CY6L3Ca8A4BE3RuOw
12+
gXdua7T2hsyMzYdv9aIdW+BMk2Fa3VFpvnm6Sh2Uje1KBIOuWTgSumcSLbaPVHKs
13+
ZQthyOtt7ueJ46E2hdgoCP0R8Rbyqdy6bhUmCpFrEQKBgQD3A6+O0BhjJovKka5L
14+
u33fphLtwnABHnH+QqPeUAy8yN2yiy0ZxL19WN0doAbF56xErTHYq+UriHgHfYAv
15+
lYtmtocwkl782yiUscIVfA9sUovzG5fsVP9fRUC5xWo+Ak59NX6lr5QXoBltanON
16+
YMAbwhz5q1NTAt9c9FPGjERLswKBgQDrp3OCqobVpcK2haLPFNsj+huqKPSp9STS
17+
hjqUjUiPAQTuZyb8H3Q5NtHB5j354BzkqaOXFCKaqiJIKHz794IuDOvou7cjF+J4
18+
4GOxnCJOFsvtvBoYWTFF0lz4++tvBtPLYZnnN2fCF/olk4ZQ2/FAapF/m6ehTLBa
19+
N3S52AzVzQKBgH7WUatPh3ZCML3PmGQi3judF1Mm6ERq0bXxmhtpl2DI863ecUYu
20+
E+7tVn0D0vaEQ5zwIgxUF9UGujt+YfgNHgub5kc2obfNAUV5EWPe1DyXFm262YPt
21+
EURmVxoNGMTGgm8grOt/ANgwyV25r6QE7iBSyHYbVynk67TbcLkfBWKpAoGBAKGw
22+
kIIcTU20YYho4w/hSIdD6c10MoOW73//l5wr4Jg2Y9LMNiSR1GYZZgz71JRpoImI
23+
l/VmXGPwznriRPeBmPHN7eQPQJY0ojC8DctkzOj1nVDuWp1QPY2hzCcOezj/3zxS
24+
KI5MJsY3O2yi72r1rm+7bz+2Zms3Ol18ZXvKcOwVAoGBALYNfh4TYHRMLB8HDNZm
25+
a7I1cq0N6ZPgvTzS/rf1qM0EabK8gvxDHzxAdnc1NLGx7JLd4svbATW7p5WjLYeu
26+
0hh/DPy2LbTYLnhOn4a5Ncm+xKYfsvw4IQg98chxemQrGkwXSDsekujoCRUt2hmJ
27+
kMwU3lK8Y0ChrcMQUvQasSrM
28+
-----END PRIVATE KEY-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package envoy.authz
2+
3+
import rego.v1
4+
5+
default allow := false
6+
7+
# METADATA
8+
# entrypoint: true
9+
allow if {
10+
input.parsed_path = [ "allow" ]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package envoy.authz_test
2+
3+
import rego.v1
4+
5+
import data.envoy.authz
6+
7+
test_not_allowed if {
8+
not authz.allow with input as {
9+
"parsed_path": [
10+
"some-path"
11+
],
12+
}
13+
}
14+
15+
test_allowed if {
16+
authz.allow with input as {
17+
"parsed_path": [
18+
"allow"
19+
],
20+
}
21+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package envoy.authz
2+
3+
import rego.v1
4+
5+
default allow := false
6+
7+
# METADATA
8+
# entrypoint: true
9+
allow if {
10+
input.parsed_path = [ "allow" ]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package envoy.authz_test
2+
3+
import rego.v1
4+
5+
import data.envoy.authz
6+
7+
test_not_allowed if {
8+
not authz.allow with input as {
9+
"parsed_path": [
10+
"some-path"
11+
],
12+
}
13+
}
14+
15+
test_allowed if {
16+
authz.allow with input as {
17+
"parsed_path": [
18+
"allow"
19+
],
20+
}
21+
}

0 commit comments

Comments
 (0)