-
Notifications
You must be signed in to change notification settings - Fork 1.1k
HowTo: Create a new rule
Scout Suite rules use a recursive engine and a battery of test cases, which means no Python or coding skills are necessary to create or modify a rule; however, understanding of Scout Suite's data structure may be necessary if you're starting from scratch.
The following is a complete list of rule attributes that may be defined in the JSON rule definition:
-
description
(required): A brief description of the rule, displayed on the service's dashboard. This field allows HTML formatting. -
rationale
: An explanation of why the rule matters, displayed when clicking on the+
icon in the service dashboard. This field allows HTML formatting. -
remediation
: Content regarding issue remediation. This field allows HTML formatting. -
compliance
: A list of objects explaining which compliance measure, version, and reference point to look towards to understand. -
references
: A list ([]
) of URL links to reference documents for this finding. -
dashboard_name
(required): The human-friendly name of the resources that are checked, displayed on the service's dashboard. -
display_path
: The path to the parent resource that must be displayed when inspecting the rule's results. This is useful then thepath
the rule applies to differs. If this value is not provided, clicking on the finding will default to the value defined in `path. -
path
(required): The path to the resources for which the rule applies.id
is used when iteration over all items in a list or dictionary should be applied. Defines the resources that will be displayed when clicking on a finding in the dashboard. -
conditions
(required): A list of conditions that, if met, will result in the resource to be flagged. -
key
: Legacy field from the HTML ruleset generator -
keys
: Legacy field from the HTML ruleset generator -
arg_names
: Legacy field from the HTML ruleset generator -
id_suffix
: If a custom HTML view has been created, this is used to enable color highlighting based on HTML IDs. -
class_suffix
: If a custom HTML view has been created, this is used to enable color highlighting based on HTML classes.
All Scout Suite rules are defined under ScoutSuite/providers/<provider>/rules/findings/
. The following snippet is the entire definition of the User without MFA
rule. Let's have a look at the various values that are defined to make it work:
- description: A brief description of the rule, displayed on the service's dashboard.
- path: The path to the resources for which the rule applies.
id
is used when iteration over all items in a list or dictionary should be applied. - dashboard_name: The human-friendly name of the resources that are checked, displayed on the service's dashboard.
- conditions: A list of conditions that, if met, will result in the resource to be flagged.
- id_suffix: If a custom HTML view has been created, this is used to enable color highlighting.
{
"description": "User without MFA",
"path": "iam.users.id",
"dashboard_name": "Users",
"conditions": [ "and",
[ "iam.users.id.", "withKey", "LoginProfile" ],
[ "iam.users.id.MFADevices", "empty", "" ]
],
"id_suffix": "mfa_enabled"
}
At the very least, these five attributes must be set when creating a new rule for Scout Suite.
As mentioned above, the conditions
attribute is a list of conditions that must be met in order for the processing engine to flag the resource as a finding. The basic format of a condition expression is as follow:
-
The first element may be string that declares the logical operation that must be performed when combining each condition's result when multiple conditions are necessary; its value must be one of "and" or "or".
-
Any other element must be a list of 3 items:
- The path to the value to be tested
- The test case to be used (provided by opinel)
- The value to be tested against
If a rule can be summarized by a single condition, it may be defined as follow:
"conditions" = [ "path_to_value_1", "equal", "trigger_value_1" ]
If multiple conditions are necessary, then the format would look as follow:
"conditions" = [
"and",
[ "path_to_value_1", "equal", "trigger_value_1" ],
[ "path_to_value_2", "equal", "trigger_value_2" ]
]
Note that conditions may be nested, so a more complex rule may look like the following:
"conditions" = [
"and",
[ "path_to_value_1", "equal", "trigger_value_1" ],
[ "path_to_value_2", "equal", "trigger_value_2" ],
[
"or",
[ "path_to_value_3", "equal", "trigger_value_3" ],
[ "path_to_value_4", "equal", "trigger_value_4" ]
]
]
To avoid code duplication, conditions that are used in multiple rules may be declared in standalone files and included in a rule. In this case, the definition of the rule's conditions would look as follow.
"conditions" = [
"and",
[ "path_to_value_1", "equal", "trigger_value_1" ],
[ "_INCLUDE_(conditions/condition-filename.json)", "", ""]
]
Where the files stored under ScoutSuite/providers/<provider>/rules/conditions/condition-filename.json
contains the following payload:
{
"conditions": [ "path_to_value", "testCase", "test_value" ]
}
Sometimes, it can be necessary to perform tests against dynamic values. The _GET_VALUE_AT_
macro can help to parameterize the rule at runtime. For example, the rule defined in ScoutSuite/providers/aws/rules/findings/ec2-security-group-opens-all-ports-to-self.json
, which flags security groups that create a virtually flat network between all instances associated with the group, is defined as follow:
{
"description": "Unrestricted Network Traffic within Security Group",
"dashboard_name": "Rules",
"display_path": "ec2.regions.id.vpcs.id.security_groups.id",
"path": "ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.security_groups.id",
"conditions": [
"and",
[
"_INCLUDE_(conditions/security-group-opens-all-ports.json)",
"",
""
],
[
"ec2.regions.id.vpcs.id.security_groups.id.rules.id.protocols.id.ports.id.security_groups.id.GroupId",
"equal",
"_GET_VALUE_AT_(ec2.regions.id.vpcs.id.security_groups.id)"
]
]
}
Notice the use of the shared condition "security-group-opens-all-ports" in this rule. The second condition checks whether one of the security group grants authorizes an EC2 security group whose ID matches the source group ID. This is enabled by the use of _GET_VALUE_AT_
Some rules may require knowledge of the ID associated with different type of resources and combine them in order to fetch the right test value. Similar to test values, the _GET_VALUE_AT_
command may be used to provide a parameterized path to the source value at runtime. For example, matching EC2 instances with network ACL configuration can be challenging for the following reasons:
- Network ACLs are defined at a VPC level
- Network ACLs are associated at a subnet level
- EC2 instances inherit their subnet's ACLs
In order to create a rule or finding that flags EC2 instances whose subnet's NACLs are wide open, several calls to _GET_VALUE_AT_
are necessary, as illustrated in the following snippet:
{
"conditions":
[ "vpc.regions.id.vpcs.id.network_acls._GET_VALUE_AT_(vpc.regions.id.vpcs.id.subnets._GET_VALUE_AT_(ec2.regions.id.vpcs.id.instances.id.network_interfaces.id.SubnetId).network_acl).allow_all_ingress_traffic", "notEqual", "0" ]
}
This snippets illustrates that calls to _GET_VALUE_AT_
may be nested. In such event, the processing engine resolves the deepest _GET_VALUE_AT_
, then iterates back to the top until all values are resolved. In this example, values
would be resolved in this order:
- The subnet ID associated with the network interface
- The network ACL ID associated with the previously determined subnet ID
Scout Suite processes two rulesets at each run:
- The findings ruleset, which is used to compute the data displayed on the
various dashboards. Unless a different ruleset is specified, the default ruleset
will be processed. A custom finding ruleset may be specified using the
--ruleset
argument, as illustrated below:
$ scout --profile <profile> --ruleset ScoutSuite/providers/azure/rules/rulesets/cis-1.0.0.json
- The filters ruleset, which is used to compute filter data on the various resource-specific views. There is currently no option to specify a different filter ruleset.
- Home
- Getting Started
- Setup
- Compliance
- Configuration and Usage
- Docker
- [v6] Upgrade to v6-alpha
- Advanced Usage
- Understanding the Architecture
- How to Contribute
- FAQ