We use cookies to ensure you get the best experience on our website.Read moreRead moreGot it

close
  • Products
    • Products
      • Snyk Code (SAST)
        Secure your code as it’s written
      • Snyk Open Source (SCA)
        Avoid vulnerable dependencies
      • Snyk Container
        Keep your base images secure
      • Snyk Infrastructure as Code
        Develop secure cloud infrastructure
      • Snyk Cloud
        Keep your cloud environment secure
    • Solutions
      • Application security
        Build secure, stay secure
      • Software supply chain security
        Mitigate supply chain risk
      • Cloud security
        Build and operate securely
    • Platform
      • What is Snyk?
        Developer-first security in action
      • Developer security platform
        Modern security in a single platform
      • Security intelligence
        Comprehensive vulnerability data
      • License compliance management
        Manage open source usage
      • Snyk Learn
        Self-service security education
  • Resources
    • Using Snyk
      • Documentation
      • Vulnerability intelligence
      • Product training
      • Support & services
      • Support portal & FAQ’s
      • User hub
    • learn & connect
      • Blog
      • Community
      • Events & webinars
      • DevSecOps hub
      • Developer & security resources
    • Listen to the Cloud Security Podcast, powered by Snyk
  • Company
    • About Snyk
    • Customers
    • Partners
    • Newsroom
    • Snyk Impact
    • Contact us
    • Jobs at Snyk We are hiring
  • Pricing
Log inBook a demoSign up
All articles
  • Application Security
  • Cloud Native Security
  • DevSecOps
  • Engineering
  • Partners
  • Snyk Team
  • Show more
    • Vulnerabilities
    • Product
    • Ecosystems
Cloud Native SecurityDevSecOps

Developing custom IaC rules with Snyk

Teodora SanduNovember 18, 2021

In an increasingly cloud native world, infrastructure as code (IaC) is often the first point of entry into an application. And with technologies such as Kubernetes and Terraform becoming increasingly popular, most app developers will update at least one Kubernetes or Terraform resource at one point in their career. 

But while updating and maintaining infrastructure can be as simple as managing a few configuration files — or as complicated as orchestrating a complex architecture with multiple cloud native stacks — one thing holds true: infrastructure security is crucial to app security. And even though many cloud providers and IaC scanning tools have built-in or community-contributed configuration and security rulesets, infrastructure is often too diverse and too complex for a “one-size secures all” approach.

In this article, I’ll walk you through securing your infrastructure environment with Snyk IaC custom rules. Leveraging the Snyk IaC rules (snyk-iac-rules) SDK, you can now write, test, and bundle custom infrastructure rules for the Snyk CLI.

Maximize flexibility with Open Policy Agent (OPA)

Behind the scenes, Snyk IaC uses Open Policy Agent (OPA), an open source general policy agent, and its language Rego to define custom rules. As a framework-agnostic agent, OPA makes it really easy for teams to modify and enforce policies across their cloud native stack, whether it’s for infrastructure, application authorization, or Kubernetes admission control. 

Since rules are written in OPA’s native query language, they are also exportable and reusable outside of Snyk. This means any investment you make here can be used across the OPA ecosystem of integrations.

For the walkthrough, you’ll need a basic understanding of OPA, as well as WebAssembly (Wasm) and OCI artifacts, which we use to bundle and distribute the rules.

Secure better with custom rules

Custom rules allow you to cater to every specific use case, making them a powerful tool when combined with prebuilt threat-modeled rulesets from security experts. 

As a custom rule example, let’s say I’m a security architect and have a specific internal requirement that all Terraform aws_iam_role resources in our application be tagged with owner, description, and type tags. 

This means I’d want to run a rule that:

  • Ensures any existing or future IAM role resources have an owner, description, and type tag
  • Notifies app developers when they forget to add tags.

I’d also want to configure our CI/CD to fail when a code change happens that doesn’t follow this standard, so it doesn’t end up in our production environments.

How would I like to do that? The answer is by configuring the Snyk CLI to run inside my CI/CD with a custom set of rules that I write, bundle, and publish to a safe place of my choice.

Developing a custom IaC rule with Snyk

With the new Snyk IaC rules SDK, I can do exactly that. I install it on my machine and with the help of the custom rules documentation I can quickly get my new tagging standard enforced in the Snyk CLI.

Take as an example the following Terraform resource, which I want to contain our owner, description, and type tags:

