Managing Custom Rules - CLI

Note

For UI instructions, see Managing Custom Rules - UI.

For API instructions, see Managing Custom Rules - API.

Just looking for info on writing custom rules? See Writing Custom Rules.

Fugue’s CLI allows you to test, create, update, and delete custom rules.

Creating Custom Rules - CLI

Creating a custom rule via the CLI generally involves three steps:

  1. Optional: Get the input for a custom rule test (CLI Reference)

  2. Optional: Test the custom rule (CLI Reference)

  3. Add the rule (CLI Reference)

Creating a Rule via CLI - Get Input for Test

It’s a best practice to test a custom rule with the CLI before adding it to your tenant. To test a custom rule, we recommend that you retrieve test input first, which is scan data to test the rule against. You can use this test input to help you write the rule. Then, you run the test by providing Fugue with the rule and the scan ID. Fugue tests the rule against the resources recorded in that scan.

You don’t have to test a rule; you can skip ahead to adding it, and the CLI will reject it if the syntax is incorrect, but you won’t know if it produces the intended results until after the next scan. We highly recommend you test rules before adding them.

To retrieve the scan data from the CLI, start by finding the scan ID for the data you want to use with the fugue list scans [environment_id] command. You’ll need the environment ID you want to grab a scan from:

fugue list scans e3717b3f-dd1c-4f07-bbc6-eccf804c4771

You can copy the ID from any past scan, or you can manually kick off a new scan with fugue scan [environment_id] and use that ID.

Next, execute the fugue get rule-input –scan [scan_id] command to retrieve the rule test input. We’ll redirect the output of the command to a new file, input.json:

fugue get rule-input --scan fc9f777e-0acb-4054-b133-2de1da174e04 > input.json

If you open up input.json, you’ll see the CLI response is a JSON representation of each resource in your environment from that scan. Here’s an abbreviated example of two VPCs:

{
    "resources": {
        "aws_vpc.dnBjLTAyYjEwMjQ4123456789012": {
            "_skeleton": {
                "depends_on": null,
                ...
            },
            ...
            "cidr_block": "10.0.0.0/16",
            "id": "vpc-02b10248f12345678",
            "tags": {
                "Name": "my-vpc",
                "Application": "Portal"
            }
        },
        "aws_vpc.dnBjLT9999999999": {
            "_skeleton": {
                "depends_on": null,
                ...
            },
            ...
            "cidr_block": "172.31.0.0/16",
            "id": "vpc-92281234",
            "tags": {}
        }
    }
}

Once you have this information, you can determine the expected result of your custom rule test. For example, if you are writing a rule that tests whether all VPCs in an environment have the tag key Application and the tag value Portal, the scan data can tell you that one VPC should pass (vpc-02b10248f12345678) and one should fail (vpc-92281234).

Using Test Input to Write Rules

You can also use the infrastructure state JSON to determine the resource attributes and syntax for writing custom rules. The way resource configuration is structured in the scan data is the same structure Fugue expects for custom rules.

So, let’s say your scan data includes an Amazon VPC like this one (cut for length):

{
    "resources": {
        ...
        "aws_vpc.dnBjLTAyYjEwMjQ4123456789012": {
            ...
            "_type": "AWS.EC2.Vpc",
            "cidr_block": "10.0.0.0/16",
            "id": "vpc-02b10248f12345678",
            "tags": {
                "Name": "my-vpc",
                "Application": "Portal"
            }
        }
    }
}

The example simple rule below uses the syntax input.tags.Application to pass VPCs tagged with the key Application and value Portal, following the JSON structure of the input above:

allow {
  input.tags.Application == "Portal"
}

In the example below, which is an advanced version of the simple rule above, we used the variable vpc to refer to an individual VPC and used vpc.tags.Application to refer to the VPC tag key Application following the JSON structure of the input:

policy[p] {
  vpcs = fugue.resources("AWS.EC2.Vpc")
  vpc = vpcs[_]
  vpc.tags.Application == "Portal"
  p = fugue.allow_resource(vpc)
} {
  vpcs = fugue.resources("AWS.EC2.Vpc")
  vpc = vpcs[_]
  not vpc.tags.Application == "Portal"
  p = fugue.deny_resource(vpc)
}

