Skip to content

Commit

Permalink
update example rules in docs, add TODO item
Browse files Browse the repository at this point in the history
  • Loading branch information
Larry Hitchon committed Apr 19, 2018
1 parent f6e64ef commit deb100d
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 22 deletions.
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
* Provide a default -query of 'Violations[]', and add an option for a full report
* Document conditions
* For Terraform, variables are currently parsed per file, but should be across all files provided
* Terraform converter wraps every map in an array - apparently it is valid HCL to have, e.g. "tags" appear multiple times in a resource
199 changes: 180 additions & 19 deletions docs/example-rules.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
# Example Rules

Add these rules to a YAML file, and pass the filename to config-lint using the -rules option.
Each rule contains a list of assertions, and these assertions use operations that are [documented here](operations.md)
Each rule contains a list of assertions, and these assertions use operations that are [documented here](operations.md).


* [Simple Expressions](#simple-expressions)
* [Boolean Expressions](#boolean-expressions)
* [Collection Expressions](#collection-expressions)
* [Dynamic Values](#dynamic-values)
* [Conditions](#conditions)
* [Macros](#macros)


## simple-expressions

To test that an AWS instance type has one of two values:

```
Version: 1
Description: Example rules
Type: Terraform
Files:
version: 1
description: Simple expression example
type: Terraform
files:
- "*.tf"
Rules:
rules:
- id: EC2_INSTANCE_TYPE
message: Instance type should be t2.micro or m3.medium
resource: aws_instance
Expand All @@ -22,17 +33,19 @@ Rules:
severity: WARNING
```

## boolean-expressions

This could also be done by using the or operation with two different assertions:

```
Version: 1
Description: Example rules
Type: Terraform
Files:
version: 1
description: Boolean expression example
type: Terraform
files:
- "*.tf"
Rules:
- id: EC2_INSTANCE_TYPE
message: Instance type should be t2.micro or m3.medium
message: Instance type shouldG be t2.micro or m3.medium
resource: aws_instance
assertions:
or:
Expand All @@ -45,27 +58,175 @@ Rules:
severity: WARNING
```

And this could also be done by looking up the valid values in an S3 object (HTTP endpoints are also supported)
## collection-expressions

There are three operators that simplify working with collections: [every](operations.md#every), [some](operations.md#some) and [none](operations.md#none).
You provide a JMESPath expression to extract the entire collection from the resource properties.
Then a separate set of expressions are applied to each element of the collection.
The expressions are the same as used for rule assertions.
The every operator requires all elements to return true for the expression, the some operator requires at least one element to return true, and the none operator requires all of the elements to return false for the expression.


```
Version: 1
Description: Example rules
Type: Terraform
Files:
version: 1
description: Collection expression example
type: YAML
files:
- "*.config"
resources:
- type: customer
key: customers[]
id: id
rules:
- id: CUSTOMER_LOCATIONS
message: Every customer location needs an address and a zip_code
resource: customer
severity: FAILURE
assertions:
- every:
key: locations
assertions:
- key: address
op: present
- key: zip_code
op: present
```

## dynamic-values

Instead of including a list of values directly in the rules file, it can be retrieved
from an S3 object at runtime. HTTP endpoints are also supported.

```
version: 1
description: Dynamic value example
type: Terraform
files:
- "*.tf"
Rules:
rules:
- id: EC2_INSTANCE_TYPE
message: Instance type should be t2.micro or m3.medium
resource: aws_instance
assertions:
- key: instance_type
op: eq
op: in
value_from: s3://your-bucket/instance-types.txt
severity: FAILURE
```

The assertions and operations were inspired by those in Cloud Custodian: http://capitalone.github.io/cloud-custodian/docs/
## conditions

Rules always have a condition based on the resource type, but you can add additional conditions. Here is an example
from the internal rule set used for the -validate option. This rule will only apply when a resource of type LintRuleSet
has a type equal to YAML. For that type of LintRuleSet, another attribute called resources must be present:

```
version: 1
description: Condition example
type: YAML
files:
- *.config
rules:
- id: YAML_RULES_HAVE_RESOURCES_SECTION
message: RuleSet for YAML required resources section
resource: LintRuleSet
severity: FAILURE
conditions:
- key: type
op: eq
value: YAML
assertions:
- key: resources
op: present
```

## macros

Because the rules are specified in YAML format, it is possible to use anchors and aliases as a simple kind of macro language to
eliminate duplicate expressions in a rule set. If you are familiar with Ruby on Rails configuration files, this might be familiar.

Here is an example where the rules for different resource types check for the same attribute names.
You can use the "&" to define an anchor. In this example there
are three of these: &has_name, &has_description and &has_name_and_description (the first two are actually used to
define the third one). Elsewhere in the file you can use the "*" (alias) and the "<<" (merge key) to insert
these expressions into multiple rules, without copying the entire expression map.

```
version: 1
description: Macro example
type: YAML
files:
- "*.config"
# some anchors to keep rules DRY
has_name: &has_name
key: name
op: present
has_name: &has_description
key: description
op: present
has_name_and_description: &has_name_and_description
and:
- <<: *has_name
- <<: *has_description
# resources to find in the config file
resources:
- type: widget
key: widgets[]
id: id
- type: gadget
key: gadgets[]
id: name
# rules to apply
rules:
- id: WIDGET_PROPERTIES
message: Widget needs name and description
severity: FAILURE
resource: widget
assertions:
- <<: *has_name_and_description
- id: GADGET_PROPERTIES
message: Gadget needs name a description
severity: FAILURE
resource: gadget
assertions:
- <<: *has_name_and_description
```

This feature of YAML can even be used for partial expressions. The JMESPath expression for find a specific tag in a Terraform resource is not particularly friendly, so that could be hidden in an anchor called "has_tag". Then a rule assertion can reference that, and include the tag name that is required.

```
Version: 1
Description: Use an alias to hide a complicated JMESPath expression
Type: Terraform
Files:
- "*.tf"
has_tag: &has_tag
key: "tags[]|[0].keys(@)"
op: contains
rules:
- id: HAS_NAME_TAG
message: Tags are required
resource: aws_ebs_volume
assertions:
- <<: *has_tag
value: Name
```

The assertions and operations were inspired by those in Cloud Custodian: http://capitalone.github.io/cloud-custodian/docs/
6 changes: 3 additions & 3 deletions docs/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ Example:
assertions:
- every:
key: Location
expresssions:
expressions:
- key: latitude
op: present
- key: longitude
Expand All @@ -277,7 +277,7 @@ Example:
assertions:
- some:
key: Location
expresssions:
expressions:
- key: latitude
op: present
- key: longitude
Expand All @@ -303,7 +303,7 @@ Example:
assertions:
- none:
key: "ipPermissions[]"
expresssions:
expressions:
- key: "fromPort"
op: eq
value: 22
Expand Down
49 changes: 49 additions & 0 deletions example-files/rules/alias.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
version: 1
description: Rules for generic YAML file
type: YAML
files:
- "*.config"

# some anchors to keep rules DRY

has_name: &has_name
key: name
op: present

has_name: &has_description
key: description
op: present

has_name_and_description: &has_name_and_description
and:
- <<: *has_name
- <<: *has_description

# resources to find in the config file

resources:
- type: widget
key: widgets[]
id: id
- type: gadget
key: gadgets[]
id: name

# rules to apply

rules:

- id: WIDGET_PROPERTIES
message: Widget needs name and description
severity: FAILURE
resource: widget
assertions:
- <<: *has_name_and_description

- id: GADGET_PROPERTIES
message: Gadget needs name a description
severity: FAILURE
resource: gadget
assertions:
- <<: *has_name_and_description

17 changes: 17 additions & 0 deletions example-files/rules/no-iam-actions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 1
description: Do not allow IAM actions
type: Terraform
files:
- "*.tf"
rules:

- id: NO_IAM_ACTIONS
message: IAM roles should not allow IAM actions
resource: aws_iam_role
assertions:
- key: assume_role_policy.Statement[].Action[]
op: not-contains
value: "iam:*"
severity: FAILURE
tags:
- iam

0 comments on commit deb100d

Please sign in to comment.