resource "aws_iam_role" "denied" {
  name = "denied"
  assume_role_policy = jsonencode({
      Version   = "2012-10-17"
      Statement = [
        {
          Action    = "sts:AssumeRole"
          Effect    = "Allow"
          Sid       = ""
          Principal = {
            Service = "ec2.amazonaws.com"
          }
        },
      ]
  })
  tags = {
    description = "a tag that describes something"
  }
}

Following the getting started documentation in the custom rules documentation, I run the template command to generate a skeleton rule:

$ snyk-iac-rules template --rule CUSTOM-RULE-8

I want the tagging standard to be a medium-level severity rule, so I modify the template as such and customize the title and message:

package rules

aws_iam_role_tags_missing(resource) {
    not resource.tags.owner
}

aws_iam_role_tags_missing(resource) {
    not resource.tags.description
}

aws_iam_role_tags_missing(resource) {
    not resource.tags.type
}

deny[msg] {
    resource := input.resource.aws_iam_role[name]
    aws_iam_role_tags_missing(resource)

    msg := {
        "publicId": "CUSTOM-RULE-8",
        "title": "IAM Role missing one of the required tags: owner, description or type",
        "severity": "medium",
        "msg": sprintf("input.resource.aws_iam_role[%s].tags", [name]),
        "issue": "",
        "impact": "",
        "remediation": "",
        "references": [],
    }
}

Before I bundle and publish the rule, I write some unit tests to verify the behaviour of the rule and put my example Terraform fixture file in the generated ./rules/CUSTOM-RULE-8/fixtures/denied2.tf file:

package rules

import data.lib
import data.lib.testing

test_CUSTOM_RULE_8 {
        # array containing test cases where the rule is allowed
        allowed_test_cases := []

        # array containing cases where the rule is denied
        denied_test_cases := [{
            "want_msgs": ["input.resource.aws_iam_role[denied].tags"],
            "fixture": "denied2.tf",
        }]

        test_cases := array.concat(allowed_test_cases, denied_test_cases)
        testing.evaluate_test_cases("CUSTOM-RULE-8", "./rules/CUSTOM-RULE-8/fixtures", test_cases)
}

You can find this rule and more in our public GitHub repository.

$ snyk-iac-rules test
​​PASS: 1/1

Once I run my tests and am satisfied with them passing, I bundle the rule using the SDK and can even test it locally with the Snyk CLI by using the --rules flag. First, I make sure to be authenticated with a test-org organization, where I aim to run all of my custom rules experiments from now on:

$ snyk auth

Then, I build my custom rules bundle and pass it to the --rules flag so that I can make sure my IaC issues get flagged up:

$ snyk-iac-rules build .
Generated bundle: bundle.tar.gz

$ snyk iac test --rules=bundle.tar.gz ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf

Testing ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf...


Infrastructure as code issues:
  ✗ IAM Role missing one of the required tags: owner, description or type [Medium Severity] [CUSTOM-RULE-8]
    introduced by input > resource > aws_iam_role[denied] > tags


Organization:      test-org
Type:              Terraform
Target file:       ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf
Project name:      fixtures
Open source:       no
Project path:      ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf

Tested ./fixtures/custom-rules/rules/CUSTOM-RULE-8/fixtures/denied2.tf for known issues, found 1 issues

With the confidence that the Snyk CLI can interpret my rule, I push it to an OCI registry, in this case DockerHub, and tag it as the very first version of my custom rules. This way if I deliver any breaking changes in future, I can do a gradual rollout of the rules by using a new tag:

$ snyk-iac-rules push --r docker.io/snykgoof/oci-example:v1 bundle.tar.gz

Last but not least, I enforce the usage of my new custom rule across all teams in my department by configuring the IaC Settings for my Snyk group through the public Group IaC Settings API. 

curl --location --request PATCH 'https://api.snyk.io/v3/groups/<group_id>/settings/iac/?version=2021-11-03~beta' \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: token <API key from Snyk>' \
--data-raw '{
   "data": {
         "type": "iac_settings",
         "attributes": {
           "custom_rules": {
             "oci_registry_url": "https://registry-1.docker.io/snykgoof/oci-example",
             "oci_registry_tag": "v1",
             "is_enabled": true
           }
       }
   }
}'

I have automated all these steps using a GitHub action workflow, as can be seen in our public GitHub repository. Now, any app developer or CI/CD pipeline authenticated with an organization underneath my group will be using my custom rule. For more information about how to integrate the Snyk CLI and the Snyk IaC Rules SDK with GitHub, please read our documentation.