Creating a Rule via CLI - Test the Rule

You can determine whether a custom rule will work by testing the code against infrastructure state from a particular scan. This will help you determine correctness of syntax and accuracy of results.

Start by using the fugue list scans [environment_id] command to get the scan ID for the data you want to use, if you haven’t already. You can use the ID from any past scan, or you can manually kick off a new scan with the fugue scan [environment_id] command and use that ID.

Next, execute the fugue test rule [rego file] command. You’ll need to specify the resource type of the rule and the scan ID, and pass in the Rego file containing your rule code.

Specifying the resource type

The way you specify the resource type depends on the type of rule (simple or advanced), provider(s), and method of uploading to Fugue.

  • Use resource_type = {resource_type} for simple rules, e.g., resource_type = "aws_s3_bucket"

  • Use resource_type = "MULTIPLE" for advanced rules

  • Use resource_type = "DEFINED_IN_CODE" if your resource type is defined in the Rego code. Defining your rule in code is optional, except in the following scenarios where you must define it as code:

If the resource type is set to DEFINED_IN_CODE, ensure the Rego code contains a resource_type = {resource_type} line if it’s a simple rule, or resource_type = "MULTIPLE" if it’s advanced.

For more information, see Custom Rules Reference, Simple Rules, and Advanced Rules.

Here’s an example command. We decided to include the resource type in the Rego code, so we set the --resource-type flag to DEFINED_IN_CODE:

fugue test rule --resource-type "DEFINED_IN_CODE" \
  --scan fc9f777e-0acb-4054-b133-2de1da174e04 rule.rego

The example rule.rego file contains this code:

package rules.app_tag

default allow = false

resource_type = "aws_vpc"

allow {
  input.tags.Application == 'Portal'
}

Fugue returns the results of the rule if the syntax is correct, or an error if Fugue cannot parse it. (Note that the CLI cannot report semantic errors, only parsing errors – just like programming in general, confirm that your custom rule has the expected results before you add it to your tenant!)

Example rule results:

========================================
ID                    | RESULT | TYPE
========================================
vpc-05621851a2b3c4d5e | PASS   | aws_vpc
vpc-07f46019987654321 | FAIL   | aws_vpc

Example error message:

fregot (rules_engine error):
  Expected at least one `allow` or `deny` rule in the module for a single resource type rule.

Creating a Rule via CLI - Add the Rule

Getting scan data and testing a rule are not prerequisites for adding a rule via the CLI, but we strongly recommend taking these steps first. The Fugue CLI checks the syntax when you add the rule but cannot report semantic errors, so you won’t know if the rule has the intended results until after the next scan.

There are two methods of creating rules via the CLI:

Creating a single rule

Tip

Using a version control system such as Git? We highly recommend using the fugue sync rules [directory] command instead to programmatically sync the rules in a repository to Fugue through CI/CD.

To create a single rule, use the fugue create rule command:

fugue create rule --description "Amazon VPCs must be tagged with Application:Portal" \
  --name "VPCs require Application:Portal tags" \
  --provider "AWS" --resource-type "DEFINED_IN_CODE" \
  --severity "High" \
  --text "package rules.app_tag

default allow = false

resource_type = \"aws_vpc\"

allow {
  input.tags.Application == 'Portal'
}"

Tip

Remember to escape any double quotes with a \ character!

Fugue returns the details about the newly added rule if the syntax is correct, or an error if Fugue cannot parse it or encounters another error. (Note that the CLI cannot report semantic errors, only parsing errors – just like programming in general, confirm that your custom rule has the expected results before you add it to your organization!)

Example output for a rule created successfully – note that STATUS is ENABLED:

============================================================================
ATTRIBUTE               | VALUE
============================================================================
RULE_ID                 | eefbd194-e73f-4930-a22d-7c64fd912bbe
NAME                    | VPCs require Application:Portal tags
DESCRIPTION             | Amazon VPCs must be tagged with Application:Portal
PROVIDER                | AWS
RESOURCE_TYPE           | DEFINED_IN_CODE
SEVERITY                | High
STATUS                  | ENABLED
FAMILIES                | -
CREATED_AT              | 2021-11-14T22:46:53-05:00
CREATED_BY              | api_client:003897de-19e9-405d-9faa-0949e145e6ba
CREATED_BY_DISPLAY_NAME |
UPDATED_AT              | -
UPDATED_BY              |
UPDATED_BY_DISPLAY_NAME |

