I'm trying to integrate OPA/open policy agent/ into gitlab ci-cd job, and evaluate it against terraform plan output.
I have independent rules in rego file and want to run each of them from package level so that opa outputs each rule with either true
or false
result.
In addition, once OPA faces with undefined/false
result it outputs with non-zero code along with the result output so that gitlab ci is aware of failing or succeeding the job. is it possible with OPA cli?
in case when some rules are failing rules.rego
package play.terraform
passing_rule{
1 = 1
}
failing_rule{
1 = 0
}
output of the command opa eval 'data.play.terraform' --data rules.rego --fail
and exit code is zero
{"result":[{"expressions":
[{"value":{"passing_rule":true},
"text":"data.play.terraform",
"location":{"row":1,"col":1}
}]
}]}
Do these rules have to be combined into one rule and that rule have to evaluated outputting single true or false
output?
Evaluating the package will never render undefined, so you'll have to be more creative if using opa eval
alone. Since you want to capture failures, you'll want to use default values as OPA does not distinguish undefined results from rules that simply did not exist. So you could update your policy like:
tf.rego
package play.terraform
default passing_rule := false
default failing_rule := false
passing_rule{
1 == 1
}
failing_rule{
1 == 0
}
Then, create a "main" package which will evaluate other packages. This pattern is known as dynamic policy composition:
main.rego
package main
import future.keywords.every
import future.keywords.in
import data.play.terraform
all_passed {
# Silly comprehension to print each result
[rule |
some rule, result in terraform
print(sprintf("%s: %s", [rule, result]))
]
every result in terraform {
result == true
}
}
In order to print the result of each rule in the terraform package, we use a comprehension to loop over them while printing the result. Finally, we use every
to determine if the rule itself should evaluate or not, in which case it doesn't will have --fail
come back with an exit code of 1.
$ opa eval --fail -f pretty -d tf.rego -d main.rego data.main.all_passed
failing_rule: false
passing_rule: true
undefined
$ echo $?
1
A bit contrived, but gets the job done :)