If we decide to apply different custom rules for different parts of the company, we can also do that by overriding the custom rules settings at the organization level and so have a different set of custom rules run for that organization only. For example, in order to continue using the --rules flag to test my custom rules with the Snyk CLI, I have configured my test-org organization to have the custom rules settings disabled. This way, I can provide my own custom rules locally:

Configuring custom iac rules in snyk iac

I may decide in the future that the Platform team needs a more restrictive set of custom rules, so I will configure their organization to use a different custom rules bundle, stored under a different OCI artifact. 

Reaping the benefits of Snyk IaC custom rules

We have seen how I, as a security architect, have used the Snyk IaC rules SDK to configure a new set of security standards for my department. Now, we can see how I, as an app developer, benefit from this feature during development time.

Let’s say I am adding a new aws_iam_role resource to our application’s Terraform infrastructure so that I can configure a new IAM role:

resource "aws_iam_role" "new_role" {
  name               = "new_role"
  assume_role_policy = jsonencode({
    Version   = "2021-11-18"
    Statement = [
      {
        Action    = "sts:AssumeRole"
        Effect    = "Allow"
        Sid       = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

I have tested this locally and verified that my IAM role was configured correctly. However, I have forgotten that my department requires very strict tagging for all our resources. As I go to open a PR though, I can see that the repository I’m pushing to has been configured to run the Snyk IaC GitHub Action and is failing. 

Testing with custom iac rules

I look at the results and notice that my new file is causing the PR check to fail, more specifically that my resource is missing an owner, description, and type tag.

Result set from custom iac rules

I go back to my code and add the missing tags and now after I push my change and the PR check reruns, I can safely and confidently push the new resource to our production environment!

Securing your applications with Snyk IaC

Snyk Infrastructure as Code (Snyk IaC) helps you develop fast while staying secure by providing developers with the security intelligence and in-line fixes for Terraform, CloudFormation, Kuberenetes configurations, and ARM templates that can be directly merged into code.

Snyk IaC works where developers do, integrating with systems like Terraform Cloud and CI/CD tools as well as developer tools like source code management (GitHub, GitLab, Bitbucket) and IDEs. 

You can get started now for free with Snyk IaC on our platform or through downloading the latest Snyk CLI. 

Discuss this blog on Discord

Join the DevSecOps Community on Discord to discuss this topic and more with other security-focused practitioners.

GO TO DISCORD
Footer Wave Top
Patch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo Segment
Develop Fast.
Stay Secure.
Snyk|Open Source Security Platform
Sign up for freeBook a demo

Product

  • Developers & DevOps
  • Vulnerability database
  • API status
  • Pricing
  • IDE plugins
  • What is Snyk?

Resources

  • Snyk Learn
  • Blog
  • Security fundamentals
  • Resources for security leaders
  • Documentation
  • Snyk API
  • Disclosed vulnerabilities
  • Open Source Advisor
  • FAQs
  • Website scanner
  • Code snippets
  • Japanese site
  • Audit services
  • Web stories

Company

  • About
  • Snyk Impact
  • Customers
  • Jobs at Snyk
  • Snyk for government
  • Legal terms
  • Privacy
  • Press kit
  • Events
  • Security and trust
  • Do not sell my personal information

Connect

  • Book a demo
  • Contact us
  • Support
  • Report a new vuln

Security

  • JavaScript Security
  • Container Security
  • Kubernetes Security
  • Application Security
  • Open Source Security
  • Cloud Security
  • Secure SDLC
  • Cloud Native Security
  • Secure coding
  • Python Code Examples
  • JavaScript Code Examples
  • Code Checker
  • Python Code Checker
  • JavaScript Code Checker
Snyk|Open Source Security Platform

Snyk is a developer security platform. Integrating directly into development tools, workflows, and automation pipelines, Snyk makes it easy for teams to find, prioritize, and fix security vulnerabilities in code, dependencies, containers, and infrastructure as code. Supported by industry-leading application and security intelligence, Snyk puts security expertise in any developer's toolkit.

Resources

  • Snyk Learn
  • Blog
  • Security fundamentals
  • Resources for security leaders
  • Documentation
  • Snyk API
  • Disclosed vulnerabilities
  • Open Source Advisor
  • FAQs
  • Website scanner
  • Code snippets
  • Japanese site
  • Audit services
  • Web stories

Track our development

© 2023 Snyk Limited
Registered in England and Wales
Company number: 09677925
Registered address: Highlands House, Basingstoke Road, Spencers Wood, Reading, Berkshire, RG7 1NT.
Footer Wave Bottom