Using fregot eval to Test Custom Rules

Note

Don’t forget to download the fugue.rego library and retrieve a test input file!

This document focuses on using Fregot’s eval command to test custom rules. fregot eval is useful for quickly evaluating a single expression, such as policy.

Using fregot eval to test a simple rule

Simple rules operate on a single resource at a time and advanced rules operate on an entire environment at a time. To test a simple rule with fregot eval, you tell Fregot exactly which resource in the input document to test, using the resource’s identifier in double-quotes.

The command structure looks like this:

fregot eval -i <JSON input filename> 'data.<package name>.<allow or deny> with input as input.resources["resource-identifier-goes-here"] <rule filename> fugue.rego

For example:

fregot eval -i input.json 'data.vm_size_simple.allow with input as input.resources["azurerm_virtual_machine.compliant_vm"]' simple-vm-size.rego fugue.rego

You can get the resource’s identifier from the input document. It’ll look something like resource_type.resource_name. In the example below, which contains two resources, the identifiers are azurerm_virtual_machine.compliant_vm and azurerm_virtual_machine.noncompliant_vm:

{
  "resources": {
    "azurerm_virtual_machine.compliant_vm": {
      "_provider": "provider.azurerm",
      "_skeleton": {
        "depends_on": null,
        "deposed": null,
        "primary": {
          "id": "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/compliantvm",
          "meta": null,
          "tainted": false
        },
      }
<cut for brevity>
    },
    "azurerm_virtual_machine.noncompliant_vm": {
      "_provider": "provider.azurerm",
      "_skeleton": {
        "depends_on": null,
        "deposed": null,
        "primary": {
          "id": "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/noncompliantvm",
          "meta": null,
          "tainted": false
        }
      }
<cut for brevity>
    }
  }
}

The output would be a single [true] or [] (undefined, aka false) value, because you specified a single resource when you entered with input as input.resources["resource-identifier-goes-here"] as part of the fregot eval command:

[true]

If you tested an allow rule and the result is [true], the resource is compliant. If you tested a deny rule and the result is [true], the resource is noncompliant.

Using fregot eval to test an advanced rule

You can use fregot eval to test the policy rule in an advanced rule. Unlike simple rules, advanced rules don’t require you to specify a particular resource during testing, because the policy set looks at all resources in the input.

The example below assumes that the input file, .rego file, and fugue.rego library are all in the present working directory:

fregot eval -i <JSON input filename> data.<package name>.policy <rule filename> fugue.rego

For example:

fregot eval -i input.json data.vm_size.policy vm_size.rego fugue.rego

Note that we haven’t specified 'with input as...' as part of the command. That’s because a policy rule returns a judgment for all resources in an environment, rather than just one, so there’s no need to single out a resource for Fregot to evaluate.

You’ll see results like this:

[[{"id":"/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/noncompliantvm","message":"invalid","type":"azurerm_virtual_machine","valid":false},{"id":"/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/compliantvm","message":"","type":"azurerm_virtual_machine","valid":true}]]

If you have jq installed, you can pipe the results into jq to format the response nicely:

fregot eval -i input.json data.vm_size.policy vm_size.rego fugue.rego | jq .

You’ll see results like this:

[
  [
    {
      "id": "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/noncompliantvm",
      "message": "invalid",
      "type": "azurerm_virtual_machine",
      "valid": false
    },
    {
      "id": "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/compliantvm",
      "message": "",
      "type": "azurerm_virtual_machine",
      "valid": true
    }
  ]
]

In this example, the resource with the ID /subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/noncompliantvm returns "valid": false and is therefore noncompliant with the rule we tested it against.

The resource with the ID /subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/compliantvm is "valid": true (compliant with the rule).

Note

The resource identifier is different from the resource ID.

  • The identifier is how Fugue uniquely identifies a resource in an input document, and is at the level directly below the resources object in the input.

  • The ID is how the provider identifies a resource, and is called id in the input.

Below, the identifier and the id are in bold:

{
  "resources": {
    "azurerm_virtual_machine.compliant_vm": {
      "_provider": "provider.azurerm",
      "_skeleton": {
        "depends_on": null,
        "deposed": null,
        "primary": {
          "id": "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/example-rg/providers/Microsoft.Compute/virtualMachines/compliantvm",
          "meta": null,
          "tainted": false
        },
      }
<cut for brevity>

What’s next?

For more information about Fregot, see the README.