Example error message – note that STATUS is INVALID:

============================================================================
ATTRIBUTE               | VALUE
============================================================================
RULE_ID                 | eefbd194-e73f-4930-a22d-7c64fd912bbe
NAME                    | VPCs require Application:Portal tags
DESCRIPTION             | Amazon VPCs must be tagged with Application:Portal
PROVIDER                | AWS
RESOURCE_TYPE           | DEFINED_IN_CODE
SEVERITY                | High
STATUS                  | INVALID
FAMILIES                | -
CREATED_AT              | 2021-11-14T23:04:40-05:00
CREATED_BY              | api_client:003897de-19e9-405d-9faa-0949e145e6ba
CREATED_BY_DISPLAY_NAME |
UPDATED_AT              | -
UPDATED_BY              |
UPDATED_BY_DISPLAY_NAME |

Uploading a directory of rules

Tip

The fugue sync rules [directory] command is ideal if you’re using version control software such as Git. You can programmatically sync the rules in a repository to Fugue via CI/CD.

The fugue sync rules [directory] command allows you to upload a directory of Rego files to Fugue. If a rule name exists, the rule is updated; otherwise, a new rule is created.

Example command:

fugue sync rules my-rules-directory

Note that each Rego file must contain metadata to indicate the rule title, description, and provider(s) at a minimum.

Here’s an example rule with metadata:

package rules.vpc_tag_app

__rego__metadoc__ := {
  "title": "VPCs require Application:Portal tags",
  "description": "Amazon VPCs must be tagged with Application:Portal",
  "custom": {
    "providers": ["AWS"],
    "severity": "High"
  }
}

default allow = false

resource_type = "aws_vpc"

allow {
  input.tags.Application == "Portal"
}

Note

HTTP header metadata is deprecated. We recommend using the newer __rego__metadoc__ method detailed in the Custom Rules Reference.

After you execute fugue sync rules [directory], you’ll see output like this:

Creating rule VPCs require Application:Portal tags

Note that if a rule name already exists, Fugue will overwrite (update) the rule:

Updating rule VPCs require Application:Portal tags

Modifying and Deleting Custom Rules - CLI

Modifying Custom Rules - CLI

Getting scan data and testing a rule are not prerequisites for modifying a rule via the CLI, but we strongly recommend taking these steps first. The Fugue CLI checks the syntax when you update the rule but cannot report semantic errors, so you won’t know if the rule has the intended results until after the next scan.

There are two methods of updating rules via the CLI:

Updating a single rule

Tip

Using a version control system such as Git? We highly recommend using the fugue sync rules [directory] command instead to programmatically sync your rules to Fugue through CI/CD.

Start by finding the rule ID for the rule you want to update. You can do this by executing the fugue list rules command and then looking for the ID of the desired rule:

fugue list rules

In the output, look for the ID column:

======================================================================================================================================================================================================================================================================
ID                                   | NAME                                                                            | PROVIDER     | SEVERITY      | RESOURCE_TYPE                   | STATUS   | DESCRIPTION                      | FAMILIES
======================================================================================================================================================================================================================================================================
eefbd194-e73f-4930-a22d-7c64fd912bbe | VPCs require Application:Portal tags                                            | AWS          | Medium        | aws_vpc                         | INVALID  | Amazon VPCs must be tagged wi... | c4e28bd,Custom
8eedf0bd-339d-4fb8-b6ad-b9dae518825e | All taggable AWS and Azure resources must be tagged                             | AWS          | Medium        | DEFINED_IN_CODE                 | DISABLED | If it's taggable, tag it.        | Custom
7b643bde-76c1-4640-9372-70dc4919416c | An AWS account must have a password policy requiring a minimum of 16 characters | AWS          | Medium        | MULTIPLE                        | ENABLED  | An AWS account must have a pa... | Custom

