Creating Infrastructure as Code (IaC) custom rules

Learning how to create IaC custom rules

Introduction to IaC custom rules

Before we begin, let us discuss

  • Why do Snyk users need Infrastructure as Code (IaC) custom rules and what are the benefits?
  • How has the workflow changed with the new release of IaC Custom Rules?

Terminology

The following terms will be used throughout this lesson

  • Custom Rule Repository - The collection of rules, specs, expected spec test results - also known as the project. This entire collection should be version-controlled.
  • Project - The project is the entire collection of rules, specs, expected spec test results, and is ultimately the name of your bundle. Project = Bundle name
  • Folder - This will be the directory to hold
  • Bundle - When you push your project to the Snyk app, the collection of rules in your project is saved as a bundle.
  • Rule - A rule is the actual check that is being performed by the code that you’ve written.
  • Resource type - This tells the policy engine what resources to check. The resource type is either declared, or you can use “MULTIPLE” to indicate that you’ve named the resource type as a variable in your rule code.
  • Rule Spec - Terraform file, cloudformation file, ARM template, or cloud input JSON used to test the custom rule
  • Manifest.json - When you push your rule bundle, this file is used to determine where it should be pushed. It contains an Org ID, used to determine which organization the bundle should be pushed to, and a Bundle ID, used to determine if the bundle exists already and should be updated, or if it should be created.

File structure Reference

As you proceed through the steps, the following file structure will be created, with each step creating a file.

File Structure

A custom code repository is comprised of the following structure

  • Lib - folder that contains shared rego files for use by all rules
    • Relations.rego - rego file that contains resource relationships.
  • Manifest - contains the bundle ID and the Org ID
  • Rules - folder that contains a file for each of your custom rules
  • Spec - folder which contains additional folders for each rule. In the folder for the rule contains the actual spec files, which will be a .tf, .json, .yaml file corresponding to the IaC platform that your rule is written for.

Scan your code & stay secure with Snyk - for FREE!

Did you know you can use Snyk for free to verify that your code
doesn't include this or other vulnerabilities?

Scan your code

Creating IaC+ custom rules in Snyk

In this lesson, you will learn how to build custom rules for Snyk's Infrastructure as Code (IaC) workflows, with an example where we will build a rule prohibiting public instances of EC2 from being used.

During this process, you will create a rule repository that resides locally on your machine. Once you create the rules that you want to incorporate, you push them to Snyk so that they can be used, along with the Snyk library of rules, across all of your IaC workflows.

Step 1: Create a custom rule repository (aka project) A repository is how you will version control your rules. This is typically done using .git commands, but you can use any source code repository.

Step 2: Create a rule. A rule is the misconfiguration that you are looking for the policy engine to flag as an issue. In this example, we will define a rule to deny public access to an EC2 instance.

Step 3: Create a rule spec. A rule spec is an example of the misconfiguration that you want the policy engine to flag as an issue. This is similar to a test case. We are creating input that the policy engine can use to determine what is and is not misconfigured according to your rule. For exercise, we would provide an example with and without public access to test with.

Step 4: Test your IaC rules. In this step, you will validate the rules you have created against some spec file you created locally.

Step 5: Push your IaC Tests. This will allow you to share the rules and have applied everywhere

Step 6: Test your rules with IAC Test against local files via CLI or SCM import. Last but not least, this course will share a sample rules bundle for your inspection.

Step 1: Creating a custom rule repository and rule using the Snyk CLI

In this step, we will discuss creating a rules repository by running the init command and selecting Project. This initializes the folder and creates all of the directories that the rules CLI will need and names your bundle. Your bundle is for when you push your Project to the Snyk app, where the collection of rules in your Project is saved as a bundle.

Commands:

  1. Run Command: snyk iac rules init
  2. Choose: project

The following folder structure will be created

IaC plus - customrules - creating a project

The rules directory above is the main folder for each of your rules. Each rule will get its own folder. Once created, and in that folder will be a file main.rego, which contains the code for your rule.

Step 2: Creating a rule in your code repository

In this step, we will discuss creating a rule. You will provide an ID and a name. Afterwards, you will provide metadata like the severity of the issue and a description.

You will indicate what type of rule you want to create:

  • IaC - Essentially IaC as scanned by CLI, IDE, and Git integrations with Snyk
  • Cloud - Using the Cloud Integrations (AWS, Azure, Google) and looking at production resource configurations
  • Both - When using Terraform, the rule can be written for IaC or Cloud configurations.

You will also need to select the file type, such as TF (Terraform files), ARM (JSON), or CloudFormation (JSON or yaml), because your Spec file extension will be based on the format of the specific platforms.

