OPA Version Migration Guide
Overview
Starting with OPAL v0.9.x, OPAL now ships with OPA v1 by default and supports both OPA v0 and OPA v1 compatibility modes. This guide explains how to migrate your Rego policies from OPA v0 to OPA v1 while ensuring a smooth transition.
What's Changed in OPA v1
OPA v1 introduces several breaking changes that affect how Rego policies are written:
- Package declarations: In OPA v0, you could write
package authzor justpackage authz. In OPA v1, you must usepackage authz.v1(with a version suffix). - Rule declarations: Rules now require explicit package versioning.
- Import statements: Import paths have changed to be more explicit.
- Built-in functions: Some built-in functions have been renamed or deprecated.
For more information, see OPA v1 Migration Guide.
Migration Strategy
OPAL provides a gradual migration path:
- Enable v0 compatibility mode (default in OPAL v0.9.x)
- Test your policies with v0 compatibility enabled
- Migrate your policies to OPA v1 format
- Disable v0 compatibility mode when ready
Step 1: Enable v0 Compatibility Mode
By default, OPAL v0.9.x enables v0 compatibility mode automatically. This means:
- OPA will accept both v0 and v1 syntax
- You can run your existing policies without immediate changes
- The
--v0-compatibleflag is automatically added to OPA
Configuration
The v0 compatibility mode is controlled by the OPAL_OPA_V0_COMPAT setting:
# Enable v0 compatibility (default in v0.9.x)
export OPAL_OPA_V0_COMPAT=true
# Disable v0 compatibility
export OPAL_OPA_V0_COMPAT=false
This setting merges with the inline OPA configuration:
# You can also set it in the inline OPA config
export OPAL_INLINE_OPA_CONFIG='{"v0_compatible": true}'
Note: If either OPAL_OPA_V0_COMPAT or OPAL_INLINE_OPA_CONFIG.v0_compatible is true, the --v0-compatible flag will be added to OPA.
Step 2: Test Your Current Policies
With v0 compatibility enabled, verify that your existing policies work correctly:
- Start OPAL with your current policies
- Test authorization queries
- Check that all expected functionality works
Step 3: Migrate Your Policies
Basic Package Migration
OPA v0 syntax:
package authz
default allow = false
allow {
input.user == "admin"
}
OPA v1 syntax:
package authz.v1
default allow := false
allow if {
input.user == "admin"
}
Key Changes to Make:
- Add
.v1suffix to package declarations - Replace
=with:=for assignments - Replace
ifstatements with guard syntax - Update import paths to include version suffixes
Example Migration
Here's a more complex example:
Before (OPA v0):
package authz
import data.users
default allow = false
allow {
user := data.users[input.user]
user.role == "admin"
input.action == "delete"
}
has_permission[user] {
user := data.users[input.user]
user.role == "admin"
}
After (OPA v1):
package authz.v1
import data.users
default allow := false
allow if {
user := data.users[input.user]
user.role == "admin"
input.action == "delete"
}
has_permission contains user if {
user := data.users[input.user]
user.role == "admin"
}
Step 4: Disable v0 Compatibility Mode
Once you've migrated all your policies:
- Set
OPAL_OPA_V0_COMPAT=falseor remove the setting (it defaults tofalsein v0.10.0+) - Remove
v0_compatible: truefrom yourOPAL_INLINE_OPA_CONFIG - Restart OPAL to apply the changes
Migration Timeline
- OPAL v0.9.x:
OPAL_OPA_V0_COMPATdefaults totruefor easier migration - OPAL v0.10.0+:
OPAL_OPA_V0_COMPATwill be unconfigured (effectivelyfalse) by default
OPA bundled in the client image
The permitio/opal-client image ships the OPA binary that runs as the inline engine. OPAL images released after 0.10.0-rc.2 ship OPA 1.21.4; earlier images shipped OPA 1.9.0. OPA tightened its compiler between those versions, so a policy that loaded on the old image can be rejected when the client loads it on the new one, with or without v0 compatibility mode:
- OPA 1.19.0: stricter safety for
:=. The right-hand side of an assignment is now a read. A policy that bound a variable backwards through:=(for examplex := y; x = 7, withynever assigned) now fails withrego_unsafe_var_error. See the 1.19.0 release notes. - OPA 1.20.0: new
andandorkeywords.import future.keywordsnow imports them too, so a policy with that import that usesandororas a name no longer parses. See the 1.20.0 release notes. - OPA 1.21.0: empty composite literals are typed as empty, and
inis type-checked.{},[]andset()no longer have the type of "any collection", so selecting from or iterating one is a type error at compile time, and so is aninwhose element can't be in the collection's type. See the 1.21.0 release notes.
Before upgrading, run the new OPA's checker against your policy repository:
docker run --rm -v "$PWD:/policy" openpolicyagent/opa:1.21.4-static check /policy
# if you run with OPAL_OPA_V0_COMPAT=true:
docker run --rm -v "$PWD:/policy" openpolicyagent/opa:1.21.4-static check --v0-compatible /policy
A policy that fails here would fail to load in the new client image. Fix it first, or stay on the previous image until you have.
Not caught by opa check. Two changes reject nothing at compile time, so check them by hand:
- OPA 1.21.0 parses YAML with the YAML 1.2 core schema. Unquoted
y,n,yes,no,onandoffused to be booleans and are now strings (trueandfalseare unaffected). Policies still compile, but a rule such asdeny if data.flags.block == truestops matching when the YAML saysblock: yes, so a decision can change without any error. Search the policy repository foryaml.unmarshal, and for those unquoted words in YAML that OPA reads (data files, bundles, config), then quote them or usetrue/false. - OPA 1.21.3 changes bundle signing. If you pass OPA a config file (
OPAL_INLINE_OPA_CONFIG,config_file) with asigningblock: signatures are now required whenever the block is present, even withoutkeyid, and asigningblock with no entries under the top-levelkeysis now a startup error.
For the full list, read OPA's changelog from 1.10.0 to 1.21.4.
Troubleshooting
Common Migration Issues
- Package not found errors: Make sure to add
.v1suffix to package declarations - Syntax errors: Update
=to:=and use guard syntax forifstatements - Import errors: Update import paths to include version suffixes
Debugging Tips
- Check OPA logs for detailed error messages
- Use OPA's playground to test individual policies
- Enable verbose logging during migration:
export OPAL_INLINE_OPA_LOG_FORMAT=full
Rollback Plan
If you encounter issues:
- Re-enable v0 compatibility mode:
export OPAL_OPA_V0_COMPAT=true
- Restart OPAL
- Fix any remaining policy issues
- Try migration again