The Open Policy Agent (OPA) is an open source, general-purpose policy engine that provides a framework for validating structured data across your cloud-native stack. It encourages users to write policy-as-code to extend the community’s move towards infrastructure as code (IaC). OPA can validate any kind of structured data, including Terraform, HTTP requests, Envoy, Kafka, SQL, Linux, and Dockerfiles; it is frequently used and associated with Kubernetes manifests.
The OPA team maintains a suite of tools for configuration validation using a domain-specific language called Rego. Rego can be a bit challenging for those unfamiliar with it, because the syntax is unlike a typical programming language. However, like any good domain-specific language (DSL), it’s quite powerful once you become familiar with it. If you want to learn how to start thinking in Rego, read this linked article.
The Kubernetes community has chosen OPA for creating configuration policies. To support that need, you can use the Fairwinds Insights command line interface (CLI) to test and validate OPA policies. The CLI helps you in two ways, by:
Validating the OPA policy syntax
Validating the Action Items that the policy outputs in Fairwinds Insights
This improves the feedback loop for developers when working with OPA policies and allows you to test your policies locally before you upload them to Fairwinds Insights.
Your first step is to install the Fairwinds Insights CLI. You can do that by visiting our GitHub page for the Insights CLI, which includes links to the CLI documentation and installation options.
Our team created a video that walks you through the steps you need to take to validate OPA policies in the CLI. If you’re not already using Insights, the free tier is available for environments up to 20 nodes, two clusters, and one repo, so you can use it to get started and follow these steps. First, run a --help
command to see which validation options are currently available. At the command line, type: insights-cli validate opa --help
. In the demo video, you can see it only validates a single policy, but you can also validate multiple policies, such as one might use in continuous integration/continuous deployment (CI/CD).
Here’s an example OPA policy that makes sure the “department” label is set on every Deployment. We’ll call this file policy.yaml
package fairwinds
labelrequired[actionItem] {
requiredLabels := {"department"}
kinds := {"Deployment"}
kind := lower(kinds[val])
lower(input.kind) == kind
provided := {label | input.metadata.labels[label]}
missing := requiredLabels - provided
count(missing) > 0
description := sprintf("Label %v is missing", [missing])
actionItem := {
"title": "Label is missing",
"description": description,
"severity": .2,
"remediation": "Add the label",
"category": "Reliability"
}
}
In order to validate this policy, we’d want to supply a Kubernetes Deployment that passes the policy and another one that fails. Here’s an example Deployment that should pass validation. We’re going to call this policy.success.yaml, which signals to the insights-cli that this should pass the OPA policy.
apiVersion: apps/v1
kind: Deployment
metadata:
name: policy-test
labels:
department: development
spec:
replicas: 1
template:
spec:
containers:
- image: busybox
Let’s see what happens when we use the Insights CLI to validate the policy above, using this Kubernetes manifest:
❯ insights-cli validate opa -r policy.rego -k policy.success.yaml
OPA policy validated successfully.
Great! Looks like everything passes. What happens if we remove the label?
❯ cat policy.success.yaml | grep -v department > policy.failure.yaml
❯ insights-cli validate opa -r policy.rego -k policy.failure.yaml
✔ Action Item:
Title: Label is missing
Category: Reliability
Severity: 0.2
Description: Label {"department"} is missing
Resource Namespace: notset
Resource Kind: Deployment
Resource Name: policy-test
Remediation: Add the label
Event Type: policy
OPA policy validated successfully.
We generated an Action Item, as expected! So we’ve confirmed that Insights will warn us if any of our Deployments are missing the “department” label.
What if we want to get a bit more specific? Maybe we don’t want to enforce our policy in the kube-system namespace, which contains a bunch of deployments we don’t manage. Fortunately, with Rego, that’s easy! And again we can use the CLI to validate that everything works as expected.
To exempt the kube-system namespace, we’ll add a new function to the policy:
blockedNamespace(elem) {
blockedNamespaces := ["kube-system"]
ns := blockedNamespaces[_]
elem.metadata.namespace == ns
}
Then, in labelrequired
function, we just have to add the line
not blockedNamespace(input)
We can tell the insights-cli which namespace we’re working in using the -N flag. If we set that to kube-system, we should see a complaint about policy.failure.yaml, which no longer generates an Action Item.
❯ insights-cli validate opa -r policy.rego -k policy.failure.yaml -N kube-system
OPA policy failed validation: 0 action items were returned, but 1 is expected
exit status 1
If you’re having trouble debugging an issue with your policy, you can use the “print” statement inside your rego code to get more feedback during policy execution. E.g. we can print the input’s kind to make sure we’re looking at the right thing:
labelrequired[actionItem] {
print("The Kind is", input.kind)
not blockedNamespace(input)
# …
}
❯ insights-cli validate opa -r policy.rego -k policy.success.yaml
The Kind is Deployment
OPA policy validated successfully.
Going through these steps, you now know how to validate that this policy is working as you intend it to. Excellent! It’s time to upload that policy to Insights. Just make sure that the OPA report is enabled in Report Hub and you are ready to start using OPA for policy management in Kubernetes.
Watch the video to walk through the steps of Validating OPA Policies in the CLI step by step.