Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Improve OPA authorization filter benchmarks #3391

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
450 changes: 450 additions & 0 deletions filters/openpolicyagent/opaauthorizerequest/benchmark_test.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,20 @@ package opaauthorizerequest

import (
"fmt"
opasdktest "github.com/open-policy-agent/opa/sdk/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zalando/skipper/eskip"
"github.com/zalando/skipper/filters"
"github.com/zalando/skipper/filters/builtin"
"github.com/zalando/skipper/proxy/proxytest"
"github.com/zalando/skipper/tracing/tracingtest"
"io"
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"time"

"github.com/golang-jwt/jwt/v4"
opasdktest "github.com/open-policy-agent/opa/sdk/test"
"github.com/stretchr/testify/assert"
"github.com/zalando/skipper/eskip"
"github.com/zalando/skipper/filters"
"github.com/zalando/skipper/metrics/metricstest"
"github.com/zalando/skipper/proxy/proxytest"
"github.com/zalando/skipper/tracing/tracingtest"

"github.com/zalando/skipper/filters/filtertest"
"github.com/zalando/skipper/filters/openpolicyagent"
)

Expand Down Expand Up @@ -791,231 +783,3 @@ func isHeadersAbsent(t *testing.T, unwantedHeaders http.Header, headers http.Hea
}
return true
}

const (
tokenExp = 2 * time.Hour

certPath = "../../../skptesting/cert.pem"
keyPath = "../../../skptesting/key.pem"
)

func BenchmarkAuthorizeRequest(b *testing.B) {
b.Run("authorize-request-minimal", func(b *testing.B) {
opaControlPlane := opasdktest.MustNewServer(
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
"main.rego": `
package envoy.authz

default allow = false

allow {
input.parsed_path = [ "allow" ]
}
`,
}),
)

f, err := createOpaFilter(opaControlPlane)
assert.NoError(b, err)

url, err := url.Parse("http://opa-authorized.test/somepath")
assert.NoError(b, err)

ctx := &filtertest.Context{
FStateBag: map[string]interface{}{},
FResponse: &http.Response{},
FRequest: &http.Request{
Header: map[string][]string{
"Authorization": {"Bearer FOOBAR"},
},
URL: url,
},
FMetrics: &metricstest.MockMetrics{},
}

b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
f.Request(ctx)
}
})

b.Run("authorize-request-with-body", func(b *testing.B) {
opaControlPlane := opasdktest.MustNewServer(
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
"main.rego": `
package envoy.authz

import rego.v1

default allow = false

allow if {
endswith(input.parsed_body.email, "@zalando.de")
}
`,
}),
)

f, err := createBodyBasedOpaFilter(opaControlPlane)
assert.NoError(b, err)

url, err := url.Parse("http://opa-authorized.test/somepath")
assert.NoError(b, err)

body := `{"email": "[email protected]"}`
ctx := &filtertest.Context{
FStateBag: map[string]interface{}{},
FResponse: &http.Response{},
FRequest: &http.Request{
Method: "POST",
Header: map[string][]string{
"Authorization": {"Bearer FOOBAR"},
"Content-Type": {"application/json"},
},
URL: url,
Body: io.NopCloser(strings.NewReader(body)),
ContentLength: int64(len(body)),
},
FMetrics: &metricstest.MockMetrics{},
}

b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
f.Request(ctx)
}
})

b.Run("authorize-request-jwt-validation", func(b *testing.B) {

publicKey, err := os.ReadFile(certPath)
if err != nil {
log.Fatalf("Failed to read public key: %v", err)
}

opaControlPlane := opasdktest.MustNewServer(
opasdktest.MockBundle("/bundles/somebundle.tar.gz", map[string]string{
"main.rego": fmt.Sprintf(`
package envoy.authz

import future.keywords.if

default allow = false

public_key_cert := %q

bearer_token := t if {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}

allow if {
[valid, _, payload] := io.jwt.decode_verify(bearer_token, {
"cert": public_key_cert,
"aud": "nqz3xhorr5"
})

valid

payload.sub == "5974934733"
}
`, publicKey),
}),
)

f, err := createOpaFilter(opaControlPlane)
assert.NoError(b, err)

url, err := url.Parse("http://opa-authorized.test/somepath")
assert.NoError(b, err)

claims := jwt.MapClaims{
"iss": "https://some.identity.acme.com",
"sub": "5974934733",
"aud": "nqz3xhorr5",
"iat": time.Now().Add(-time.Minute).UTC().Unix(),
"exp": time.Now().Add(tokenExp).UTC().Unix(),
"email": "[email protected]",
}

token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

privKey, err := os.ReadFile(keyPath)
if err != nil {
log.Fatalf("Failed to read priv key: %v", err)
}

key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privKey))
if err != nil {
log.Fatalf("Failed to parse RSA PEM: %v", err)
}

