permitio/opal: keeping OPA and Cedar policy agents in sync
Policy and data administration, distribution, and real-time updates on top of Policy Agents (OPA, Cedar, ...)
At a glance
- What is it?
- OPAL is an administration layer that watches policy and data sources and pushes live updates to Policy Agents. It fits teams running OPA or Cedar across many services, and it assumes you already have a policy engine to feed.
- Who is it for?
- Adopt OPAL if you run more than a handful of OPA or Cedar agents and policy or data changes arrive faster than a redeploy cycle can carry them. Skip it if you have one policy agent, no external data source to watch, or no appetite for running a server, a websocket channel and clients as separate moving parts.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What OPAL adds on top of OPA and Cedar
OPA decouples policy from code, but it does not by itself tell you when policy or the data behind it has changed. The README frames OPAL as the layer that closes that gap, detecting changes to policy and policy data in realtime and pushing live updates to your agents. The intended audience is anyone running authorization as a service: microservice fleets where each service embeds a policy engine, and where an access decision may depend on data that lives in an API, a database, git, S3 or a third-party SaaS product. The README lists four use cases, and they share one shape. You have many policy engines, they need the same policy bundle, and the data underneath that bundle changes between deploys. OPAL is for that, not for evaluating a policy. It never answers an authorization question.
Server, client and the websocket PubSub channel
The architecture is client-server and stateless. OPAL Servers publish policy and data updates over a lightweight websocket PubSub channel. OPAL clients subscribe to that channel via topics. The part worth reading twice is what happens after a notification: each client fetches data directly from the source and loads it into its managed Policy Engine instance. The server is a signal, not a proxy. That choice keeps the server off the data path, so a large data set is not streamed through it, but it also means every client needs network reachability and credentials for every source. In a segmented network that is the constraint that decides whether OPAL is workable. The README describes the server as stateless, which is what allows more than one and makes the deployment pattern a normal horizontally scaled service rather than a singleton. Topics let a client subscribe to a subset, which is how the README's promise of syncing services with only the data they need is meant to be read.
Installing OPAL and running the docker-compose example
The README gives two distribution paths: Python packages with a built-in CLI, and pre-built Docker images. The Makefile names the package targets explicitly: install-client-from-src and install-server-from-src, plus docker-build-client and docker-run-server. For a first real use, the README's TL;DR downloads a working server and client configuration and starts it. Run this in an empty directory:
curl -L https://raw.githubusercontent.com/permitio/opal/master/docker/docker-compose-example.yml \
> docker-compose.yml && docker compose upWhat you should see is both containers starting and the client logging its subscription and its fetch from the policy store. The Makefile's defaults hint at the wiring: OPAL_SERVER_URL defaults to http://host.docker.internal:7002, and OPAL_POLICY_STORE_URL defaults to http://host.docker.internal:8181, which is the conventional OPA port. The server port 7002 is the one to expose to clients. The README also points at a live playground environment in docker-compose and a getting started guide for containers, and says a Helm chart exists at permitio/opal-helm-chart for Kubernetes. Those are the paths to follow once the example runs, because the example is a demo configuration rather than a production topology.
The client does the fetching, and that is the failure mode
Because clients pull from sources directly, a client that loses its credentials fails silently in the sense that matters: it keeps serving its last loaded policy and data. Nothing in the README describes a staleness alarm or a rollback to a previous bundle, and the README does not document rollback at all. If an authorization decision depends on data that changed an hour ago, a disconnected client will keep answering from the old state until it reconnects. The same architecture makes OPAL the wrong tool for a single policy agent with a static policy bundle: you would be adding a server, a websocket dependency and a client process to solve a problem a file copy already solves. It is also the wrong tool if your policy store cannot be watched. OPAL needs a source it can poll or be notified by, and the README's list of sources is APIs, DBs, git, S3 and third-party SaaS services, not an arbitrary internal system.
OPAL compared with a CI pipeline that pushes bundles
The obvious alternative is a deployment pipeline: build the bundle, push it to each OPA instance, restart or reload. That approach has one moving part fewer and no long-lived connection to keep alive, and for policy that changes on a release cadence it is genuinely simpler. The difference is where the change originates. A pipeline reacts to a merge or a deploy; OPAL reacts to the policy store and to the data sources themselves. If your authorization data changes because a user was added to a group in your own API, a pipeline has nothing to trigger on unless you build the trigger. OPAL is that trigger. The cost is the reverse of the pipeline's: OPAL adds a runtime dependency that must be up when data changes, while a pipeline adds latency between the change and the agents seeing it. Pick based on whether the data or the code is the thing that moves.
Maintenance, packaging and the Apache-2.0 licence
The repository is not archived, and the last push was on 2026-09-22. Release 0.9.9 landed on 2026-08-27, with 0.9.9-rc.3 and 0.9.9-rc.2 before it in August 2026, so the project is still cutting releases and the version string is pre-1.0. Treat that as a signal about upgrade cost: pre-1.0 releases can change configuration between minor versions, and OPAL is deployed as three packages (opal-common, opal-client, opal-server) that the requirements.txt installs together from local paths, so the three versions move as a set. Pinning all three to the same version is the safe habit. The licence is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant; it also requires that you preserve notices and state significant changes. The README does not discuss any commercial edition or licence exception, so there is nothing here that would push a team toward a paid tier. This is not legal advice; if you redistribute OPAL inside a product, have counsel read the NOTICE and patent clauses rather than the summary.
What to check before you put OPAL in front of production traffic
Three things decide whether OPAL fits, and none of them are answered by the README. First, can every client reach every data source directly? The client fetches, so a client in a private subnet needs egress to each source, not just to the server. Second, how long can a client serve stale data? The README describes realtime updates but not a staleness bound or a health signal for a client that has fallen behind. Third, how do you authenticate clients to the server? The Makefile references OPAL_AUTH_PRIVATE_KEY and OPAL_AUTH_PUBLIC_KEY pointing at /root/ssh/opal_rsa and /root/ssh/opal_rsa.pub, which shows key-based authentication is part of the configuration, but key rotation and token lifetime are not covered in the README. The documentation site at docs.opal.ac is where those answers live, and the getting started guide for containers is the right next read after the compose example.
Editorial conclusion
Adopt OPAL if you run more than a handful of OPA or Cedar agents and policy or data changes arrive faster than a redeploy cycle can carry them. Skip it if you have one policy agent, no external data source to watch, or no appetite for running a server, a websocket channel and clients as separate moving parts. Before committing, verify three things in your own environment: that your policy store is one OPAL can poll or be notified by, that your clients can reach the data sources directly because the client does the fetching, and that token expiry and client reconnect behaviour are acceptable for your longest-lived agent. The quickstart docker-compose file is the cheapest way to check all three.
Frequently asked questions
What does permitio/opal do?
It is an administration layer for policy engines such as Open Policy Agent and Cedar Agent. It detects changes to policy and policy data and pushes live updates to the agents, so each service stays in sync with the authorization data it needs.
What company is behind permitio/opal?
The repository is owned by Permit.io, and the README states that OPAL is used as the core engine of the Permit.io Authorization Service. The project is published under the Apache-2.0 licence.
What is permitio/opal software?
OPAL is an Open Policy Administration Layer: a client-server, stateless system that publishes policy and data updates over a websocket PubSub channel and lets clients load them into a managed policy engine instance.
What is an open policy agent?
Open Policy Agent is a policy engine that decouples policy from code. OPAL is described as an administration layer for policy engines such as OPA, keeping those agents up to date in realtime.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/permitio-opal)