Lastly, you will select the resource type, where you are indicating what sort of resource you want to use as Input for inspection for misconfigurations.

The end result is a rule folder and a rule file, i.e. main.rego, used to run against your input.

The example in the first video starts by defining a new rule that indicates EC2 public instances should not be used. In the second video, we will show an example of how to declare the rule.

Commands

  1. Run the command: snyk iac rules init
  2. Choose: rule

What does this create?

  • This command creates our rule folder and a rule file main.rego
  • Our rule code goes in main.rego The following folder structure will exist after running the command

iacplus-customrules-rules

To learn how to write Rego, there are many courses available online, such as https://academy.styra.com/courses/opa-rego

For metadata, please see README and examples on: Snyk-Labs

Step 3: Creating a rule specification

In this step we will discuss creating a rule specification. A "spec" is essentially a test file with valid and invalid configurations of the resources we are inspecting.

Commands

  1. Run the following command: snyk iac rules init
  2. Choose: rule spec

What does this create?

  • This creates a rules directory in the "spec" directory, and then a directory called "inputs", where the spec file is created. The spec file itself will have the file extension based on the spec type that you created.

What is the directory view after this is added?

iacplus-customrules-rulespec

Step 4: Running "snyk iac rules test"

In this step we will discuss how our rule evaluates against the spec files we create. When we run our commands we are telling the CLI to run/test against the spec files in the folders that match the rule name folders. For example, our main.rego file in the "INSTANCE_RULE" folder will run against the spec in the "spec/rules/INSTANCE_RULE/inputs/instance.tf" file. The resulting output will be a JSON document listing the name of the resource with a passed: true, or passed: fail result. For simplicity sake, it is recommended to name the resource that you expect to pass “valid” and the resource that you expect to fail, “invalid”.

Finally, we want to run it again with the --update-expected flag if the JSON document is not produced. That output will appear in spec/rules/INSTANCE_RULE/expected/instance.json

Commands

Run the following commands:

  • snyk iac rules test
  • snyk iac rules test --update-expected

What does this do?

  • This tests the rule you create against the spec file.
  • When you add the --update-expected flag, it produces a file that shows the results against our spec. That JSON file will show us whether the resources defined in our spec pass or fail. Look for your desired outcomes by naming your resources “valid” and “invalid”. You can also have multiple valid or invalid cases by giving them unique names like “valid1” and “valid2”.

What files are created?

  • A JSON file is created and it is the output of the test result against our spec. It will be named whatever you named your spec_file.json. In this case, it is instance.json and gives the output of whether the valid or invalid test passed. If your invalid is passed:true then you need to review your spec as well as your rule to troubleshoot.

What is the directory view after we do this?

iacplus-customrules-iacrulestest

Step 5: Pushing the IaC rules

In this step, we will discuss the process for pushing your rule bundle to your Snyk Organization to be used whenever you are testing IaC files.

Pushing your IaC rules is the act of sharing your bundle and pushing it to your default or specified Organization in Snyk. This command also updates your manifest.json file and populates it with a custom_rule_id and the associated organization_id

Commands Run the following command:

  • snyk iac rules push

It's strongly suggested to include --org= with the appropriate Organization ID, to target where the upload will occur. Otherwise, it will be directed to your default Organization in Snyk.

Step 6: Testing your rules with "snyk iac test"

In this step we will discuss how to test your new rule against a Terraform file. While this example is using the CLI to test a local file, which just happens to be the sample file we used as a spec file for simplicity’s sake, you can use any file that would have the expected behavior you want to test. Also note that when you rescan a file via SCM integration in the Snyk UI, these rules will also be applied/tested.

Commands

Run the following command:

  • snyk iac test

Add the --org= option, with the appropriate Organization ID to ensure the correct rules are applied.

View the results: iacplus-customrules-iactest

Updating/deleting your rules

Updating A Rule

Whenever you change your rule code and then run snyk iac rules push - the CLI will use the manifest.json file and either create a new bundle or update the bundle.

Deleting a Rule

Deleting a rule within your bundle is the same process. You delete the rego file and spec then push the bundle again.

Deleting a Bundle

Deleting an entire bundle can be done via the API. For more information, see https://apidocs.snyk.io/experimental?version=2023-08-23%7Eexperimental#get-/orgs/-org_id-/cloud/rule_bundles

Example IaC custom rules

Now that you have seen how to create, push, and test a rule, try creating one in your own Snyk instance. Be sure not to do this in your production Snyk environment until you have real rules you want to create.

The following are some demonstration rules that you can review and learn from

Congratulations

Congrats! You know all about IaC custom rules. Check out our other lessons to learn more about using Snyk.