// Sign and get the complete encoded token as a string using the secret
signedToken, err := token.SignedString(key)
if err != nil {
log.Fatalf("Failed to sign token: %v", err)
}

ctx := &filtertest.Context{
FStateBag: map[string]interface{}{},
FResponse: &http.Response{},
FRequest: &http.Request{
Header: map[string][]string{
"Authorization": {fmt.Sprintf("Bearer %s", signedToken)},
},
URL: url,
},
FMetrics: &metricstest.MockMetrics{},
}

b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
f.Request(ctx)
assert.False(b, ctx.FServed)
}
})
}

func createOpaFilter(opaControlPlane *opasdktest.Server) (filters.Filter, error) {
config := generateConfig(opaControlPlane, "envoy/authz/allow")
opaFactory := openpolicyagent.NewOpenPolicyAgentRegistry()
spec := NewOpaAuthorizeRequestSpec(opaFactory, openpolicyagent.WithConfigTemplate(config))
return spec.CreateFilter([]interface{}{"somebundle.tar.gz"})
}

func createBodyBasedOpaFilter(opaControlPlane *opasdktest.Server) (filters.Filter, error) {
config := generateConfig(opaControlPlane, "envoy/authz/allow")
opaFactory := openpolicyagent.NewOpenPolicyAgentRegistry()
spec := NewOpaAuthorizeRequestWithBodySpec(opaFactory, openpolicyagent.WithConfigTemplate(config))
return spec.CreateFilter([]interface{}{"somebundle.tar.gz"})
}

