Building Policy Gate for DevSecOps using Open Policy Agent

Nikhil Mittal
Engineering @ Chargebee
3 min readNov 30, 2022

In our last blog, we detailed our approach to building a continuous application security pipeline with the objective of providing centralized visibility of the overall security posture of production touching repositories using open-source tools.

With this implementation, our security workflow does not fail even if the tools detected any vulnerabilities in the scans. This was a founding stone to our shift left initiative

Next, to drive the adoption of our security workflow to individual production touching repositories in Chargebee, we decided to build a security policy engine using OPA to control the data produced by open-source tools to act as a gatekeeper so we can effectively control the success or failure of security workflow along with managing exceptions.

This is how the current security workflow looks like

The policy engine evaluates data produced by the open-source tools that we use

  • SAST -> SemGrep
  • SCA -> OWASP Dependency Checker
  • Secret Scanning -> GitLeaks
  • SBOM -> CycloneDx

All these tools produce JSON formatted report which is combined together using JQ to feed them to the policy engine

Security Policy Engine

The security policy engine starts with default.rego which checks if the overall count of violations is Zero or not.

package cb.devsecops.policy

default allow = false

allow {
count(violations) == 0
}

Violations are defined separately for each tool we use in the security pipeline. Let’s consider an example of SemGrep policy implementation. For SemGrep we have sast.rego file created in the policy engine where it initially checks for all the issues against a configured severity for instance if we decide to fail SemGrep only for ERROR categorized issues we can define this severity in the configuration file and the same does for other tools like SCA we can define to fail only on CRITICAL or HIGH severity issues.

This is what a sample SAST policy looks like:

package cb.devsecops.policy

import future.keywords.every
import future.keywords.in

violations[{"message": msg, "code": code}] {
issue = input.semgrep.results[_]
issue.extra.severity in data.config.semgrep.fail_on_severities
not semgrep_exempted(issue)

msg := "SAST result have issues with WARNING or ERROR"
code := "sast_fail"
}

semgrep_exempted(issue) {
exceptions := data.config.exceptions.semgrep

exceptions[_].attributes.fingerprint = issue.extra.fingerprint

# Support glob so that we can use patterns like 'javascript.**'
glob.match(exceptions[_].attributes.check_id, ["."], issue.check_id)
glob.match(exceptions[_].attributes.path, ["/"], issue.path)
}

Once the initial check for severity is completed it moves toward exception management. Producing false positive issues with security scans is a prevalent scenario.

To deal with this situation we have defined a way to add exceptions for each tool. So the next check is to see if the flagged issue is configured as an exception or not.

For example, if the policy engine catches a HIGH severity issue and it’s made as an exception, the security workflow won’t fail. And if the issue is failing on severity and not configured in exception our security workflow will fail. Let’s consider an example of exception management in the policy engine

{
"exceptions": {
"semgrep": [
{
"reason": "This is a example exception criteria",
"attributes": {
"check_id": "example-check-id",
"fingerprint": "example-fingerprint",
"path": "/target/example/path/file.ts"
}
}
],
"gitleaks": [
{
"reason": "This is a example exception criteria",
"attributes": {
"StartLine": 21,
"EndLine": 21,
"File":"/target/example/path/file.ts",
"Commit":"<commitSHA>"
}
}
],
"odc": [

]
}
}

Once the policy engine is integrated with the security workflow this is how it looks in action

Closing note

With this tooling, at Chargebee we intend to drive policy as code adoption and encourage security policies to be codified in the pipeline.

Possibilities of adopting Policy as Code are limitless. Any change in security policies will mean we need to change only the policy code instead of the rest of the system. It also ensures the separation of concerns between tools developers, integrators, and policymakers.

For comments or feedback, you can get in touch with me over Twitter 😀

If you are interested in our work and want to solve complex problems in SaaS products, platform & cloud infrastructure engineering — we are hiring!

--

--