Managing Custom Rules - API

Fugue’s API allows you to test, create, edit, and delete custom rules. This document explains how to do all of the above.

Creating, Testing, and Managing Custom Rules - API

Note

For UI instructions, see Creating and Managing Custom Rules - UI.

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

Ready to begin? Below are general instructions for creating custom rules with Fugue via the API.

In a hurry? Jump ahead:

Creating Custom Rules - API

For UI instructions, see Creating Custom Rules - UI.

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

  1. Optional: Get the input for a custom rule test (Example request | API Reference)

  2. Optional: Test the custom rule (Example request | API Reference)

  3. Add the rule (Example request | API Reference)

This video demonstrates how to test and create a custom rule through the API:

Creating a Rule via API - Get Input for Test

(Example request | API Reference)

It’s a best practice to test a custom rule with the API before adding it to your organization. To test a custom rule, we recommend that you retrieve test input first, which is scan data to test the rule against. (When you test a rule with Fugue, it is tested against the resources recorded in that scan.) However, it is an optional step, since Fugue only needs the scan ID to test a rule – retrieving/viewing the input is strictly for the user’s benefit. You also don’t have to test a rule; you can skip ahead to adding it, and the API will reject it if the syntax is correct, 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 via the API.

To retrieve the scan data from the API, start by finding the scan ID for the data you want to use. You can use the ID from any past scan, or you can manually kick off a new scan and use that ID – see the FAQ for details.

Next, send a GET request to the Fugue API /rules/test/input?scan_id={scan_id} endpoint, replacing {scan_id} with your scan ID. Here’s an example curl command that returns the state of the infrastructure recorded in scan 535d21d2-700b-4b4f-9aa9-123456789012:

curl -X GET \
"https://api.riskmanager.fugue.co/v0/rules/test/input?scan_id=535d21d2-700b-4b4f-9aa9-123456789012" \
  -u $CLIENT_ID:$CLIENT_SECRET

(You can also use a GUI such as Postman. For more information, see the API User Guide.)

The API 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"
            }
        }
    }
}

In this case, a simple rule can refer to the VPC CIDR block property with input.cidr_block or the VPC ID with input.id. The example 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"
}

For an advanced rule you could use <variable>.id to refer to the VPC ID, or <variable>.cidr_block to refer to the VPC CIDR block. 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 API - Test the Rule

(Example request | API Reference | YouTube video)

Note

There are some important things to note when sending an API request to test a rule – see Custom Rules API - Things to Know.

You can determine whether a custom rule will work by testing the code against infrastructure state from a particular scan. Note that getting the test input (scan data) from the API is not a prerequisite for testing a rule; it’s strictly for the user’s benefit, since Fugue needs only the scan ID in order to test the rule against the scan data.

Whether you retrieve the scan data or not, the next step is to test the rule against the API to determine correctness of syntax and accuracy of results.

Start by finding 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 and use that ID; see the FAQ for details.

Next, send a POST request to the Fugue API /rules/test endpoint with a request body containing the custom rule code, resource type, and scan ID of the data Fugue will use to test the rule. You can save the JSON in a file and attach it with the -d @{filename} option. Here’s an example curl request to /rules/test:

curl -X POST \
"https://api.riskmanager.fugue.co/v0/rules/test" \
  -u $CLIENT_ID:$CLIENT_SECRET \
  -H "Content-Type: application/json" \
  -d @body.json

(You can also use a GUI such as Postman. For more information, see the API User Guide.)

And here’s an example request body for a rule that passes VPCs with the tag key Application and tag value Portal:

{
    "rule_text": "allow { input.tags.Application == 'Portal' }",
    "scan_id": "535d21d2-700b-4b4f-9aa9-123456789012",
    "resource_type": "AWS.EC2.Vpc"
}