func generateConfig(opaControlPlane *opasdktest.Server, path string) []byte {
return []byte(fmt.Sprintf(`{
"services": {
"test": {
"url": %q
}
},
"bundles": {
"test": {
"resource": "/bundles/{{ .bundlename }}"
}
},
"labels": {
"environment": "test"
},
"plugins": {
"envoy_ext_authz_grpc": {
"path": %q,
"dry-run": false
}
}
}`, opaControlPlane.URL(), path))
}
22 changes: 22 additions & 0 deletions filters/openpolicyagent/opaauthorizerequest/testResources/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIJAKjOTehGhMMYMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxGTAXBgNVBAMMEGxvY2FsZXhhbXBsZS5vcmcwHhcNMTkw
MTE4MTYzNzI3WhcNMTkwMTI3MTYzNzI3WjBgMQswCQYDVQQGEwJBVTETMBEGA1UE
CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
MRkwFwYDVQQDDBBsb2NhbGV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA42H1BFt2/ZZuqNCl+VVG99sfRO4r5FXcJccUmHajLDIYdudA
jWLXMG9jhc+HfOLIKYWd5NGAJKAHVzNVbGgEDGG8icy83ShTkmMISEnyYqqDH6wf
qkxMwZ6hYQnJUveRPOejcfGVUNh8XNu7WC228qyWd+0JaVVxVU7F3ks2q/eRxKQM
fOZYh4gY5d4gt/JbAU8VNgWo9jCEuK+026CkpTyGVYa2iCLjOiKjjnKpixgSXhUU
kQsHITp2yTULHC9Wqn92VLCi1al/CCtpZExwO+jq5sihCCfE/Erq+wesnC+vFalE
BmV7K9qe+k0SGyM1O7yFLClCfbuuIEwguhCNVwIDAQABo1AwTjAdBgNVHQ4EFgQU
gJB4kmWERbmiOj3FQULuMtowTpswHwYDVR0jBBgwFoAUgJB4kmWERbmiOj3FQULu
MtowTpswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAk2FmuKemxfNF
b0Aeoph/KEXekzM2YSsMjAlXiIt7SidNEy5XWLE30RKY1TXpYg3kB5qihLT7S0VB
UVV3vQwvc8htnuAJB+tukBcQzIFPHWFxdv69j+iRTVjf/zPXTS4CeoHujAVRlFuc
wbEumkxyT/MX4XfhBHPjhe7fy5MMULESAmWPHrOm5HO+HUVYt8OzBpYG2o3izJ+I
NFy9rAjfgbakvv0D2XnNl01n9gycLag6m6UVnXyvisiiNmFhobYlryM/O8T4uEo1
rU62hJKI6iN3S9wtRDvNk6PwXIwJ0kGJkjFXR/K84ViN6DaQULwZDWyaytfvJKtY
2IZhpkvX0Q==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions filters/openpolicyagent/opaauthorizerequest/testResources/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDjYfUEW3b9lm6o
0KX5VUb32x9E7ivkVdwlxxSYdqMsMhh250CNYtcwb2OFz4d84sgphZ3k0YAkoAdX
M1VsaAQMYbyJzLzdKFOSYwhISfJiqoMfrB+qTEzBnqFhCclS95E856Nx8ZVQ2Hxc
27tYLbbyrJZ37QlpVXFVTsXeSzar95HEpAx85liHiBjl3iC38lsBTxU2Baj2MIS4
r7TboKSlPIZVhraIIuM6IqOOcqmLGBJeFRSRCwchOnbJNQscL1aqf3ZUsKLVqX8I
K2lkTHA76OrmyKEIJ8T8Sur7B6ycL68VqUQGZXsr2p76TRIbIzU7vIUsKUJ9u64g
TCC6EI1XAgMBAAECggEARNs3HVitUeGqJQj6GeUPFqOOdotBU2YEwpPk0r6qbwnE
is1AqRATZiF1G+JafyEVyC0kQVSH349uaaOr7KYbA7zdIUWUs8wwcpX2vh1WfzZv
erne5O0yGTf2WrJh+vPpUW47+pdTxiWok14e/3bofdhxwGNRhEpRhanTFZvlNHGz
0p9SY8AyBbpNFEl0TkwLP+hcyKqz91jgOnE98MnUYKh6ZG3CY6L3Ca8A4BE3RuOw
gXdua7T2hsyMzYdv9aIdW+BMk2Fa3VFpvnm6Sh2Uje1KBIOuWTgSumcSLbaPVHKs
ZQthyOtt7ueJ46E2hdgoCP0R8Rbyqdy6bhUmCpFrEQKBgQD3A6+O0BhjJovKka5L
u33fphLtwnABHnH+QqPeUAy8yN2yiy0ZxL19WN0doAbF56xErTHYq+UriHgHfYAv
lYtmtocwkl782yiUscIVfA9sUovzG5fsVP9fRUC5xWo+Ak59NX6lr5QXoBltanON
YMAbwhz5q1NTAt9c9FPGjERLswKBgQDrp3OCqobVpcK2haLPFNsj+huqKPSp9STS
hjqUjUiPAQTuZyb8H3Q5NtHB5j354BzkqaOXFCKaqiJIKHz794IuDOvou7cjF+J4
4GOxnCJOFsvtvBoYWTFF0lz4++tvBtPLYZnnN2fCF/olk4ZQ2/FAapF/m6ehTLBa
N3S52AzVzQKBgH7WUatPh3ZCML3PmGQi3judF1Mm6ERq0bXxmhtpl2DI863ecUYu
E+7tVn0D0vaEQ5zwIgxUF9UGujt+YfgNHgub5kc2obfNAUV5EWPe1DyXFm262YPt
EURmVxoNGMTGgm8grOt/ANgwyV25r6QE7iBSyHYbVynk67TbcLkfBWKpAoGBAKGw
kIIcTU20YYho4w/hSIdD6c10MoOW73//l5wr4Jg2Y9LMNiSR1GYZZgz71JRpoImI
l/VmXGPwznriRPeBmPHN7eQPQJY0ojC8DctkzOj1nVDuWp1QPY2hzCcOezj/3zxS
KI5MJsY3O2yi72r1rm+7bz+2Zms3Ol18ZXvKcOwVAoGBALYNfh4TYHRMLB8HDNZm
a7I1cq0N6ZPgvTzS/rf1qM0EabK8gvxDHzxAdnc1NLGx7JLd4svbATW7p5WjLYeu
0hh/DPy2LbTYLnhOn4a5Ncm+xKYfsvw4IQg98chxemQrGkwXSDsekujoCRUt2hmJ
kMwU3lK8Y0ChrcMQUvQasSrM
-----END PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package envoy.authz

import rego.v1

default allow := false

# METADATA
# entrypoint: true
allow if {
input.parsed_path = [ "allow" ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package envoy.authz_test

import rego.v1

import data.envoy.authz

test_not_allowed if {
not authz.allow with input as {
"parsed_path": [
"some-path"
],
}
}

test_allowed if {
authz.allow with input as {
"parsed_path": [
"allow"
],
}
}
11 changes: 11 additions & 0 deletions skptesting/simple-opa-bundle/allow.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package envoy.authz

import rego.v1

default allow := false

# METADATA
# entrypoint: true
mefarazath marked this conversation as resolved.
Show resolved Hide resolved
allow if {
input.parsed_path = [ "allow" ]
}
21 changes: 21 additions & 0 deletions skptesting/simple-opa-bundle/allow_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package envoy.authz_test

import rego.v1

import data.envoy.authz

test_not_allowed if {
not authz.allow with input as {
"parsed_path": [
"some-path"
],
}
}

test_allowed if {
authz.allow with input as {
"parsed_path": [
"allow"
],
}
}