Open Policy Agent (OPA)
website·Indexed 42 days ago
https://www.openpolicyagent.org/docsAn open-source general-purpose policy engine that uses the Rego declarative language to write policies. It supports installation as a server, interactive mode, or Go library, and provides integrations for Kubernetes Admission Control and the Envoy proxy.
What's inside OPA
- Regal is a linter and language server for Rego. It is designed to identify common mistakes, bugs, and inefficiencies in Rego policies, suggest idiomatic approaches, and enforce coding style and best practices. It can be used as a standalone CLI tool, integrated into editors (via a language server), or incorporated into CI/CD build pipelines.
Overview of OPA-Envoy Plugin
The OPA-Envoy plugin extends OPA with a gRPC server that implements the Envoy External Authorization API. This allows Envoy (v1.7.0+) to delegate fine-grained, context-aware access control decisions to OPA without modifying the underlying microservices. It is typically deployed as a sidecar container in Kubernetes or as a standalone process running alongside Envoy to minimize network latency and improve performance.Overview of Open Policy Agent (OPA)
Open Policy Agent (OPA) is an open-source, general-purpose policy engine that decouples policy decision-making from policy enforcement. It allows developers to specify policy as code using a high-level declarative language called Rego. OPA accepts arbitrary structured data (typically JSON) as input and can generate arbitrary structured data as output, making it suitable for microservices, Kubernetes, CI/CD pipelines, and API gateways.Use OPA for Kubernetes Admission Control
OPA can be deployed as a Kubernetes Admission Controller to enforce policies during create, update, and delete operations. It can act as a validating controller (denying requests) or a mutating controller (modifying objects).
Common use cases include:
- Requiring specific labels on all resources.
- Restricting container images to corporate registries.
- Ensuring Pods specify resource requests and limits.
- Preventing conflicting Ingress objects.
- Injecting sidecar containers or setting specific annotations.
Access and query input data in Rego
In Rego, data provided in a query is bound to a global variable calledinput. You can access specific fields using the dot (.) operator or square-bracket syntax for array elements or keys containing special characters. If a referenced value does not exist, OPA returnsundefined.package servers # Accessing a field output := input.servers # Accessing array elements output := input.servers[0].protocols[0] # Accessing keys with special characters output := input["foo~bar"]Verify conditions for all elements using the `every` keyword
Theeverykeyword is used to succinctly express that a specific condition must hold for all elements of a domain ('FOR ALL' logic).package servers # True if no server in the input list exposes the telnet protocol no_telnet_exposed if { every server in input.servers { not "telnet" in server.protocols } }Iterate over collections in Rego
Iteration in Rego is implicit. Use thesome ... in ...syntax to iterate over a collection. OPA evaluates the rule body for each element; if any element satisfies all expressions in the body, the rule is defined. To collect multiple results into a set, use thecontainskeyword.package servers # Check if any network is public exists_public_network if { some network in input.networks network.public == true } # Check if any server exposes "http" http_server if { some server in input.servers "http" in server.protocols } # Collect IDs of ports connected to public networks exposed_ports contains port.id if { some port in input.ports some network in input.networks port.network == network.id network.public == true }Install Open Policy Agent (OPA)
OPA can be installed on macOS via Homebrew or by downloading the binary directly. After downloading a binary, it must be made executable usingchmod 755. It is recommended to move the binary to a directory in yourPATH.# Install via Homebrew brew install opa # Or download binary directly (example for macOS arm64) curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_darwin_arm64 chmod 755 ./opa # Verify installation opa versionIterate over collections using the `some` keyword
Thesome ... in ...syntax is used to iterate over a collection (the last argument). It binds variables (such as key or value) to the collection items and introduces these bindings to the rest of the rule body. This is the standard way to express 'FOR SOME' logic in Rego.package servers # Returns the ID of networks that are public public_network contains net.id if { some net in input.networks net.public } # Returns the ID of servers that allow telnet shell_accessible contains server.id if { some server in input.servers "telnet" in server.protocols }Implement OPA policy decisions for Envoy
By default, OPA-Envoy queries the policy path
envoy/authz/allow(accessed asdata.envoy.authz.allowin Rego).- Boolean Response: Return
trueto allow the request orfalseto deny it. - Object Response: Return an object that MUST contain the
allowedkey (boolean). You may optionally include:headers: Custom headers to send to the downstream client or upstream.body: Response body data for the downstream client.http_status: An HTTP response status code other than 403 (Forbidden).
- Boolean Response: Return
Use OPA Gatekeeper for Kubernetes Policy Management
OPA Gatekeeper is the recommended project for Kubernetes admission control. It extends plain OPA by providing:
- An extensible, parameterized policy library.
- Native Kubernetes CRDs for instantiating policies (Constraints).
- Native Kubernetes CRDs for extending the policy library (Constraint Templates).
- Built-in audit functionality.
Plain OPA and kube-mgmt are alternatives for users who specifically need OPA management features like status logs, decision logs, and bundles.
Implement logical OR in Rego
Logical AND is expressed by joining multiple expressions in a single query. To express logical OR, define multiple rules with the same name. For complete rules, thedefaultkeyword can be used to provide a fallback value if all other rules with that name are undefined. For partial rules, each rule definition contributes its values to the resulting set.package example.logical_or # Default value if no rules match default shell_accessible := false # Rule 1: True if telnet is exposed shell_accessible if { some server in input.servers "telnet" in server.protocols } # Rule 2: True if ssh is exposed shell_accessible if { some server in input.servers "ssh" in server.protocols }