Fugue returns the results of the rule if the syntax is correct, or an error if Fugue cannot parse it. (Note that the API 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 rule results:

{
    "errors": [],
    "resources": [
        {
            "id": "vpc-02b10248f12345678",
            "result": "PASS",
            "type": "AWS.EC2.Vpc"
        },
        {
            "id": "vpc-92281234",
            "result": "FAIL",
            "type": "AWS.EC2.Vpc"
        }
    ],
    "result": "FAIL"
}

Example error message:

{
    "errors": [
        {
            "severity": "error",
            "text": "fregot (custom_rules_engine error):\n  Expected at least one `allow` or `deny` rule in the module for a single resource type rule."
        }
    ],
    "resources": [],
    "result": "UNKNOWN"
}

Creating a Rule via API - Add the Rule

(Example request | API Reference | YouTube video)

Note

There are some important things to note when sending an API request to add a rule – see Custom Rules API - Things to Know.

Getting scan data and testing a rule are not prerequisites for adding a rule via the API, but we strongly recommend taking these steps first. The Fugue API 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.

To start, send a POST request to the Fugue API /rules endpoint with a request body containing the following information:

  • name: Name of the rule

  • source: Always "CUSTOM"

  • description: Description of the rule

  • provider: Either AWS, AWS_GOVCLOUD, or AZURE. (For Azure Government, select AZURE.)

  • resource_type:

  • rule_text: Rego code used by the rule. See Custom Rules API - Things to Know

  • severity: Level of severity. Default: High. See Rule Severity Definitions

(See the API Reference for more information.)

You can save the JSON in a file and attach it with the -d @{filename} option. Here’s an example curl request to /rules:

curl -X POST \
"https://api.riskmanager.fugue.co/v0/rules" \
  -u $CLIENT_ID:$CLIENT_SECRET \
  -H "Content-Type: application/json" \
  -d @body.json

(You can also use a GUI such as Postman. For more information, see the API User Guide.)

And here’s an example request body to create a rule that passes VPCs with the tag key Application and tag value Portal:

{
  "name": "AWS VPCs should be tagged Application:Portal",
  "source": "CUSTOM",
  "description": "AWS VPCs in this environment should be tagged with the key 'Application' and value 'Portal'",
  "provider": "AWS",
  "rule_text": "allow { input.tags.Application == 'Portal' }",
  "resource_type": "AWS.EC2.Vpc",
  "severity": "Low"
}

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 API 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 rule creation response – note that errors is null and status is ENABLED:

{
   "compliance_controls": [
      "0b4dc932-d5e1-42f0-802e-a2d71a2b3c4d"
   ],
   "created_at": 1574881762,
   "created_by": "61ae1bed-1b6f-4829-0000-123456789012",
   "created_by_display_name": null,
   "description": "AWS VPCs in this environment should be tagged with the key 'Application' and value 'Portal'",
   "errors": null,
   "id": "a3896797-15d7-486e-8dbf-098765432109",
   "name": "AWS VPCs should be tagged Application:Portal",
   "provider": "AWS",
   "resource_type": "AWS.EC2.Vpc",
   "rule_text": "allow { input.tags.Application == 'Portal' }",
   "severity": "Low",
   "source": "CUSTOM",
   "status": "ENABLED",
   "updated_at": null,
   "updated_by": null,
   "updated_by_display_name": null
}

Example error message – note that errors lists an error and status is INVALID:

{
  "compliance_controls": [
    "717deb94-62e8-47eb-bbab-a2d71a2b3c4d"
  ],
  "created_at": 1574882676,
  "created_by": "61ae1bed-1b6f-4829-8c85-123456789012",
  "created_by_display_name": null,
  "description": "AWS VPCs in this environment should be tagged with the key 'Application' and value 'Portal'",
  "errors": [
    {
      "severity": "error",
      "text": "fregot (custom_rules_engine error):\n  Expected a `policy` rule in the module for a multi-resource rule."
    }
  ],
  "id": "4edb5efc-5b48-4d5c-9c64-098765432109",
  "name": "AWS VPCs should be tagged Application:Portal",
  "provider": "AWS",
  "resource_type": "MULTIPLE",
  "rule_text": "allow { input.tags.Application == 'Portal' }",
  "severity": "Low",
  "source": "CUSTOM",
  "status": "INVALID",
  "updated_at": null,
  "updated_by": null,
  "updated_by_display_name": null
}

Modifying and Deleting Custom Rules - API

Note

There are some important things to note when sending an API request to modify or delete a rule – see Custom Rules API - Things to Know.

For UI instructions, see Modifying and Deleting Custom Rules - UI.

Modifying Custom Rules - API

(Example request | API Reference)

Getting scan data and testing a rule are not prerequisites for modifying a rule via the API, but we strongly recommend taking these steps first. The Fugue API 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.

Start by finding the rule ID for the rule you want to update. You can do this by listing all custom rules and then looking for the ID of the desired rule. Here’s an example curl command that lists all custom rules for an organization:

curl -X GET \
"https://api.riskmanager.fugue.co/v0/rules" \
  -u $CLIENT_ID:$CLIENT_SECRET

In the output, look for the id property:

{
  "count": 1,
  "is_truncated": false,
  "items": [
    {
      "compliance_controls": [
        "0b4dc932-d5e1-42f0-802e-a2d71a2b3c4d"
      ],
      "created_at": 1574881765,
      "created_by": "61ae1bed-1b6f-4829-0000-123456789012",
      "created_by_display_name": null,
      "description": "AWS VPCs in this environment should be tagged with the key 'Application' and value 'Portal' to",
      "id": "a3896797-15d7-486e-8dbf-098765432109",
      "name": "AWS VPCs should be tagged Application:Portal",
      "provider": "AWS",
      "resource_type": "AWS.EC2.Vpc",
      "rule_text": "allow { input.tags.Application == 'Portal' }",
      "severity": "Low",
      "source": "CUSTOM",
      "status": "ENABLED",
      "updated_at": null,
      "updated_by": null,
      "updated_by_display_name": null
    }
  ]
}

In the example above, the rule ID is a3896797-15d7-486e-8dbf-098765432109.

Next, send a PATCH request to the Fugue API /rules/{rule_id} endpoint, replacing {rule_id} with your rule ID. You’ll also need a JSON request body containing the following information – name, description, and status are optional and resource_type and rule_text are required:

(See the API Reference for more information.)

You can save the JSON in a file and attach it with the -d @{filename} option. Here’s an example curl request to /rules/{rule_id}:

curl -X PATCH \
"https://api.riskmanager.fugue.co/v0/rules/a3896797-15d7-486e-8dbf-098765432109" \
  -u $CLIENT_ID:$CLIENT_SECRET \
  -H "Content-Type: application/json" \
  -d @body.json

(You can also use a GUI such as Postman. For more information, see the API User Guide.)

And here’s an example request body to update a rule:

{
  "name": "AWS VPCs should be tagged Application:Finance",
  "description": "AWS VPCs in this environment should be tagged with the key 'Application' and value 'Finance'",
  "status": "ENABLED",
  "resource_type": "AWS.EC2.Vpc",
  "rule_text": "allow { input.tags.Application == 'Finance' }",
  "severity": "Medium"
}

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

Deleting Custom Rules - API

(Example request | API Reference)

Start by finding the rule ID for the rule you want to update, if you haven’t already. See instructions in Modifying Custom Rules - API.

Next, send a DELETE request to the Fugue API /rules/{rule_id} endpoint, replacing {rule_id} with your rule ID. Here’s an example curl command that deletes rule a3896797-15d7-486e-8dbf-098765432109:

curl -X DELETE \
"https://api.riskmanager.fugue.co/v0/rules/a3896797-15d7-486e-8dbf-098765432109" \
  -u $CLIENT_ID:$CLIENT_SECRET

(You can also use a GUI such as Postman. For more information, see the API User Guide.)

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

Viewing Compliance Results - API

For UI instructions, see Viewing Compliance Results - UI.

All custom rules with valid syntax automatically run against your environment on the next scheduled scan. After the scheduled scan runs or is kicked off manually, you can request the Custom compliance standard results from the API.

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

Compliance by Resource - API

The API 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 - API

For UI instructions, see Compliance by Resource Type - UI.

To view compliance by resource type using the API, see Listing Compliance Results by Resource Type for a Scan.

Compliance by Control - API

For UI instructions, see Compliance by Control - UI.

To view compliance by control using the API, see Listing Compliance Results by Control for a Scan.

Waiving Custom Rules - API

The API does not currently support waiving rules. To waive a rule using the UI, see How to Waive a Rule. See Waiving Rules to learn more about waivers.

Custom Rules API - Things to Know

There are three important things to remember about sending API requests for custom rules:

  1. Since the request body is JSON, certain special characters such as newlines and double quotes must be escaped.

  2. A simple rule should format the resource type according to the list on the service coverage pages (see AWS & AWS GovCloud and Azure & Azure Government) (e.g., "AWS.S3.Bucket", "Azure.Network.NetworkSecurityRule")

  3. An advanced rules should have a resource_type of MULTIPLE even if it involves only one resource type. (Hint: If your rule uses an allow or deny function, it’s a simple rule. If it uses one of the three advanced rule functions, it’s advanced.)

This is especially applicable to testing a rule, adding a rule, and modifying a rule.

Example Rules

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