This release includes a powerful new compiler optimization for Enterprise OPA: Loop-Invariant Code Motion!
This technique allows Enterprise OPA to hoist redundant code out of loops in query plans, and allows it to intelligently restructure nested loops as well. In iteration-heavy policies, the speedups can be dramatic.
This optimization is now enabled by default, so your policies will immediately benefit upon upgrading to the latest Enterprise OPA version.
This release pulls in OPA v1.12.1 and the latest Regal release, v0.37.0.
This release pulls in OPA v1.10.1.
This release pulls in OPA v1.10.0.
This release pulls in OPA v1.9.0 and the latest Regal release, v0.36.1.
The Compile API extensions have been ported from EOPA to OPA, and are now feature in EOPA as a standard OPA feature. Concretely, this means that the headers and annotations expected for Compile API usage need to follow the OPA requirements. If you have used EOPA's Compile API extensions to generate data filters before, you need to replace:
- Compile metadata no longer resides in "custom section"
Before:
package filters
# METADATA
# scope: document
# custom:
# unknowns:
# - input.fruits
# mask_rule: masksAfter:
package filters
# METADATA
# scope: document
# compile: # <-------- replace custom with compile
# unknowns:
# - input.fruits
# mask_rule: masks(If you have other custom annotations, those can stay in the "custom" section. Only the compile-related keys have been moved into their own section.)
- Headers
The target and dialect selection was driven by Accept headers. Previously, these used a prefix of "application/vnd.styra". Now, they use "application/vnd.opa", e.g. "application/vnd.opa.postgresql+json".
This release fixes a path validation bug that could cause panics when EOPA was run in server mode with --authorization=basic.
This release includes only a release engineering bugfix for the build system, with no other code changes from the EOPA v1.43.0 release.
This release pulls in OPA v1.8.0.
Until the binary signing setup is restored, we'll go with only publishing docker images (https://ghcr.io/open-policy-agent/eopa) and binaries in the GitHub release artifacts. Homebrew and properly-signed artifacts for macOS and Windows will come back in the future.
From now on, Enterprise OPA does not need an extra license when talking to Styra DAS!
This release also includes various dependency bumps, and updates the embedded OPA version to v1.6.0.
Enterprise OPA now automatically enters licensed mode when connected to a Styra DAS instance. This should allow for easier setup and deployment of Enterprise OPA for Styra customers.
If Styra DAS is not available, Enterprise OPA will fall back to its existing license key system.
This bugfix release updates the embedded OPA version to v1.5.1.
It's only relevant to users explicitly selecting the rego target (i.e. OPA's evaluation engine) in eopa eval, or using fallback mode.
This release includes various dependency bumps, and updates the embedded OPA version to v1.5.0.
This release contains a security fix, addressing CVE-2025-46569. The release also updates the embedded OPA version to v1.4.0, and the embedded Regal version to v0.33.1.
For details on the security content of this release, please see the OPA v1.4.0 release notes, and the associated Security Advisory.
This release fixes a bug related to using Rego v0 bundles with the Compile API.
Also, referencing mask rules in annotations has been simplified: rules defined in the same package can now be referenced without the full prefix:
package filters
# METADATA
# scope: document
# custom:
# unknowns: ["input.tickets"]
# mask_rule: masks # <-------- here
default include := true #|
# v-------------------------------
masks.tickets.description.replace.value := "<description>"Starting from this release, our Windows binaries feature a Styra icon.
This releases introduces Column Masking in Data Filters and small change to the Compile API. It also features various dependency bumps.
In certain data filtering use cases, a row might be returned from the database that has a sensitive column present. We still want the application to be able to display everything it can to the user, but ideally hiding or modifying the sensitive values before display.
This is now supported by defining mask rules in your data filter policies, for example:
package filters
# METADATA
# scope: document
# description: Return all rows, for sake of the example.
# custom:
# unknowns: ["input.tickets"]
# mask_rule: data.filters.masks
default include := true
# Mask all ticket descriptions by default.
default masks.tickets.description.replace.value := "<description>"
# Allow viewing the description if the user is an admin.
masks.tickets.description.replace.value := {} if {
"admin" in data.roles[input.tenant][input.user]
}Column masks are also returned by rego.compile(), and supported in filter.helper().
The Compile API in Enterprise OPA now mirrors the Data API more closely: The rule to be used for translation into SQL clauses or UCAST expressions is part of the request path.
See the Data Filters Compilation API docs for all details. Users of our TypeScript SDK don't need to adapt anything, the changes have been made in the latest releases.
This release includes various dependency bumps, and updates the embedded OPA version to v1.3.0, and the embedded Regal version to v0.32.0.
This release includes an SQLite target for data filters generated by the Compile API, along with bugfixes and dependency bumps.
This release also includes Windows Authenticode signing and timestamping for the Windows EOPA binary. This means fewer security pop-ups on Windows, and easier deployments in enterprise contexts!
This release fixes a bug where parameterized tests were not properly evaluated in Enterprise OPA.
There is also a small change to the filter.helper() arguments: The mandatory tables argument is now a positional argument:
Before:
filtered := filter.helper(
"data.filters.include",
"SELECT fruits.name, users.name as owner FROM fruits LEFT JOIN users ON fruits.owner_id = users.id",
{
"tables": {
"fruits": fruits_table,
"users": users_table,
},
"debug": true,
})After:
filtered := filter.helper(
"data.filters.include",
"SELECT fruits.name, users.name as owner FROM fruits LEFT JOIN users ON fruits.owner_id = users.id",
{
"fruits": fruits_table,
"users": users_table,
},
{
"debug": true,
})Also, the filter.helper() now accepts a SQL query (second argument) that already contains a WHERE clause.
This release includes a bug fix for ref heads and an overeager planner optimization (see upstream issue and fix). It also features performance improvements to the gRPC API plugin.
This release includes an new local file data source, for pulling in data stored on disk.
Enterprise OPA can now read in data from local files on disk:
# enterprise-opa.yaml
plugins:
data:
users:
type: localfile
file_path: users.json
file_type: json
polling_interval: 1s
rego_transform: "data.localfile.transform"See the docs for more information.
This release includes a fix for ref heads in evaluation (see upstream issue) and includes various dependency bumps.
This release features a new built-in function, rego.compile, that mirrors the extended Compile API of Enterprise OPA.
It is intended for data filter policy testing.
It is accompanied by a helper function, data.system.eopa.utils.tests.v1.filter.helper that allows for exemplary data policy testing.
With a data policy like this, filters.rego,
package filters
# METADATA
# scope: document
# custom:
# unknowns: ["input.tickets", "input.users"]
include if input.users.name == input.usernameyou can use the helper to create a test that actually filters some tables:
package filters
import data.system.eopa.utils.tests.v1.filter
tickets_table := [
{"id": 0, "description": "bluetooth icon is green", "assignee": "a"},
{"id": 1, "description": "yellow pages are purple", "assignee": "a"},
{"id": 2, "description": "bluegrass sounds orange", "assignee": "b"},
]
users_table := [
{"id": "a", "name": "jane"},
{"id": "b", "name": "john"},
]
test_assignee_can_see_their_tickets if {
filtered := filter.helper(
"data.filters.include",
"SELECT tickets.description, users.name as assignee FROM tickets LEFT JOIN users ON tickets.assignee = users.id",
{"tables": {
"tickets": tickets_table,
"users": users_table,
}},
) with input.username as "jane"
count(filtered) == 2
{"description": "bluetooth icon is green", "assignee": "jane"} in filtered
{"description": "yellow pages are purple", "assignee": "jane"} in filtered
}The low-level built-in method rego.compile can be used to write unit tests for the generated filter queries, like
package filters
test_generated_where_clause if {
conditions := rego.compile({
"query": "data.filters.include",
"target": "sql+postgresql",
}) with input.username as "jane"
conditions.sql == "WHERE users.name = E'jane'"
}This release brings in the latest OPA version, v1.2.0, updates the embedded Regal version to v0.31.1, and includes various other dependency bumps.
This release contains an extension to the /v1/compile API for data filtering, and various dependency bumps.
With this release, Enterprise OPA supports generating SQL WHERE clauses and UCAST conditions from partial evaluation.
For example, consider the following policy:
# METADATA
# scope: package
# custom:
# unknowns:
# - input.tickets
# - input.users
package filters
tenancy if input.tickets.tenant == input.tenant.id # tenancy check
include if {
tenancy
resolver_include
}
include if {
tenancy
not user_is_resolver(input.user, input.tenant.name)
}
resolver_include if {
user_is_resolver(input.user, input.tenant.name)
input.users.name == input.user # ticket is assigned to user
}
resolver_include if {
user_is_resolver(input.user, input.tenant.name)
# ticket is unassigned and unresolved
input.tickets.assignee == null
input.tickets.resolved == false
}
user_is_resolver(user, tenant) if "resolver" in data.roles[tenant][user]
test_user_is_admin if {
include with input.user as "alice"
with input.tenant as {"id": 2, "name": "acmecorp"}
with input.tickets.tenant as 2
with data.roles.acmecorp.alice as ["admin"]
}and this roles.json:
{
"acmecorp": {
"alice": ["admin"],
"caesar": ["reader", "resolver"]
}
}When Enterprise OPA is running with these loaded (e.g. eopa run -s filters.rego roles:roles.json), the following request shows you how to generate SQL WHERE clauses for a certain dialect ("postgres", also supports "sqlserver" and "mysql"):
$ curl 127.0.0.1:8181/v1/compile \
-d '{"query": "data.filters.include", "input": {"tenant":{"id": 2, "name": "acmecorp"}, "user": "caesar"}, "unknowns": ["input.tickets", "input.users"]}' \
-H "Accept: application/vnd.styra.sql.postgres+json"
{
"result": {
"query": "WHERE ((tickets.tenant = E'2' AND users.name = E'caesar') OR (tickets.tenant = E'2' AND tickets.assignee IS NULL AND tickets.resolved = FALSE))"
}
}
It further supports application/vnd.styra.ucast.prisma+json and application/vnd.styra.ucast.linq+json for generating UCAST conditions compatible with @styra/ucast-prisma and Styra.Ucast.Linq respectively.
See the OpenAPI spec for further details. Comprehensive documentation is going to follow this release; please reach out for support in the meantime.
After partial evaluation, a set of checks is run to ensure that the results can be translated into your target format.
The same checks can be run in testing using eopa test, which is using the metadata and tests to inform the checker about possible inputs and unknowns.
For example, if your tenancy rule was
tenancy if object.get(input, ["tickets", "tenant"], "unknown") == input.tenant.idthen eopa test filters.rego would flag this:
$ eopa test pkg/compile/bench_filters.rego
PASS: 1/1
--------------------------------------------------------------------------------
Data Policy Analysis:
pkg/compile/bench_filters.rego:9: pe_fragment_error: invalid builtin `object.get`
test_user_is_admin (pkg/compile/bench_filters.rego:40)
This release includes additional compatibility bugfixes for Enterprise OPA's bundle handling, and various dependency bumps.
This release brings in the latest OPA version, v1.1.0, and various dependency bumps.
Also, a bug related to the fmt subcommand's argument flag parsing was fixed.
This release is built with Go 1.23.5 to fix CVE-2024-45341 and CVE-2024-45336.
It also pulls in the latest Regal version, v0.30.2.
This release includes another bugfix for Enterprise OPA's bundle handling, allowing it to make use of the rego_version bundle manifest field.
This release also bumps the embedded Regal version to v0.30.0.
This release includes a bugfix for Enterprise OPA's bundle handling, restoring compatibility with v0 policy bundles.
This release includes the OPA v1.0 code changes. Please see the OPA v1 Release Notes for more details. Read more about the OPA 1.0 announcement here on our blog.
Everything you need to know about compatibility for v0 Rego code that hasn't been migrated yet can be found in these docs.
This release further includes various dependency bumps and updates the embedded Regal version to v0.29.2.
This release also bumps the golang.org/x/crypto dependency to version 0.31.0.
In that version, CVE-2024-45337 is fixed.
Please note that the vulnerable code has not been used in Enterprise OPA (or OPA), but some automated security scanners don't account for that.
For further information, see https://github.com/advisories/GHSA-v778-237x-gjrc.
With this release, the built-in sql.send() can be used to talk to Oracle Databases.
This release further includes various dependency bumps and updates the embedded Regal version to v0.29.0.
sql.send now supports Oracle databases! To connect to it, use a data_source_name of
oracle://USER:PASSWORD@HOST:PORT/DATABASE
See the sql.send documentation
for all details about the built-in.
This release includes various dependency bumps, and changes the capabilities files to include names and descriptions for upcoming Regal support of Enterprise OPA builtins.
This release includes various dependency bumps, and updates the embedded OPA version to v0.70.0.
This release includes various dependency bumps, as well as support for Google Cloud Storage as a sink for decision logs.
You can now configure Enterprise OPA to send decision logs to Google Cloud Storage.
This is done by configuring a new sink of type gcs in the decision log configuration:
decision_logs:
plugin: eopa_dl
plugins:
eopa_dl:
output:
- type: gcs
bucket: logsFor all configuration options, please see the reference documentation.
This release includes various dependency bumps, as well as fixes for a performance regression affecting licensed Enterprise OPA users.
This release updates the OPA version used in Enterprise OPA to v0.69.0.
It also includes various dependency bumps.
This release contains various version bumps and an improvement to EKM ergonomics!
Starting with this release, you no longer need to reference service and keys replacements via JSON pointers, but you can use direct lookups, like
services:
acmecorp:
credentials:
bearer:
scheme: "bearer"
token: "${vault(kv/data/acmecorp/bearer:data/token)}"Furthermore, these are also supported in plugins allowing you to retrieve secrets for their configurations as well.
These replacement can also be done in substrings, like this:
decision_logs:
plugin: eopa_dl
plugins:
eopa_dl:
output:
- type: http
url: https://myservice.corp.com/v1/logs
headers:
Authorization: "bearer ${vault(kv/data/logs:data/token)}"Replacements also happen on discovery bundles, if their config includes lookup calls of this sort.
See here for the docs on Using Secrets from HashiCorp Vault.
This release contains optimizations for the Batch Query API.
This release updates the OPA version used in Enterprise OPA to v0.68.0.
It also includes various dependency bumps.
This release upgrades the common_input field for the Batch Query API to support recursive merges with each per-query input. This is expected to allow further reduction of request sizes when the majority of each query's input would be shared data.
Here is an example of the recursive merging in action:
{
"inputs": {
"A": {
"user": {
"name": "alice",
"type": "admin"
},
"action": "write",
},
"B": {
"user": {
"name": "bob",
"type": "employee"
}
},
"C": {
"user": {"name": "eve"}
}
},
"common_input": {
"user": {
"company": "Acme Corp",
"type": "user",
},
"action": "read",
"object": "id1234"
}
}The above request using common_input is equivalent to sending this request:
{
"inputs": {
"A": {
"user": {
"name": "alice",
"company": "Acme Corp",
"type": "admin"
},
"action": "write",
"object": "id1234"
},
"B": {
"user": {
"name": "bob",
"company": "Acme Corp",
"type": "employee"
},
"action": "read",
"object": "id1234"
},
"C": {
"user": {
"name": "eve",
"company": "Acme Corp",
"type": "user",
},
"action": "read",
"object": "id1234"
}
}
}In the event of matching keys between the common_input and the per-query input object, the per-query input's value is used.
This behavior is intentionally like the behavior of object.union in Rego.
This release contains a new optional field for Batch Query API requests: common_input.
This field allows factoring out common top-level keys in an input object, which can greatly reduce request sizes in some cases.
Here is an example:
{
"inputs": {
"A": {
"user": "alice",
"action": "write",
},
"B": {
"user": "bob"
},
"C": {
"user": "eve"
}
},
"common_input": {
"action": "read",
"object": "id1234"
}
}The above request using common_input is equivalent to sending this request:
{
"inputs": {
"A": {
"user": "alice",
"action": "write",
"object": "id1234"
},
"B": {
"user": "bob",
"action": "read",
"object": "id1234"
},
"C": {
"user": "eve",
"action": "read",
"object": "id1234"
}
}
}In cases where the types are both JSON Objects, the objects' top-level keys will be merged non-recursively.
In the event of a conflict where both common_input and the per-query input have the same key, the per-query input's key/value pair is used, as shown in the earlier example where common_input provides the "action": "read" key/value pair, and query "A" provides "action": "write" for the same top-level key/value pair.
In cases where the common_input's type conflicts with that of the per-query input, the per-query input value is used.
Example:
{
"inputs": {
"A": [1, 2, 3]
},
"common_input": {
"foo": "bar"
}
}The above example is equivalent to the following request, because the input type overrides:
{
"inputs": {
"A": [1, 2, 3]
}
}This patch contains optimizations and bugfixes for the Batch Query API when used with OPA authorization policies.
This patch contains optimizations for the Batch Query API, and also updates the Regal version used in Enterprise OPA to version v0.25.0.
This patch contains experimental features for logging intermediate evaluation results. This feature is not generally available at this time, and is disabled during normal use.
This release updates Enterprise OPA to allow for environment variable substitution for the config produced by the discovery bundle. This release also updates some dependencies.
For example, with the environment variable ENV1=test1, and this config is used via discovery:
bundle:
name: ${ENV1}
decision_logs: {}
status: {}Enterprise OPA would interpret the configuration like so:
bundle:
name: test1
decision_logs: {}
status: {}This release updates the OPA version used in Enterprise OPA to v0.67.1, which includes a bugfix for chunked request handling.
This release fixes a regression in the Enterprise OPA CLI help text on some commands, and includes several updates to our dependencies.
This release updates the OPA version used in Enterprise OPA to v0.67.0, and updates Regal to v0.24.0
The OPA version bump includes max request body size limits (a potentially breaking change for clients who use enormous request sizes), optimizations around request handling, and improved performance under load for gzipped requests.
It also updates the OPA version used in Enterprise OPA to v0.66.0, and brings in various dependency bumps.
The OPA version bump includes memory usage improvements when loading gigantic bundles.
This release includes an new Apache Pulsar data source, a Bulk Eval HTTP API for evaluating a policy with multiple inputs in one request, and performance improvements when loading large bundles.
It also updates the OPA version used in Enterprise OPA to v0.65.0, and brings in various dependency bumps.
Enterprise OPA can now subscribe to Apache Pulsar topics:
# enterprise-opa.yaml
plugins:
data:
users:
type: pulsar
url: pulsar://pulsar.corp.com:6650
topics:
- users
rego_transform: "data.pulsar.transform"See the docs for more information.
You can now do multiple policy evaluations in one request:
POST /v1/batch/data/policy/allow
{
"inputs": {
"id-1": {
"user": "alice",
"action": "read",
"resource": "book"
},
"id-2": {
"user": "alice",
"action": "create",
"resource": "book"
},
"id-3": {
"user": "alice",
"action": "delete",
"resource": "book"
}
}
}The response looks like this:
{
"responses": {
"id-1": {
"result": true
},
"id-1": {
"result": true
},
"id-3": {
"result": false
},
}
}It supports the standard query parameters (like pretty, metrics, strict-builtin-errors).
Previously, activating a bundle did some unneeded work. It became apparent, and problematic, when using very large bundles (1+ GB). The issue has been fixed, leading to noticable performance improvements when using very large bundles.
This release includes an enhancement to the Apache Kafka data source, and updates the OPA version used in Enterprise OPA to v0.64.1, and brings in various dependency bumps.
Each instance of the Kafka data plugin now contributes a bunch of Prometheus metrics to the global metrics endpoint:
kafka_MOUNTPOINT_METRIC
Where MOUNTPOINT is foo:bar for a Kafka data plugin configured to manage data.foo.bar. (The Prometheus metrics naming restrictions forbid
both "." and "/" in metric names.)
When run with log level "debug", the low-level Kafka logs are overwhelming most of the times.
They are now suppressed by default, and can be inspected when running with the environment variable EOPA_KAFKA_DEBUG, like:
EOPA_KAFKA_DEBUG=1 eopa run -s -ldebug -c eopa.yaml transform.rego
In addition to that, the consumer group (if configured) is now logged when the data source plugin is initiated. Also, new key/value fields were introduced to read the batch size and transformation time from the logs more easily.
This improves the performance by lowered data conversion overheads.
This, too, benefits Kafka transforms because they always include a json.unmarshal call.
This release includes an enhancement to the Apache Kafka data source, updates the OPA version used in Enterprise OPA to v0.63.0, and brings in various dependency bumps.
By providing consumer_group: true in the Kafka data source configuration, Enterprise OPA will register the data plugin instance as its own consumer group with the Kafka Broker.
This improves observability of the Kafka data plugin, since you can now use standard Kafka tooling to determine the status of your consuming Enterprise OPA instances, including the number of messages they lag behind.
Due to the way consumer groups work, each data plugin instance will form its own one-member consumer group. The group name includes the Enterprise OPA instance ID, which is reset on restarts. These two measures guarantee that the message consumption behaviour isn't changed: each (re)started instance of Enterprise OPA will read all the messages of the topic, unless configured otherwise.
For details, see the Kafka data source documentation.
When a data source Rego transform fails, it can be difficult to debug, even more so when it depends on hard-to-reproduce message batches coming in from Apache Kafka.
To help with this, any print() calls in Rego transforms are now emitted, even if the overall transformation failed, e.g. with an object insertion conflict.
This release includes a few new features around test generation, as well as a Regal version bump.
It is now possible to quickly spin up a test suite for a policy project with Enterprise OPA, using the new test generation commands: test bootstrap and test new.
These commands will generate test stubs that are pre-populated with input objects, based off of what keys each rule body references from the input.
While the stubs usually need some customization after generation in order to match the exact policy constraints, the generation commands remove much of the initial boilerplate work required for basic test coverage.
Given the file example.rego:
package example
import rego.v1
servers := ["dev", "canary", "prod"]
default allow := false
allow if {
input.servers.names[_] == data.servers[_]
input.action == "fetch"
}We can generate a set of basic tests for the allow rules using the command: eopa test bootstrap -d example.rego example/allow
The generated tests will appear in a file called example_test.rego, and should look roughly like the following:
package example_test
import rego.v1
# Testcases generated from: example.rego:7
# Success case: All inputs defined.
test_success_example_allow_0 if {
test_input = {"input": {}}
data.example.allow with input as test_input
}
# Failure case: No inputs defined.
test_fail_example_allow_0_no_input if {
test_input = {}
not data.example.allow with input as test_input
}
# Failure case: Inputs defined, but wrong values.
test_fail_example_allow_0_bad_input if {
test_input = {"input": {}}
not data.example.allow with input as test_input
}
# Testcases generated from: example.rego:9
# Success case: All inputs defined.
test_success_example_allow_1 if {
test_input = {"input": {"action": "EXAMPLE", "servers": {"names": "EXAMPLE"}}}
data.example.allow with input as test_input
}
# Failure case: No inputs defined.
test_fail_example_allow_1_no_input if {
test_input = {}
not data.example.allow with input as test_input
}
# Failure case: Inputs defined, but wrong values.
test_fail_example_allow_1_bad_input if {
test_input = {"input": {"action": "EXAMPLE", "servers": {"names": "EXAMPLE"}}}
not data.example.allow with input as test_input
}If we add a new rule to the policy with an OPA metadata annotation test-bootstrap-name:
# ...
# METADATA
# custom:
# test-bootstrap-name: allow_admin
allow if {
"admin" in input.user.roles
}We can then add generated tests for this new rule to the test file with the command eopa test new -d example.rego 'allow_admin'
The new test will be appended at the end of test file, and will look like:
# ...
# Testcases generated from: example.rego:17
# Success case: All inputs defined.
test_success_allow_admin if {
test_input = {"input": {"user": {"roles": "EXAMPLE"}}}
data.example.allow with input as test_input
}
# Failure case: No inputs defined.
test_fail_allow_admin_no_input if {
test_input = {}
not data.example.allow with input as test_input
}
# Failure case: Inputs defined, but wrong values.
test_fail_allow_admin_bad_input if {
test_input = {"input": {"user": {"roles": "EXAMPLE"}}}
not data.example.allow with input as test_input
}The metadata annotation allows control over test naming with both the bootstrap and new commands.
If two rules have the same metadata annotation, an error message will report the locations of the conflicts.
This release includes updates to embedded OPA and Regal versions, and various bug fixes and dependency bumps. It also include some telemetry enhancements.
This release updates the OPA version used in Enterprise OPA to v0.62.0,
and the embedded Regal version (used with eopa lint) to v0.17.0.
Previously, an extra step was necessary to have eopa run pick up DAS
libraries pulled in via eopa pull. Now, the generated configuration already
includes all the necessary settings for a seamless workflow of:
eopa login --url https://my-tenant.styra.comeopa pulleopa run --server
See How to develop and test policies locally using Styra DAS libraries for details.
Previously, Enterprise OPA would include the data.system tree in queries for
data -- either via the CLI, eopa eval data or via the HTTP API,
GET /v1/data. That isn't harmful, but it differs from what OPA does.
Now, Enterprise OPA will give the same results -- omitting data.system.
Enterprise OPA now reports on the type of bundles used: delta/snapshot and JSON or BJSON, to help prioritizing future work.
This release fixes an issue with using OPA fallback mode (when missing a license) together with bundles.
The embedded Regal version (used with eopa lint) was updated to v0.16.0.
This release addresses an issue where YAML files in a bundle could cause Enterprise OPA to return an error, particularly during eopa eval.
Enterprise OPA now integrates the powerful Regal linter for Rego policies!
For example, if you had the example policy from the Regal docs:
policy/authz.rego:
package authz
import future.keywords
default allow = false
deny if {
"admin" != input.user.roles[_]
}
allow if not denyYou can lint the policy with eopa lint as follows:
$ eopa lint policy/
Rule: not-equals-in-loop
Description: Use of != in loop
Category: bugs
Location: policy/authz.rego:8:13
Text: "admin" != input.user.roles[_
Documentation: https://docs.styra.com/regal/rules/bugs/not-equals-in-loop
Rule: use-assignment-operator
Description: Prefer := over = for assignment
Category: style
Location: policy/authz.rego:5:1
Text: default allow = false
Documentation: https://docs.styra.com/regal/rules/style/use-assignment-operator
Rule: prefer-some-in-iteration
Description: Prefer `some .. in` for iteration
Category: style
Location: policy/authz.rego:8:16
Text: "admin" != input.user.roles[_
Documentation: https://docs.styra.com/regal/rules/style/prefer-some-in-iteration
1 file linted. 3 violations found.You can now pull down policies and libraries from a Styra DAS instance, allowing easier local testing and development.
To start the process, run eopa login, like in the example below.
eopa login --url https://example.styra.com
This will bring up an OAuth login screen, which will allow connecting your local Enterprise OPA instance to your company's DAS instance.
Once your Enterprise OPA instance is authenticated, you can then pull down the policies from your DAS Workspace using eopa pull.
eopa pull
This will store the policies and library code from DAS under a folder named .styra/include/libraries by default.
This release updates the OPA version used in Enterprise OPA to v0.61.0, and includes telemetry enhancements, bug fixes, and various dependency updates.
Gigantic floating point numbers (like 23456789012E667) no longer cause a panic in the VM.
Enterprise OPA now includes the latest retrieved bundle sizes, and the number of datasource plguins that are used, to help prioritizing future work.
This release contains a bugfix for an issue where some Rego policies querying the entirety of the data namespace could see incorrect results.
These releases are release engineering improvements and fixes for our automated publishing of artifacts, such as capabilities JSON files, gRPC protobuf definitions, and more.
This is a bug fix release for an exception that occurred when using a per-output mask or drop decision that included a print() statement.
It's only relevant to you if
- you are using the
eopa_dldecision logs plugin, - with a per-output mask_decision or drop_decision,
- and that decision includes a
print()call.
This release updates the OPA version used in Enterprise OPA to v0.60.0,
and includes improvements for Decision Logging, sql.send, and the eopa eval
experience.
When you evaluate a policy, eopa eval --format=pretty will include extra links to
docs pages explaining the errors, and how to overcome them.
For example, with a policy like
# policy.rego
package policy
allow := data[input.org].allow$ eopa eval -fpretty -d policy.rego data.policy.allow
1 error occurred: policy.rego:3: rego_recursion_error: rule data.policy.allow is recursive: data.policy.allow -> data.policy.allow
For more information, see: https://docs.styra.com/opa/errors/rego-recursion-error/rule-name-is-recursive
Note that the output only appears on standard error, and only for output format
"pretty", so it should not interfere with any scripted usage of eopa eval you
may have.
Enterprise OPA lets you configure multiple sinks for your decision logs.
With this release, you can also specific per-output mask_decision and drop_decision
settings, to accomodate different privacy and data restrictions.
For example, this configuration would apply a mask decision (data.system.s3_mask)
only for the S3 sink, and a drop decision (data.system.console_drop) for the console
output.
decision_logs:
plugin: eopa_dl
plugins:
eopa_dl:
buffer:
type: memory
output:
- type: console
drop_decision: system/console_drop
- type: s3
mask_decision: system/s3_mask
# more configAlso see
- Decision Logs Configuration
- Tutorial: Logging decisions to AWS S3
- Masking and dropping decision logs from the OPA docs.
sql.send now supports Microsoft SQL Server! To connect to it, use a data_source_name of
sqlserver://USER:PASSWORD@HOST:PORT?database=DATABASE_NAME
For complete description of data_source_name options available, see: https://github.com/microsoft/go-mssqldb#connection-parameters-and-dsn
It also comes with the usual Vault helpers, under system.eopa.utils.sqlserver.v1.vault.
See the sql.send documentation
for all details.
Telemetry data sent to Styra's telemetry system now includes the License ID.
You can use eopa run --server --disable-telemetry to opt-out.
This release updates the OPA version used in Enterprise OPA to v0.59.0, and integrates some performance improvements and a few bug fixes.
- Fixed a panic when running
eopa bundle converton Delta Bundles.
- The Set and Object types received a few small performance optimizations in this release, which net out speedups of around 1-7% on some benchmarks.
- Set union operations are slightly faster now.
This release contains a security fix for gRPC handlers used with OpenTelemetry, various performance enhancements, bug fixes, third-party dependency updates, and a way to have Enterprise OPA fall back to "OPA-mode" when there is no valid license.
This release updates the gRPC handlers used with OpenTelemetry to address a security vulnerability (CVE-2023-47108, https://github.com/advisories/GHSA-8pgv-569h-w5rw).
When using eopa run and eopa exec without a valid license, Enterprise OPA will now log a message,
and continue executing as if it was an ordinary instance of OPA.
This is enabled by running the license check synchronously. It'll be quick for missing files and environment variables.
If you don't want to fallback to OPA, because you expect your license to be present and valid, you can
pass --no-license-fallback to both eopa run and eopa exec: the license validation will run asynchronously,
and stop the process on failures.
- The gRPC API's decision logs now include the
inputsent with the request. - An issue with the
mongodb.findandmongodb.find_onecaching has been resolved.
This release updates the OPA version used in Enterprise OPA to v0.58.0, and integrates several performance improvements and a bug fix:
Function calls in Rego now have their return value cached: when called with the same arguments, subsequent evaluations will use the cached value. Previously, the function body was evaluated twice.
Currently, only simple argument types are subject to caching: numbers, bools, strings -- collection arguments are exempt.
If your policy does not make use of any of the data.system.eopa.utils helpers of Enterprise OPA's
builtin functions, they are not loaded,
and thus avoid superfluous work in the compiler.
When evaluating a policy, certain compiler stages in OPA are now skipped: namely, the Rego VM in Enterprise OPA does not make use of OPA's rule and comprehension indices, so we no longer build them in the compiler stages.
The Rego VM now uses less allocations, improving overall performance.
Fixes a bug with "Preview Selection".
This is a bug fix release addressing the following security issue:
OpenTelemetry-Go Contrib security fix CVE-2023-45142:
Denial of service in otelhttp due to unbound cardinality metrics.
Note: GO-2023-2102 was fixed in v1.11.0
A malicious HTTP/2 client which rapidly creates requests and immediately resets them can cause excessive server resource consumption.
This release includes several bugfixes and a powerful new feature for data source integrations: Rego transform rules!
Enterprise OPA now supports Rego transform rules for all data source plugins! These transform rules allow you to reshape and modify data fetched by the data sources, before that data is stored in EOPA for use by policies.
This feature can be opted into for a data source by adding a rego_transform key to its YAML configuration block.
For this example, we will assume we have an HTTP endpoint that responds with the following JSON document:
[
{"username": "alice", "roles": ["admin"]},
{"username": "bob", "roles": []},
{"username": "catherine", "roles": ["viewer"]}
]Here's what the OPA configuration might look like for a fictitious HTTP data source:
plugins:
data:
http.users:
type: http
url: https://internal.example.com/api/users
method: POST # default: GET
body: '{"count": 1000}' # default: no body
file: /some/file # alternatively, read request body from a file on disk (default: none)
timeout: "10s" # default: no timeout
polling_interval: "20s" # default: 30s, minimum: 10s
follow_redirects: false # default: true
headers:
Authorization: Bearer XYZ
other-header: # multiple values are supported
- value 1
- value 2
rego_transform: data.e2e.transformThe rego_transform key at the end means that we will run the data.e2e.transform Rego rule on the incoming data before that data is made available to policies on this EOPA instance.
We then need to define our data.e2e.transform rule.
rego_transform rules generally take incoming messages as JSON via input.incoming and return the transformed JSON for later use by other policies.
Below is an example of what a transform rule might look like for our HTTP data source:
package e2e
import future.keywords
transform.users[id] := d {
some entry in input.incoming
id := entry.username
d := entry.roles
}In the above example, the transform policy will to populate the data.http.users object with key-value pairs.
Each key-value pair will be generated by iterating across the JSON list in input.incoming, and for each JSON object, the key will be taken from the username field, and the value from the roles field.
Given our earlier data source, the result stored in EOPA for data.http.users will look like:
{
"alice": ["admin"],
"bob": [],
"catherine": ["viewer"]
}This general pattern applies to all the data source integrations in Enterprise OPA, including the Kafka data source (covered below).
The Kafka data source now supports the new rego_transform rule system, similar to the other major data source integrations.
The main difference for new message transformation rules is the use of specialized variables to refer to new and existing Kafka data: input.incoming and input.previous.
input.incoming represents the batch of incoming new Kafka messages, and input.previous refers to everything stored previously by the Kafka data source.
This allows constructing data source transform rules in a straightforward way.
See the Reference documentation for more details and examples of the new transform rules.
In this release dynamodb.send has been split apart into more specialized variants embodying the same functionality: dynamodb.get and dynamodb.query.
For normal key-value lookups in DynamoDB, dynamodb.get provides a straightforward solution.
Here is a brief usage example:
thread := dynamodb.get({
"endpoint": "dynamodb.us-west-2.amazonaws.com",
"region": "us-west-2",
"table": "thread",
"key": {
"ForumName": {"S": "help"},
"Subject": {"S": "How to write rego"}
}
}) # => { "row": ...}See the Reference documentation for more details.
For queries on DynamoDB, dynamodb.query allows control over the query expression and other parameters:
Here is a brief usage example:
music := dynamodb.query({
"region": "us-west-1",
"table": "foo",
"key_condition_expression": "#music = :name",
"expression_attribute_values": {":name": {"S": "Acme Band"}},
"expression_attribute_names": {"#music": "Artist"}
}) # => { "rows": ... }See the Reference documentation for more details.
It is now possible to use a single MongoDB collection as a data source, with optional filtering/projection at retrieval time.
For example if you had collection1 in a MongoDB instance set to the following JSON document:
[
{"foo": "a", "bar": 0},
{"foo": "b", "bar": 1},
{"foo": "c", "bar": 0},
{"foo": "d", "bar": 3}
]If you configured a MongoDB data source to use collection1:
plugins:
data:
mongodb.example:
type: mongodb
uri: <your_db_uri_here>
auth: <your_login_info_here>
database: database
collection: collection1
keys: ["foo"]
filter: {"bar": 0}The configuration shown above would filter this collection down to just:
[
{"foo": "a", "bar": 0},
{"foo": "c", "bar": 0}
]The keys parameter in the configuration shown earlier guides how the collection is transformed into a Rego Object, mapping the unique key field(s) to the corresponding documents from the filtered collection:
{
"a": {"foo": "a", "bar": 0},
"c": {"foo": "c", "bar": 0}
}You could then use this data source in a Rego policy just like any other aggregate data type. As a simple example:
package hello_mongodb
filtered_documents := data.mongodb.example
allow if {
count(filtered_documents) == 2 # Want just 2 items in the collection.
}This release updates the OPA version used in Enterprise OPA to v0.57.0, and integrates several bugfixes and new features.
These releases have been release engineering fixes to sort out automated publishing of this changelog, capabilities JSON files, and gRPC protobuf definitions.
This release updates the OPA version used in Enterprise OPA to v0.56.0, and integrates several bugfixes and new features.
Enterprise OPA now supports querying MongoDB databases!
Two new builtins are dedicated for this purpose: mongodb.find, and mongodb.find_one. These correspond approximately to MongoDB's db.collection.find() and db.collection.findOne() operations, respectively. These operations make it possible to integrate MongoDB databases efficiently into policies, depending on whether a single or multiple document lookup is needed.
Find out more in the new Tutorial, or see the Reference documentation for more details.
This builtin currently supports sending GetItem and Query requests to a DynamoDB endpoint, allowing direct integration of DynamoDB into policies.
Find out more in the new Tutorial, or see the Reference documentation for more details.
This new builtin provides support for more direct, request-oriented Hashicorp Vault integrations in policies than was previously possible through the EKM Plugin.
See the Reference documentation for more details.
The gRPC server plugin now integrates into Enterprise OPA's decision logging! This means that gRPC requests are logged in a near-identical format to HTTP requests, allowing deeper insight into the usage and performance of Enterprise OPA deployments in production.
This release updates the OPA version used in Enterprise OPA to v0.55.0.
This release makes Styra Enterprise OPA a drop-in replacement for opa-envoy-plugin, to be used with the External Authorization feature of the popular Envoy API gateway, and Envoy-based service meshes such as Istio and Gloo Edge.
It works exactly like opa-envoy-plugin``, i.e. the images known as openpolicyagent/opa:latest-envoy`,
but featuring all the Enterprise OPA enhancements.
See here for a general introduction to OPA and Envoy.
Styra Enterprise OPA now supports OpenTelemetry Traces for the following operations:
- Rego VM evaluations, with extra spans for
http.sendandsql.send - All decision log operations.
- All of its gRPC handlers.
This allows for improved observability, allowing you to quicker pin-point any issues in your distributed authorization system.
This release updates the OPA version used in Styra Enterprise OPA to v0.54.0, along with gRPC plugin improvements and new gRPC streaming endpoints.
Most gRPC implementations default to having a max receivable message size of 4 MB for both servers and clients. This helps avoid memory exhaustion from large messages sent by misconfigured or malicious actors on the other side of the connection.
This size limit presents a problem for Enterprise OPA though: a relatively simple rule query that returns a large amount of data can easily break past that 4 MB message size limit. Additionally, clients who need to provide more than 4 MB of data for a data update or rule query input can also run into the receivable message size limit. To work around this problem, we have to attack it from both the client and server sides.
On the client side, most gRPC implementations allow providing the "Max Receive Message Size" as a parameter for the gRPC call. (See the CallOption.MaxRecvMsgSize option in Go, for example.)
This means that clients who want to receive potentially massive responses from the Enterprise OPA server will need to do a little more setup at call time, but don't necessarily need to change their Enterprise OPA configs.
For the server side of the problem, we changed Enterprise OPA to support a new configuration option for the gRPC plugin: grpc.max_recv_message_size
In the example configuration below, we start up the Enterprise OPA gRPC server on localhost:9090, and set it to receive messages up to 8 MB in size:
plugins:
grpc:
# 8 MB, in bytes:
max_recv_message_size: 8589934592
addr: "localhost:9090"This allows the server to receive larger gRPC messages from clients than before.
Fixing both sides of the large gRPC message size problem allow for high-throughput and data-heavy use cases over the gRPC API that were not possible before.
The Data and Policy gRPC services now provide bidirectional streaming endpoints!
These endpoints work similarly to the experimental BulkRW endpoint that was explored in earlier versions of Enterprise OPA, and provide several speed and efficiency benefits over the REST API or existing unary gRPC endpoints.
They provide fixed-structure transactions that describe batches of CRUD operations, where all "write" operations (that would cause changes to the Data and Policy stores) are run as a single, sequential write transaction first, and then all "read" operations, such as rule queries, are evaluated in parallel. If any write operations fail, the entire request fails. Read operations have their failures reported as normal response messages with error-wrapping message types.
These batched operations can provide substantial throughput improvements over using the existing unary gRPC endpoints:
- The connection cost is paid once at the start of the stream, instead of once per call.
- Read and write operations enjoy greatly reduced contention for access to the Data and Policy stores.
- Some operations are able to be parallelized.
For styles of API access where the successes and failures of write operations should be independent of one another, callers can send several smaller messages over the stream, and will receive back individual successful responses, or error messages for each failure that occurs.
See the Enterprise OPA gRPC docs on the Buf Schema Registry for more details.
This release fixes a typographical error in the protobuf markdown introduced when renaming Enterprise OPA.
This release changes the name of Styra Load to Styra Enterprise OPA.
This release updates the OPA version used in Styra Load to v0.53.1.
This release features a long-sought-after new built-in: sql.send!
The new builtin in Styra Load, sql.send, can be considered http.send's relational cousin:
It allows you to run any kind of custom query against a relational database management system, including
- PostgreSQL
- MySQL
- SQLite
This is an example call, querying a SQLite database with a parametrized SQL query:
subordinate := sql.send({
"driver": "sqlite",
"data_source_name": "sqlite://data/company.db",
"query": "SELECT * FROM subordinates WHERE manager = $1 AND subordinate = $2",
"args": [input.user, username],
})
count(subordinate.rows) > 0 # Make sure the row exists in the subordinates table.Just like http.send, it allows you to pull in the most recent data you have in your database
when it's relevant for your policy decision.
Find out more in the new tutorial.
You can now send decision logs to S3-compatible stores.
Find out more in the new tutorial.
It is now possible to sign up for a free trial directly through the Styra Load CLI.
Running load license trial will collect all required information and generate a
new license key, which can be used to activate Styra Load immediately.
This release includes OPA v0.53.0. See the release notes for details.
This release unveils two new feature sets, and includes some smaller quality-of-life improvements:
The Styra Load Vault integration can be used to:
- Retrieve the Styra Load License key from a Vault secret
- Override the configuration for a Styra Load service or key configuration
- Override the configuration of
http.send
See the documentation for more details.
Styra Load now features its own decision logging infrastructure! It gives you extra flexibility, and a multitude of new sinks, including Apache Kafka and Splunk.
Find out more about this by following the tutorial.
- The Git data source now allows configuring a
branch. - The S3 data source now lets you provide an
endpoint. This enables you to work with other S3-compatible APIs, like MinIO.
This release contains an update to the latest version of OPA (v0.52.0), as well as bugfixes and performance improvements.
- LIA: Output now displays time values in human-friendly units, instead of always nanoseconds.
- Small performance improvements around internal string caching.
- Improved logging around licensing errors.
data: Plugin now detects and errors when a bundle's roots would clash with the namespace owned by adataplugin.
This release includes a host of runtime performance improvements, bugfixes, and a new gRPC plugin. Startup times have also been dramatically improved over older releases, thanks to upstream fixes in some of our dependencies.
Load now supports gRPC versions of OPA's Policy and Data REST APIs, as well as a new experimental bulk operations API.
The gRPC server is enabled via the grpc plugin.
The plugin can be enabled in your Load config file like so:
plugins:
grpc:
addr: ":9090"Or if you prefer the CLI, try: load run -s --set plugins.grpc.addr=:9090
In addition to the normal Load HTTP server, this will start up an unsecured gRPC server on the port you specified in the plugin's options. This mode is great for testing with tools like grpcurl, but we strongly recommend that you protect your gRPC server using one of the TLS options detailed below if you intend to make the gRPC port visible to other systems.
To secure the gRPC server, server-side TLS support is available.
Given the files cert.pem and key.pem, you could configure your Load instance to secure your gRPC connections like so:
plugins:
grpc:
addr: ":9090"
tls:
cert_file: "cert.pem"
cert_key_file: "key.pem"For additional security, mutual TLS (mTLS) connections can be used, where the client must present a certificate signed by the same Root CA as the server's certificate.
Given the root CA file ca.pem, we can add on to the configuration example for server-side TLS, and require clients to authenticate themselves using mTLS:
plugins:
grpc:
addr: ":9090"
authentication: "tls"
tls:
cert_file: "cert.pem"
cert_key_file: "key.pem"
ca_cert_file: "ca.pem"Any client whose certificate was signed with ca.pem will be able to authenticate to the server.
All others will get disconnections or TLS errors.
- Improved iteration speeds over large Rego Object types.
- Improved memory efficiency via interning for some types.
- Fixed a minor Rego incompatibility to match OPA's behavior.
- Performance improvements for queries of "all of
data", likeload eval [...] dataorGET /v1/datawith Load's API. - Fix bug when referencing a bundle via
load eval bundle.tar.gz(without explicitly loading it as a bundle via-b). This ensures compatibility with how OPA operates in these circumstances. - Restructure parts of the gRPC API to make it more resource-focussed.
- Change the exit code for license validation related errors from 2 to 3 -- to differentiate them from any other errors.
This release marks the first general availability release of Styra Load. Load provides a number of improvements over open source OPA, including:
- Optimizations (CPU/Memory use)
- Datasource integrations
- Live Impact Analysis
- This release is a release engineering fix to sort out part of our gRPC documentation system.
- Fix
--disable-telemetrybeing ignored forload run --server. - Use
google.protobuf.Valueandgoogle.protobuf.Structin the gRPC API instead of raw JSON strings. - Further performance improvements to the Rego VM and bundle loading.
- Fix
load bundle convertregression
These releases have been release engineering fixes to sort out MacOS binary signing of published executables.
load evalnow has a CLI flag for changing the instruction limit.- Various BJSON bundle loading issues have been identified and fixed.
- Data paths controlled by data plugins are now protected from manual updates via the API.
load versionhas been revamped.- Windows users may have a better CLI experience now, as a superfluous user information lookup has been removed.
- Further performance improvements to the Rego VM.
- Updated the internal OPA version to v0.50.2.
- Various other third-party dependency bumps.
- Fixed a hang triggered by sending the gRPC
BulkRWendpoint multiple blank messages in sequence.
- Updated the internal OPA version to v0.50.0. See the OPA Release Notes for details.
- Live Impact Analysis can now be used from the CLI:
load liactl record. Seeload liactl help record. - Performance improvements to the Rego VM.
- Capabilities: Load now includes OPA-compatible capabilities data.
- Build: Load container images now include SBOM data.
- Various other third-party dependency bumps.