Managing Custom Rules - API

Note

For UI instructions, see Managing Custom Rules - UI.

For CLI instructions, see Managing Custom Rules - CLI.

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

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

Creating Custom Rules - API

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)

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

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 API - Test the Rule

(Example request | API Reference)

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 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 (be sure to escape newlines and double quotes!), 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.

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 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. We decided to include the resource type in the Rego code, so we set the resource_type request body parameter to DEFINED_IN_CODE, and defined the resource_type declaration inside rule_text as aws_vpc.

{
    "resource_type": "DEFINED_IN_CODE",
    "rule_text": "package rules.app_tag\n\ndefault allow = false\n\nresource_type = \"aws_vpc\"\n\nallow { input.tags.Application == 'Portal' }",
    "scan_id": "535d21d2-700b-4b4f-9aa9-123456789012"
}

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 tenant!)

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)

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

  • providers: The provider(s) for the rule. Values - AWS, AWS_GOVCLOUD, AZURE, GOOGLE, REPOSITORY, or any combination. (For Azure Government, select AZURE.) Note that the provider parameter is deprecated; use providers instead.

  • resource_type: The resource type the rule applies to.

    • If your rule involves the REPOSITORY provider or multiple providers (whether simple or advanced), you must define the resource_type in code (the rule_text request body parameter) and set the resource_type request body parameter to DEFINED_IN_CODE.

    • Otherwise, for simple rules, specify the actual resource type used in the rule. (e.g., aws_vpc)

    • Otherwise, for advanced rules, always use "MULTIPLE", even if the rule involves a single resource type.

  • rule_text: Rego code used by the rule. Be sure to escape newlines and double quotes. See Writing Custom Rules.

  • 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'",
  "providers": ["AWS"],
  "rule_text": "package rules.app_tag\n\ndefault allow = false\n\nresource_type = \"aws_vpc\"\n\nallow { input.tags.Application == 'Portal' }",
  "resource_type": "DEFINED_IN_CODE",
  "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 tenant!)

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",
   "providers": ["AWS"],
   "resource_type": "DEFINED_IN_CODE",
   "rule_text": "allow { input.tags.Application == 'Portal' }",
   "severity": "Low",
   "source": "CUSTOM",
   "status": "ENABLED",
   "tf_resource_type": null,
   "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",
  "providers": ["AWS"],
  "resource_type": "DEFINED_IN_CODE",
  "rule_text": "package rules.app_tag\n\ndefault allow = false\n\nresource_type = \"MULTIPLE\"\n\nallow { input.tags.Application == 'Portal' }",
  "severity": "Low",
  "source": "CUSTOM",
  "status": "INVALID",
  "tf_resource_type": null,
  "updated_at": null,
  "updated_by": null,
  "updated_by_display_name": null
}

Modifying and Deleting Custom Rules - API

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",
      "providers": ["AWS"],
      "resource_type": "DEFINED_IN_CODE",
      "rule_text": "package rules.app_tagnndefault allow = falsennresource_type = "aws_vpc"nnallow { input.tags.Application == 'Portal' }",
      "severity": "Low",
      "source": "CUSTOM",
      "status": "ENABLED",
      "tf_resource_type": null,
      "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 whichever of the following fields you want to change:

  • name: Name of the rule

  • source: Always "CUSTOM"

  • description: Description of the rule

  • providers: The provider(s) for the rule. Values - AWS, AWS_GOVCLOUD, AZURE, GOOGLE, REPOSITORY, or any combination. (For Azure Government, select AZURE.) Note that the provider parameter is deprecated; use providers instead.

  • resource_type: The resource type the rule applies to.

    • If your rule involves the REPOSITORY provider or multiple providers (whether simple or advanced), you must define the resource_type in code (the rule_text request body parameter) and set the resource_type request body parameter to DEFINED_IN_CODE.

    • Otherwise, for simple rules, specify the actual resource type used in the rule. (e.g., aws_vpc)

    • Otherwise, for advanced rules, always use "MULTIPLE", even if the rule involves a single resource type.

  • rule_text: Rego code used by the rule. Be sure to escape newlines and double quotes. See Writing Custom Rules.

  • 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/{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": "DEFINED_IN_CODE",
  "rule_text": "package rules.app_tag\n\ndefault allow = false\n\nresource_type = \"aws_vpc\"\n\nallow { 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!)

Example Rules

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

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.

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

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, 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

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

Compliance by Control - API

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

Waiving Custom Rules - API

To waive a rule using the API, see Creating a Rule Waiver.

Disabling and Enabling Custom Rules - API

To disable or enable a rule, simply modify the rule and set status to ENABLED or DISABLED. See Enabling and Disabling Rules for more information.