opaopen-policy-agentrego

How to check if given string is contained in tags


Say I have the following test input, I would like to be able to write a test that checks if the string Application is contained in any of the tag keys. The idea being that this check would be able to match tags with different naming conventions across resources.

Any idea how to accomplish this?

{
    "resource": {
        "aws_vpc": {
            "_type": "AWS.EC2.Vpc",
            "cidr_block": "10.0.0.0/16",
            "id": "vpc-abc123",
            "tags": {
                "MyApplication": "Test",
                "Application": "Test",
                "Name": "my-vpc"
            }
        }
    }
}

Solution

  • TLDR; Insert a variable into a reference to iterate over values in the data:

    some key
    val := input.resource.aws_vpc.tags[key]
    contains(key, "Application")
    

    When you insert variables into references, OPA/Rego finds all of the assignments to those variables that satisfy the expressions in the rule. For example, if the rule was simply:

    check {
      some key
      input.resource.aws_vpc.tags[key]
    }
    

    Then check would be true if input.resource.aws_vpc_tags contains at least one value (which isn't false). For more information on iteration see this section in the Rego introduction docs. In your case, you want to test if any of the keys contain "Application" so you just add an additional statement in the rule:

    check {
      some key
      input.resource.aws_vpc.tags[key]
      contains(key, "Application")
    }
    

    Now check is true if there is at least one value with a key containing the string "Application". If you only need a simple boolean check then this would work. In some cases, you might want the values of the keys that contain "Application". In those cases, you could use a Set Comprehension:

    vals := {val |
      some key
      val := input.resource.aws_vpc.tags[key]
      contains(key, "Application") 
    }
    

    If you evaluated the latter against your test input the output would be:

    ["Test"]
    

    Technically the output would be a set but since JSON does not support sets, OPA renders them as arrays for external callers.

    Here's the same example (with a slightly different input) in the playground: https://play.openpolicyagent.org/p/KfbrwYDxIJ.

    If you're looking for more examples and tutorials of how to use OPA/Rego check out this online course (disclosure: I work for Styra).