A little over a year ago, we created the OPCR project to bridge the gap between Open Policy Agent and the Open Container Initiative. We wanted to be able to build OPA policies into immutable images, which can be tagged, versioned, and signed just like any OCI image.
OPCR consisted of three initiatives:
We’re excited to report that in December 2022, the CNCF has accepted OPCR, and specifically the policy CLI, as a Sandbox project! ✅
Back in May 2022, the OPA project accepted our contribution of (3), and now OPA can natively consume images built with the policy CLI! ✅ ✅
Finally, as more registries have added support for OCI v2 artifacts, including AWS ECR, Docker Hub, GitHub Container Registry, and Google Container Registry, we decided that maintaining a purpose-built registry for policy images is no longer necessary.
Therefore, we’re planning on retiring the Open Policy Registry (currently hosted at opcr.io) on January 31, 2023.
The opcr.io domain, as well as the github opcr-io organization, will transfer to the CNCF, and will host the Open Policy Containers project (now focused entirely on the policy CLI).
Moving from opcr.io to gcr.io, ghcr.io, or any other OCI v2-compliant container registry is straightforward - please reach out to us in the community slack if you need any help!
For example, to move your content from opcr.io to ghcr.io:
echo $PAT | policy login -s ghcr.io -u <username> -–password-stdin
policy pull opcr.io/<account>/<policy-name>:<tag>
policy tag opcr.io/<account>/<policy-name>:<tag> ghcr.io/<account>/<policy-name>:<tag>
policy push ghcr.io/<account>/<policy-name>:<tag>
For Aserto users, we will continue to maintain the Aserto Policy Registry (registry.prod.aserto.com), and you can continue to use the policy CLI with that registry.
We're excited how far we've come over the last year in getting OPA to natively consume policies packaged as OCI images. If you have any feedback or requests, don't hesitate to open an issue!
As of version v0.40.0, OPA can now consume policy bundles packaged as OCI images. This allows building and tagging OPA policies just like docker containers, including using tools like cosign to sign those images and verify the signatures.
OCI images can be built using the policy CLI, part of the Open Policy Containers project.
Read on for more details!
The policy CLI tool can be easily used to build and push a policy to a remote OCI registry using just two simple commands:
policy build <path_to_src> -t <org>/<repo>:<tag>policy push <registry>/<org>/<repo>:<tag>A full tutorial is available here.
The services configuration documentation for OPA now includes a parameter defined as type to allow users to configure OCI compatible service registries.
Example of using a public policy image configuration with the bundle plugin from Open Policy Registry:
config.yaml
---
services:
open-policy-registry:
url: https://opcr.io
type: oci
bundles:
authz:
service: open-policy-registry
resource: opcr.io/aserto-templates/peoplefinder-rbac:1.0.0
persist: true
polling:
min_delay_seconds: 3
max_delay_seconds: 5
persistence_directory: /tmp/opa
Example of running an OPA instance from the command line using the opa CLI:
opa run -c config.yaml
Once the interactive terminal starts you will receive a log message that your configured plugin will download the OCI image from the configured registry and it will allow you to check the policy.
GitHub Packages is a platform that allows you to host and maintain packages and containers. The Policy CLI is a tool that can be used for building, versioning, and publishing your authorization policies. It uses OCI standards to manage artifacts, and the Open Policy Agent (OPA) to compile and run (For more instructions for downloading and using the Policy CLI head to our documentation).
You can now use the Policy CLI to manage your policy images with GHCR as well as the Open Container Registry. In this post, we’ll walk through using the Policy CLI with GHCR.
To log in to the Policy CLI using your Github Packages credentials, use the following command:
policy login -s ghcr.io -u <username>
This command will ask for the password, you can use your Github PAT to authenticate to GHCR if you have it enabled for your account. After authentication, the CLI will offer to set this server as your default registry. We recommend you set it as the default to make usage easier for the next couple of commands.
If you already have an image in your local registry that you want to push to GHCR you will need to first tag the image correctly before pushing. The structure of the image label is as follows:
<org>/<repo>:<tag>
Example:
Your local registry contains a built image that was tagged john/myapp:rbac.
If you want to push this same image from your local registry to ghcr.io, so you should tag this image with the command:
policy tag john/myapp:rbac ghcr.io/<myusername_or_org>/myapp:rbac
After tagging your image, you can push it to ghcr.io using the command:
policy push ghcr.io/<myusername_or_org>/myapp:rbac
Following the example mentioned above, if you want to remove this image from your local storage you can use the command:
policy rm ghcr.io/<myusername_or_org>/myapp:rbac
Once you have a container package with your authorization policy, you can pull the image using the following command:
policy pull ghcr.io/<myusername_or_org>/myapp:rbac
To check whether your pulled image is working as intended you can use the following command to open an interactive OPA shell:
policy repl ghcr.io/<myusername_or_org>/myapp:rbac
The following command will fetch the container packages stored in ghcr.io and will display a table with the available images:
policy remote images -o <myusername_or_org>
GHCR has a couple of limitations regarding package removal that need to be taken into consideration:
policy rm -r -a <image>).Assuming you want to remove the image mentioned in the example above, you can run the following command to remove the container image:
policy rm -r -a ghcr.io/<myusername_or_org>/myapp:rbac
Although the CLI contains a command to change the visibility of an upstream image, at the moment GHCR does not allow this operation through an API. Currently, we recommend using the web UI to change a package’s visibility.
]]>OPA is used to enforce policies in many contexts, including microservices, Kubernetes, CI/CD pipelines, and API gateways. Having a single engine and language for handling authorization policies across the stack is a huge advantage for developers: it allows for policy reuse and makes testing, automation, and maintenance easier.
OPA policies are written in Rego and then bundled into a compressed tarball. The tarball is then loaded into the target environment, where the policy is enforced.
We believe that OPA’s distribution workflow could be enhanced and improved by integrating it with two Linux Foundation OSS projects: OCIv2 - the industry standard for container image formats, and Sigstore, an open and pluggable standard for code signing.
Three interconnected concerns need to be addressed as part of the policy-as-code workflow: versioning, signing, and sharing.
Currently, there’s no prescribed mechanism or convention for versioning OPA bundles. You could come up with your own naming convention. You could also version the bundle by adding the version information in its manifest file. Using a naming convention is helpful but can’t be standardized or enforced. Leveraging the manifest file within the policy bundle means that whenever you try to resolve what version has been deployed or is currently running, you have to crack open the tarball to retrieve the version information.
That’s where the OCIv2 standard comes in: by wrapping policy bundles with an OCI container, we can add a layer of metadata, including version information and tags. So now, our policy images can be indexed and searched without requiring extracting the bundle's content. With searchable indexes, policy images become easily discoverable and shareable.
The OCI wrapper provides us with an immutable artifact, further increasing our confidence that we precisely know what we’re running or deploying. In addition, using an OCI wrapper means we can effectively utilize the cosign signing tool by Sigstore, an open-source project _dedicated _to code signing. The advantages of using an industry-standard solution over a home-grown, custom solution are clear. Given that OPA’s mission doesn’t revolve around signing, we think using Sigstore for this purpose makes a lot of sense.
Using the OCI standards allows us to leverage a well-established workflow - the same one developers know and love using Docker.

