Skip to content

Commit 0cee1c3

Browse files
committed
OPA: Allow prepare query optimisation via partial evaluation
1 parent 1b4b204 commit 0cee1c3

File tree

6 files changed

+132
-103
lines changed

6 files changed

+132
-103
lines changed

config/config.go

+19-16
Original file line numberDiff line numberDiff line change
@@ -284,14 +284,15 @@ type Config struct {
284284
LuaModules *listFlag `yaml:"lua-modules"`
285285
LuaSources *listFlag `yaml:"lua-sources"`
286286

287-
EnableOpenPolicyAgent bool `yaml:"enable-open-policy-agent"`
288-
OpenPolicyAgentConfigTemplate string `yaml:"open-policy-agent-config-template"`
289-
OpenPolicyAgentEnvoyMetadata string `yaml:"open-policy-agent-envoy-metadata"`
290-
OpenPolicyAgentCleanerInterval time.Duration `yaml:"open-policy-agent-cleaner-interval"`
291-
OpenPolicyAgentStartupTimeout time.Duration `yaml:"open-policy-agent-startup-timeout"`
292-
OpenPolicyAgentRequestBodyBufferSize int64 `yaml:"open-policy-agent-request-body-buffer-size"`
293-
OpenPolicyAgentMaxRequestBodySize int64 `yaml:"open-policy-agent-max-request-body-size"`
294-
OpenPolicyAgentMaxMemoryBodyParsing int64 `yaml:"open-policy-agent-max-memory-body-parsing"`
287+
EnableOpenPolicyAgent bool `yaml:"enable-open-policy-agent"`
288+
OpenPolicyAgentConfigTemplate string `yaml:"open-policy-agent-config-template"`
289+
OpenPolicyAgentEnvoyMetadata string `yaml:"open-policy-agent-envoy-metadata"`
290+
OpenPolicyAgentCleanerInterval time.Duration `yaml:"open-policy-agent-cleaner-interval"`
291+
OpenPolicyAgentStartupTimeout time.Duration `yaml:"open-policy-agent-startup-timeout"`
292+
OpenPolicyAgentRequestBodyBufferSize int64 `yaml:"open-policy-agent-request-body-buffer-size"`
293+
OpenPolicyAgentMaxRequestBodySize int64 `yaml:"open-policy-agent-max-request-body-size"`
294+
OpenPolicyAgentMaxMemoryBodyParsing int64 `yaml:"open-policy-agent-max-memory-body-parsing"`
295+
EnableOpenPolicyAgentPreevaluationOptimization bool `yaml:"enable-open-policy-agent-preevaluation-optimization"`
295296

296297
PassiveHealthCheck mapFlags `yaml:"passive-health-check"`
297298
}
@@ -516,6 +517,7 @@ func NewConfig() *Config {
516517
flag.Int64Var(&cfg.OpenPolicyAgentMaxRequestBodySize, "open-policy-agent-max-request-body-size", openpolicyagent.DefaultMaxRequestBodySize, "Maximum number of bytes from a http request body that are passed as input to the policy")
517518
flag.Int64Var(&cfg.OpenPolicyAgentRequestBodyBufferSize, "open-policy-agent-request-body-buffer-size", openpolicyagent.DefaultRequestBodyBufferSize, "Read buffer size for the request body")
518519
flag.Int64Var(&cfg.OpenPolicyAgentMaxMemoryBodyParsing, "open-policy-agent-max-memory-body-parsing", openpolicyagent.DefaultMaxMemoryBodyParsing, "Total number of bytes used to parse http request bodies across all requests. Once the limit is met, requests will be rejected.")
520+
flag.BoolVar(&cfg.EnableOpenPolicyAgentPreevaluationOptimization, "enable-open-policy-agent-preevaluation-optimization", false, "As an optimization, apply partial evaluation during preparation of the OPA policy. This can reduce the time to evaluate the policy at runtime but consumes more memory.")
519521

520522
// TLS client certs
521523
flag.StringVar(&cfg.ClientKeyFile, "client-tls-key", "", "TLS Key file for backend connections, multiple keys may be given comma separated - the order must match the certs")
@@ -928,14 +930,15 @@ func (c *Config) ToOptions() skipper.Options {
928930
LuaModules: c.LuaModules.values,
929931
LuaSources: c.LuaSources.values,
930932

931-
EnableOpenPolicyAgent: c.EnableOpenPolicyAgent,
932-
OpenPolicyAgentConfigTemplate: c.OpenPolicyAgentConfigTemplate,
933-
OpenPolicyAgentEnvoyMetadata: c.OpenPolicyAgentEnvoyMetadata,
934-
OpenPolicyAgentCleanerInterval: c.OpenPolicyAgentCleanerInterval,
935-
OpenPolicyAgentStartupTimeout: c.OpenPolicyAgentStartupTimeout,
936-
OpenPolicyAgentMaxRequestBodySize: c.OpenPolicyAgentMaxRequestBodySize,
937-
OpenPolicyAgentRequestBodyBufferSize: c.OpenPolicyAgentRequestBodyBufferSize,
938-
OpenPolicyAgentMaxMemoryBodyParsing: c.OpenPolicyAgentMaxMemoryBodyParsing,
933+
EnableOpenPolicyAgent: c.EnableOpenPolicyAgent,
934+
OpenPolicyAgentConfigTemplate: c.OpenPolicyAgentConfigTemplate,
935+
OpenPolicyAgentEnvoyMetadata: c.OpenPolicyAgentEnvoyMetadata,
936+
OpenPolicyAgentCleanerInterval: c.OpenPolicyAgentCleanerInterval,
937+
OpenPolicyAgentStartupTimeout: c.OpenPolicyAgentStartupTimeout,
938+
OpenPolicyAgentMaxRequestBodySize: c.OpenPolicyAgentMaxRequestBodySize,
939+
OpenPolicyAgentRequestBodyBufferSize: c.OpenPolicyAgentRequestBodyBufferSize,
940+
OpenPolicyAgentMaxMemoryBodyParsing: c.OpenPolicyAgentMaxMemoryBodyParsing,
941+
EnableOpenPolicyAgentPreevaluationOptimization: c.EnableOpenPolicyAgentPreevaluationOptimization,
939942

940943
PassiveHealthCheck: c.PassiveHealthCheck.values,
941944
}

filters/openpolicyagent/evaluation.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ package openpolicyagent
33
import (
44
"context"
55
"fmt"
6+
"time"
7+
68
ext_authz_v3_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
79
ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
810
"github.com/open-policy-agent/opa-envoy-plugin/envoyauth"
911
"github.com/open-policy-agent/opa-envoy-plugin/opa/decisionlog"
1012
"github.com/open-policy-agent/opa/ast"
11-
"github.com/open-policy-agent/opa/rego"
1213
"github.com/open-policy-agent/opa/server"
1314
"github.com/open-policy-agent/opa/topdown"
1415
"github.com/opentracing/opentracing-go"
1516
pbstruct "google.golang.org/protobuf/types/known/structpb"
16-
"time"
1717
)
1818

1919
func (opa *OpenPolicyAgentInstance) Eval(ctx context.Context, req *ext_authz_v3.CheckRequest) (*envoyauth.EvalResult, error) {
@@ -70,7 +70,7 @@ func (opa *OpenPolicyAgentInstance) Eval(ctx context.Context, req *ext_authz_v3.
7070
return nil, err
7171
}
7272

73-
err = envoyauth.Eval(ctx, opa, inputValue, result, rego.DistributedTracingOpts(opa.DistributedTracing()))
73+
err = envoyauth.Eval(ctx, opa, inputValue, result)
7474
if err != nil {
7575
return nil, err
7676
}

filters/openpolicyagent/openpolicyagent.go

+32-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
ext_authz_v3_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
1919
"github.com/google/uuid"
20+
"github.com/open-policy-agent/opa-envoy-plugin/envoyauth"
2021
"github.com/open-policy-agent/opa/ast"
2122
"github.com/open-policy-agent/opa/config"
2223
"github.com/open-policy-agent/opa/logging"
@@ -74,6 +75,8 @@ type OpenPolicyAgentRegistry struct {
7475
bodyReadBufferSize int64
7576

7677
tracer opentracing.Tracer
78+
79+
preevaluationOptimization bool
7780
}
7881

7982
type OpenPolicyAgentFilter interface {
@@ -122,6 +125,13 @@ func WithTracer(tracer opentracing.Tracer) func(*OpenPolicyAgentRegistry) error
122125
}
123126
}
124127

128+
func WithPreevaluationOptimization(enable bool) func(*OpenPolicyAgentRegistry) error {
129+
return func(cfg *OpenPolicyAgentRegistry) error {
130+
cfg.preevaluationOptimization = enable
131+
return nil
132+
}
133+
}
134+
125135
func NewOpenPolicyAgentRegistry(opts ...func(*OpenPolicyAgentRegistry) error) *OpenPolicyAgentRegistry {
126136
registry := &OpenPolicyAgentRegistry{
127137
reuseDuration: defaultReuseDuration,
@@ -369,6 +379,7 @@ type OpenPolicyAgentInstance struct {
369379
bundleName string
370380
preparedQuery *rego.PreparedEvalQuery
371381
preparedQueryDoOnce *sync.Once
382+
preparedQueryErr error
372383
interQueryBuiltinCache iCache.InterQueryCache
373384
once sync.Once
374385
stopped bool
@@ -740,22 +751,11 @@ func (opa *OpenPolicyAgentInstance) Runtime() *ast.Term { return opa.manager.Inf
740751
// Logger is an implementation of the envoyauth.EvalContext interface
741752
func (opa *OpenPolicyAgentInstance) Logger() logging.Logger { return opa.manager.Logger() }
742753

743-
// PreparedQueryDoOnce is an implementation of the envoyauth.EvalContext interface
744-
func (opa *OpenPolicyAgentInstance) PreparedQueryDoOnce() *sync.Once { return opa.preparedQueryDoOnce }
745-
746754
// InterQueryBuiltinCache is an implementation of the envoyauth.EvalContext interface
747755
func (opa *OpenPolicyAgentInstance) InterQueryBuiltinCache() iCache.InterQueryCache {
748756
return opa.interQueryBuiltinCache
749757
}
750758

751-
// PreparedQuery is an implementation of the envoyauth.EvalContext interface
752-
func (opa *OpenPolicyAgentInstance) PreparedQuery() *rego.PreparedEvalQuery { return opa.preparedQuery }
753-
754-
// SetPreparedQuery is an implementation of the envoyauth.EvalContext interface
755-
func (opa *OpenPolicyAgentInstance) SetPreparedQuery(q *rego.PreparedEvalQuery) {
756-
opa.preparedQuery = q
757-
}
758-
759759
// Config is an implementation of the envoyauth.EvalContext interface
760760
func (opa *OpenPolicyAgentInstance) Config() *config.Config { return opa.opaConfig }
761761

@@ -764,6 +764,27 @@ func (opa *OpenPolicyAgentInstance) DistributedTracing() opatracing.Options {
764764
return buildTracingOptions(opa.registry.tracer, opa.bundleName, opa.manager)
765765
}
766766

767+
// CreatePreparedQueryOnce is an implementation of the envoyauth.EvalContext interface
768+
func (opa *OpenPolicyAgentInstance) CreatePreparedQueryOnce(opts envoyauth.PrepareQueryOpts) (*rego.PreparedEvalQuery, error) {
769+
opa.preparedQueryDoOnce.Do(func() {
770+
regoOpts := append(opts.Opts, rego.DistributedTracingOpts(opa.DistributedTracing()))
771+
772+
prepareOpts := opts.PrepareOpts
773+
774+
if opa.registry.preevaluationOptimization {
775+
prepareOpts = append(prepareOpts, rego.WithPartialEval())
776+
}
777+
778+
pq, err := rego.New(regoOpts...).
779+
PrepareForEval(context.Background(), prepareOpts...)
780+
781+
opa.preparedQuery = &pq
782+
opa.preparedQueryErr = err
783+
})
784+
785+
return opa.preparedQuery, opa.preparedQueryErr
786+
}
787+
767788
// logging.Logger that does not pollute info with debug logs
768789
type QuietLogger struct {
769790
target logging.Logger

go.mod

+25-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module github.com/zalando/skipper
22

3+
replace github.com/open-policy-agent/opa-envoy-plugin => github.com/mjungsbluth/opa-envoy-plugin v0.26.0-envoy-2.0.20241014153129-8c49c01d8364
4+
35
require (
46
github.com/AlexanderYastrebov/noleak v0.0.0-20230711175737-345842f874fb
57
github.com/MicahParks/keyfunc v1.9.0
@@ -27,7 +29,7 @@ require (
2729
github.com/lightstep/lightstep-tracer-go v0.26.0
2830
github.com/miekg/dns v1.1.62
2931
github.com/oklog/ulid v1.3.1
30-
github.com/open-policy-agent/opa v0.68.0
32+
github.com/open-policy-agent/opa v0.69.0
3133
github.com/open-policy-agent/opa-envoy-plugin v0.68.0-envoy-4
3234
github.com/opentracing/basictracer-go v1.1.0
3335
github.com/opentracing/opentracing-go v1.2.0
@@ -48,38 +50,38 @@ require (
4850
github.com/yookoala/gofast v0.8.0
4951
github.com/yuin/gopher-lua v1.1.1
5052
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab
51-
golang.org/x/crypto v0.27.0
53+
golang.org/x/crypto v0.28.0
5254
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
53-
golang.org/x/net v0.29.0
55+
golang.org/x/net v0.30.0
5456
golang.org/x/oauth2 v0.23.0
5557
golang.org/x/sync v0.8.0
56-
golang.org/x/term v0.24.0
58+
golang.org/x/term v0.25.0
5759
golang.org/x/time v0.6.0
58-
google.golang.org/protobuf v1.34.2
60+
google.golang.org/protobuf v1.35.1
5961
gopkg.in/go-jose/go-jose.v2 v2.6.3
6062
gopkg.in/yaml.v2 v2.4.0
6163
layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf
6264

6365
)
6466

6567
require (
66-
cloud.google.com/go/compute/metadata v0.3.0 // indirect
68+
cloud.google.com/go/compute/metadata v0.5.0 // indirect
6769
dario.cat/mergo v1.0.0 // indirect
6870
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
6971
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
7072
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
7173
github.com/Microsoft/go-winio v0.6.2 // indirect
7274
github.com/OneOfOne/xxhash v1.2.8 // indirect
73-
github.com/agnivade/levenshtein v1.1.1 // indirect
75+
github.com/agnivade/levenshtein v1.2.0 // indirect
7476
github.com/armon/go-metrics v0.4.1 // indirect
7577
github.com/beorn7/perks v1.0.1 // indirect
7678
github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect
7779
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 // indirect
7880
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
7981
github.com/cespare/xxhash v1.1.0 // indirect
80-
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
81-
github.com/containerd/containerd v1.7.21 // indirect
82-
github.com/containerd/errdefs v0.1.0 // indirect
82+
github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 // indirect
83+
github.com/containerd/containerd v1.7.22 // indirect
84+
github.com/containerd/errdefs v0.2.0 // indirect
8385
github.com/containerd/log v0.1.0 // indirect
8486
github.com/containerd/platforms v0.2.1 // indirect
8587
github.com/cpuguy83/dockercfg v0.3.1 // indirect
@@ -91,7 +93,7 @@ require (
9193
github.com/docker/docker v27.1.1+incompatible // indirect
9294
github.com/docker/go-units v0.5.0 // indirect
9395
github.com/dustin/go-humanize v1.0.0 // indirect
94-
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
96+
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
9597
github.com/felixge/httpsnoop v1.0.4 // indirect
9698
github.com/fsnotify/fsnotify v1.7.0 // indirect
9799
github.com/go-ini/ini v1.67.0 // indirect
@@ -101,7 +103,7 @@ require (
101103
github.com/go-ole/go-ole v1.2.6 // indirect
102104
github.com/gobwas/glob v0.2.3 // indirect
103105
github.com/gogo/protobuf v1.3.2 // indirect
104-
github.com/golang/glog v1.2.1 // indirect
106+
github.com/golang/glog v1.2.2 // indirect
105107
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
106108
github.com/golang/protobuf v1.5.4 // indirect
107109
github.com/golang/snappy v0.0.4 // indirect
@@ -169,18 +171,20 @@ require (
169171
go.opentelemetry.io/otel/trace v1.28.0 // indirect
170172
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
171173
go.uber.org/atomic v1.9.0 // indirect
172-
go.uber.org/automaxprocs v1.5.3 // indirect
173-
golang.org/x/mod v0.20.0 // indirect
174-
golang.org/x/sys v0.25.0 // indirect
175-
golang.org/x/text v0.18.0 // indirect
176-
golang.org/x/tools v0.24.0 // indirect
174+
go.uber.org/automaxprocs v1.6.0 // indirect
175+
golang.org/x/mod v0.21.0 // indirect
176+
golang.org/x/sys v0.26.0 // indirect
177+
golang.org/x/text v0.19.0 // indirect
178+
golang.org/x/tools v0.26.0 // indirect
177179
gonum.org/v1/gonum v0.8.2 // indirect
178-
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
179-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
180-
google.golang.org/grpc v1.66.0 // indirect
180+
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
181+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
182+
google.golang.org/grpc v1.67.1 // indirect
181183
gopkg.in/yaml.v3 v3.0.1 // indirect
182184
oras.land/oras-go/v2 v2.3.1 // indirect
183185
sigs.k8s.io/yaml v1.4.0 // indirect
184186
)
185187

186-
go 1.22
188+
go 1.22.0
189+
190+
toolchain go1.23.1

0 commit comments

Comments
 (0)