terraformgitlab-ciopen-policy-agentrego

Can OPA check all rules individually or these rules have to be combined into one parent rule to make a decision?


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?


Solution

  • 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 :)