The process follows the familiar build -> tag -> push -> pull pattern. When needed, we can use cosign to sign the policy image.
policy CLIThe policy CLI works with any artifact registry that supports OCI containers as a media type. Using the policy CLI is very similar to using the Docker CLI. Here are some examples:
$ policy build . -t omrigazitt1/peoplefinder:1.0.0
Created new image.digest: sha256:84dbd4e3b5572dd2f23c3c987c89443fdcb57af87d714ea296fc552192fb17e9
Tagging image.reference: omrigazitt1/peoplefinder:1.0.0
$ policy tag omrigazitt1/peoplefinder:1.0.0 omrigazitt1/peoplefinder:latest
Tagging image.reference: omrigazitt1/peoplefinder:latest
$ policy push omrigazitt1/peoplefinder:1.0.0
Resolved ref [opcr.io/omrigazitt1/peoplefinder:1.0.0].digest: sha256:84dbd4e3b5572dd2f23c3c987c89443fdcb57af87d714ea296fc552192fb17e9
Pushed ref [opcr.io/omrigazitt1/peoplefinder:1.0.0].digest: sha256:05e6ed84d86f6a252e24f33cb12138d9193780f1d89a1b2ff14ced315fdf8481
$ cosign sign --key cosign.key opcr.io/omrigazitt1/peoplefinder:1.0.0
Enter password for private key: Pushing signature to: opcr.io/omrigazitt1/peoplefinder:sha256-05e6ed84d86f6a252e24f33cb12138d9193780f1d89a1b2ff14ced315fdf8481.sig
$ policy pull omrigazitt1/peoplefinder:1.0.0
Pulling.ref: omrigazitt1/peoplefinder:1.0.0
Pulled ref [opcr.io/omrigazitt1/peoplefinder:1.0.0].digest: sha256:84dbd4e3b5572dd2f23c3c987c89443fdcb57af87d714ea296fc552192fb17e9
$ policy save omrigazitt1/peoplefinder
Resolved ref [opcr.io/omrigazitt1/peoplefinder:1.0.0].digest: sha256:84dbd4e3b5572dd2f23c3c987c89443fdcb57af87d714ea296fc552192fb17e9
$ policy images
| REPOSITORY | TAG | SIZE | CREATED AT |
|--------------------------|-------|-------|--------------|
| omrigazitt1/peoplefinder | 1.0.0 | 555 B | 1 minute ago |
$ policy images --remote
| REPOSITORY | TAG |
|--------------------------|-------|
| omrigazitt1/peoplefinder | 1.0.0 |
We created Open Policy Containers because we believe OPA policies should be easy to share, and we think that OCIv2 is the best standard for that purpose. Leveraging OCIv2 allows us to use other tools in the ecosystem, which improves the overall development workflow as well as the distribution process.
We hope you find this tool useful!
policy CLI. It takes about 5 minutes to complete, and you'll learn how to:
cosignThe full tutorial is here.
When we first started using OPA, we were impressed with how flexible it is as a general-purpose decision engine. We were familiar with using it for infrastructure scenarios (like k8s admission control), but thought we could extend its use to application and API authorization scenarios.
One thing we missed, though, is the ability to interact with policy bundles in the same way that we interact with docker images.
We modeled the policy CLI on docker - a familiar pattern to most developers. With the policy
CLI, you can build, tag, push, and pull policy images just like you do with docker.
By representing policy images as OCIv2 containers, you can push and pull them into any OCIv2-compatible registry.
And indeed, you can use any OCI-compliant container registry with the policy CLI - GitHub Container Registry, Google Container Registry, Docker Hub, AWS ECR, etc.
In addition we thought it would be useful to have a container registry that would focus exclusively on policies as a container image type.
We built Open Policy Registry as a container registry for round-tripping policy image containers.
We believe that as a "meta-project", OPCR brings together three existing CNCF ecosystems, and makes them "better together":
We'd love to hear from you! Tweet / DM us at @openpolicyreg or find us in our Slack!