Open Policy Agent Integration

This guide will teach you how to integrate Open Policy Agent into your service mesh and utilize its policy creation and enforcement system. In this practical example, we will demonstrate how to establish a policy for the Grey Matter SLO service based on method and payload. This example can be modified and used for any service throughout your mesh.

Learn how to integrate Open Policy Agent and in doing so:

  • Create custom policies ensuring proper authorization surrounding your services

  • Safely determine what values and information can reach your service

  • Base policies off of information such as request:

    • Method

    • Parsed-Body Values

    • Headers

    • Path

    • Content Length

    • Destination / Origin

    • Parsed Query

    • User-Agent

    • Many More

Prerequisites

Successful installation of the following:

  • Grey Matter deployed into the Kubernetes environment

  • Greymatter CLI configured with access to the environment

Note In order to use Open Policy Agent, we need to launch an OPA-Container in the pod of the service we are looking to policy-enforce. The following steps will explain how to do so, along with a practical example.

Step 1: Creating the Rego Policy

Rego is the backbone of OPA, it is the structured language that OPA policies are written in and interpreted.

Rego code is structured in such a way that information is passed to it through requests and depending on the logic of the Rego code, it will return values such as 'deny' or 'allow' as true or false, depending on how the conditions are met within the code. The code-snippet below is an example of a Rego policy that prevents users on the Grey Matter dashboard from setting memory-utilization violation triggers that are under 20 MB. We will save it as slo-policy.rego

package envoy.authz # Use envoy package
import input.attributes.request.http as http_request # Shorten HTTP request info as 'http_request'
default allow = true # Initialize allow variable, allow requests by default
allow = false { # Do not allow HTTP requests with that are true of all the conditions set in 'action_denied'
action_denied
}
action_denied { # If all of the conditions in this block are true, block the request. If any of these conditions are false, don't block request
any({http_request.method == "PUT", http_request.method == "POST"}) # If request method is PUT or POST
input.parsed_body.threshold < 20 # If threshold is less than
input.parsed_body.threshold != null # When threshold is set to nothing
input.parsed_body.metricKey == "mem" # Ensuring its a memory value
input.parsed_body.operator == "gte" # If greater than or equal operator
}

Note Want to read more about how the Rego language works and how to write your own Rego code? See Rego Policy Language and Rego Policy Reference.

Applying the policy as a secret

In order for this Rego policy file to be found in the mesh, we need to apply it as a secret:

kubectl create secret generic opa-policy --from-file slo-policy.rego

Step 2: Modifying the Service Deployment File

Getting the Deployment File

The first step in launching an OPA-Container in our service's pod is to to grab the deployment file of the pod we're looking to secure. We can do this by using the following command.

kubectl get deployment -o yaml slo > slo.yaml

Editing the Deployment File

Next, we will edit the service deployment file we just grabbed. We need to add in the container image for Open Policy Agent along with several arguments in the deployment file we just grabbed (saved to our current directory). This ensures that the container will spawn into our pod seamlessly. Following the format of the YAML code-snippet below, it exhibits specifically how the container setup should look. This code can be placed right under containers: whose immediate parent is spec: as seen here.

spec:
containers:
- name: opa
image: openpolicyagent/opa:latest-istio
volumeMounts:
- readOnly: true
mountPath: /policy
name: opa-policy
args:
- "run"
- "--server"
- "--addr=localhost:8181"
- "--log-level=debug"
- "--diagnostic-addr=0.0.0.0:8282"
- "--set=plugins.envoy_ext_authz_grpc.addr=:9191"
- "--set=plugins.envoy_ext_authz_grpc.query=data.envoy.authz.allow"
- "--set=decision_logs.console=true"
- "--ignore=.*"
- "/policy/slo-policy.rego"

In addition to the code-snippet above, you must also add the follow code to your deployment file. At the end of the file, there should be a parent called volumes. It is at this point you will add the following as such:

volumes:
- name: opa-policy
secret:
secretName: opa-policy

This step helps us to grab the Rego policy from our secret.

Applying the Deployment File

Now that we have our opa-policy secret in the mesh and our deployment file is saved and ready to go, we can apply it with:

kubectl apply -f ./slo.yaml

You can check on the progress of you deployment by using kubectl get pods -w -n default . Once your new pod is in the Running stage and the old one is done Terminating (~1min), we can move on to the next step.

Step 3: Editing the Listener

The final step is to edit the listener that is corresponding with the deployment you have been working on in this guide. We will be adding the envoy.ext_authz filter into the active_http_filters section of the listener. This filter will ensure that all requests being sent to our service are first checked with Open Policy Agent. The filter will also listen to Open Policy Agent's deny or allow response that comes from our parsed Rego Policy and accept the request dependent on the value of the response.

You can use the command greymatter list listener to get a list of listeners that are available for editing. In our example's case, we are looking for listener-slo as we are looking to edit the slo deployment.

Using the following command, we will edit the listener that we want:

greymatter edit listener listener-slo

Now, in your terminal's default editor, you will be shown the listener's data in a json format. The only fields that need to be edited are shown below:

"active_http_filters": [
"gm.metrics",
"envoy.ext_authz"
],
"http_filters": {
"envoy_ext_authz": {
"with_request_body": {
"max_request_bytes": 8192,
"allow_partial_message": true
},
"failure_mode_allow": false,
"grpc_service": {
"google_grpc": {
"target_uri": "127.0.0.1:9191",
"stat_prefix": "ext_authz"
},
"timeout": "10s"
}
},

Notice how we have added envoy.ext_authz to the active_http_filters parent and that we have added a second snippet, envoy_ext_authz, into the http_filters parent. The snippet added into the http_filters area makes it so that the requests sent from the filter are sent using the gRPC protocol and that all the of the request's information can be sent through ext_authz and observed by our Rego Policy. Please note: The json data we have added is not specific to our example only, and will not require editing. Any following http_filters can start to be placed after the last line of the above code-snippet.

Save this edit and allow some time (~30s) for the changes to propagate through the mesh.

Successful Output

If you have followed our example, you'll notice that for your Service Level Objective service in the Grey Matter dashboard, you will not be able to successfully change the memory-utilization violation field to any number less than 20 as it will return a 403 Forbidden Status. However, you will be able to edit the number to be anything equal to or greater than 20, or blank so that no violation trigger exists.

In the dashboard

In the network console

Congratulations

You have successfully integrated Open Policy Agent into your service mesh and created a custom Rego Policy to go along with it, in order to protect your service!

Want to look further into Open Policy Agent / Rego Policies?

Read further in-depth on Open Policy Agent and its more advanced capabilities such as, but not limited to, JWT Verification / Signing, dynamic Access Control Lists, and editing policies on the fly. See Here

Questions?

Need Help?

Create an account at Decipher Support to reach our team.