Once you have the ID of the rule you want to update, execute the fugue update rule [rule_id] command and specify the flag(s) you want to update:

fugue update rule eefbd194-e73f-4930-a22d-7c64fd912bbe --severity "Medium"

Note

Custom rule providers cannot be updated via the CLI. Instead, use the UI or API.

You’ll see output like this:

============================================================================
ATTRIBUTE               | VALUE
============================================================================
NAME                    | VPCs require Application:Portal tags
DESCRIPTION             | Amazon VPCs must be tagged with Application:Portal
PROVIDER                | AWS
SEVERITY                | Medium
RESOURCE_TYPE           | DEFINED_IN_CODE
STATUS                  | ENABLED
FAMILIES                | Custom
CREATED_AT              | 2021-11-15T05:23:57-05:00
CREATED_BY              | api_client:003897de-19e9-405d-9faa-0949e145e6ba
CREATED_BY_DISPLAY_NAME |
UPDATED_AT              | 2021-11-15T05:29:44-05:00
UPDATED_BY              | api_client:003897de-19e9-405d-9faa-0949e145e6ba
UPDATED_BY_DISPLAY_NAME |

Updating a directory of rules

Tip

The fugue sync rules [directory] command is ideal if you’re using version control software such as Git. You can programmatically sync your rules to Fugue via CI/CD.

The fugue sync rules [directory] command allows you to upload a directory of Rego files to Fugue. If a rule name exists, the rule is updated; otherwise, a new rule is created.

See Uploading a directory of rules for more information.

Example Rules

For examples of simple and advanced custom rules, see our GitHub repo.

Deleting Custom Rules - CLI

Start by executing fugue list rules to find the ID for the rule you want to update, if you haven’t already.

Then, execute the fugue delete rule [rule_id] command:

fugue delete rule eefbd194-e73f-4930-a22d-7c64fd912bbe

If the delete call is successful, there is no output.

Note

If you delete or disable a custom rule, the rule is not removed from an environment until after the next scan. The deleted or disabled rule continues to display in the environment’s compliance tabs and the pass/fail results count toward your compliance posture. After the next scan, the rule is removed from the environment and results are not counted toward your compliance posture.

Viewing Compliance Results - CLI

All custom rules with valid syntax automatically run against environments with the Custom family enabled on their next scan. After the scheduled scan runs or is kicked off manually with fugue scan [environment_id], you can request the Custom compliance family results from the CLI.

Additionally, the three compliance endpoints allow you to take a deeper dive into why your custom rule is passing or failing.

Compliance by Resource - CLI

The CLI does not currently support viewing compliance by resource. To view compliance by resource results in the UI, see Compliance by Resource - UI.

Compliance by Resource Type - CLI

To view compliance by resource type using the CLI, use the fugue get compliance-by-resource-types [scan_id] command:

fugue get compliance-by-resource-types 4b66a672-fc9c-4674-9b5c-4df42d23a40c

You’ll see output like this:

======================================================================
RESOURCE_TYPE                       | COMPLIANT | NONCOMPLIANT | TOTAL
======================================================================
AWS.ACM.Certificate                 | 1         | 0            | 1
AWS.AutoScaling.LaunchConfiguration | 2         | 0            | 2
AWS.CloudFront.Distribution         | 0         | 1            | 1
<cut for length>

Compliance by Control - CLI

To view compliance by control using the CLI, use the fugue get compliance-by-rules [scan_id]:

fugue get compliance-by-rules 4b66a672-fc9c-4674-9b5c-4df42d23a40c

You’ll see output like this:

===================================================
FAMILY                           | RULE    | RESULT
===================================================
AWS-Well-Architected_v2020-07-02 | REL10.1 | FAIL
AWS-Well-Architected_v2020-07-02 | REL6.1  | FAIL
AWS-Well-Architected_v2020-07-02 | REL9.1  | PASS
<cut for length>

Waiving Custom Rules - CLI

To waive a rule using the CLI, see the fugue create rule-waiver command.

Disabling and Enabling Custom Rules - CLI

The CLI does not support enabling and disabling rules; use the UI or API instead. See Enabling and Disabling Rules for more information.