This repository contains an extended version of OPA (OPA-Envoy) that allows you to enforce OPA policies with Envoy.
Use OPA GitHub Issues to request features or file bugs.
The OPA-Envoy plugin can be deployed with Envoy-based service meshes such as:
OPA-Envoy extends OPA with a gRPC server that implements the Envoy External Authorization API. You can use this version of OPA to enforce fine-grained, context-aware access control policies with Envoy without modifying your microservice.
More information about the OPA-Envoy plugin including performance benchmarks, debugging tips, detailed usage examples can be found here.
This section assumes you are testing with Envoy v1.10.0 or later.
-
Start Minikube.
minikube start
-
Install OPA-Envoy.
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/opa-envoy-plugin/main/quick_start.yaml
The
quick_start.yaml
manifest defines the following resources:-
A ConfigMap containing an Envoy configuration with an External Authorization Filter to direct authorization checks to the OPA-Envoy sidecar. See
kubectl get configmap proxy-config
for details. -
OPA configuration file, and an OPA policy into ConfigMaps in the namespace where the app will be deployed, e.g.,
default
. -
A Deployment consisting an example Go application with OPA-Envoy and Envoy sidecars. The sample app provides information about employees in a company and exposes APIs to
get
andcreate
employees. More information about the app can be found here. The deployment also includes an init container that installs iptables rules to redirect all container traffic through the Envoy proxy sidecar. More information can be found here.
-
-
Make the application accessible outside the cluster.
kubectl expose deployment example-app --type=NodePort --name=example-app-service --port=8080
-
Set the
SERVICE_URL
environment variable to the service’s IP/port.minikube:
export SERVICE_PORT=$(kubectl get service example-app-service -o jsonpath='{.spec.ports[?(@.port==8080)].nodePort}') export SERVICE_HOST=$(minikube ip) export SERVICE_URL=$SERVICE_HOST:$SERVICE_PORT echo $SERVICE_URL
minikube (example):
192.168.99.100:31380
-
Exercise the sample OPA policy.
For convenience, we’ll want to store Alice’s and Bob’s tokens in environment variables.
export ALICE_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZ3Vlc3QiLCJzdWIiOiJZV3hwWTJVPSIsIm5iZiI6MTUxNDg1MTEzOSwiZXhwIjoxOTQxMDgxNTM5fQ.rN_hxMsoQzCjg6lav6mfzDlovKM9azaAjuwhjq3n9r8" export BOB_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJzdWIiOiJZbTlpIiwibmJmIjoxNTE0ODUxMTM5LCJleHAiOjE5NDEwODE1Mzl9.ek3jmNLPclafELVLTfyjtQNj0QKIEGrbhKqpwXmQ8EQ"
Check that
Alice
can get employees but cannot create one.curl -i -H "Authorization: Bearer "$ALICE_TOKEN"" http://$SERVICE_URL/people curl -i -H "Authorization: Bearer "$ALICE_TOKEN"" -d '{"firstname":"Charlie", "lastname":"OPA"}' -H "Content-Type: application/json" -X POST http://$SERVICE_URL/people
Check that
Bob
can get employees and also create one.curl -i -H "Authorization: Bearer "$BOB_TOKEN"" http://$SERVICE_URL/people curl -i -H "Authorization: Bearer "$BOB_TOKEN"" -d '{"firstname":"Charlie", "lastname":"Opa"}' -H "Content-Type: application/json" -X POST http://$SERVICE_URL/people
Check that
Bob
cannot create an employee with the same firstname as himself.curl -i -H "Authorization: Bearer "$BOB_TOKEN"" -d '{"firstname":"Bob", "lastname":"Rego"}' -H "Content-Type: application/json" -X POST http://$SERVICE_URL/people
To deploy OPA-Envoy include the following container in your Kubernetes Deployments:
containers:
- image: openpolicyagent/opa:latest-envoy
imagePullPolicy: IfNotPresent
name: opa-envoy
volumeMounts:
- mountPath: /config
name: opa-envoy-config
args:
- run
- --server
- --addr=localhost:8181
- --diagnostic-addr=0.0.0.0:8282
- --config-file=/config/config.yaml
livenessProbe:
httpGet:
path: /health?plugins
port: 8282
readinessProbe:
httpGet:
path: /health?plugins
port: 8282
The OPA-Envoy configuration file should be volume mounted into the container. Add the following volume to your Kubernetes Deployments:
volumes:
- name: opa-envoy-config
configMap:
name: opa-envoy-config
In the Quick Start section an OPA policy is loaded via a volume-mounted ConfigMap. For production deployments, we recommend serving policy Bundles from a remote HTTP server.
Using the configuration shown below, OPA will download a sample bundle from https://www.openpolicyagent.org. The sample bundle contains the exact same policy that was loaded into OPA via the volume-mounted ConfigMap.
config.yaml:
services:
- name: controller
url: https://www.openpolicyagent.org
bundles:
envoy/authz:
service: controller
plugins:
envoy_ext_authz_grpc:
addr: :9191 # default `:9191`
path: envoy/authz/allow # default: `envoy/authz/allow`
dry-run: false # default: false
enable-reflection: false # default: false
grpc-max-recv-msg-size: 40194304 # default: 1024 * 1024 * 4
grpc-max-send-msg-size: 2147483647 # default: max Int
skip-request-body-parse: false # default: false
enable-performance-metrics: false # default: false. Adds `grpc_request_duration_seconds` prometheus histogram metric
You can download the bundle and inspect it yourself:
mkdir example && cd example
curl -s -L https://www.openpolicyagent.org/bundles/envoy/authz | tar xzv
In this way OPA can periodically download bundles of policy from an external server and hence loading the policy via a
volume-mounted ConfigMap would not be required. The readinessProbe
to GET /health?bundles
ensures that the opa-envoy
container becomes ready after the bundles are activated.
Dependencies are managed with Modules.
If you need to add or update dependencies, modify the go.mod
file or
use go get
. More information is available here.
Finally commit all changes to the repository.