Using Terrascan for Static Code Analysis of Your Infrastructure Code (part 2)

You followed my advice and configured terrascan as a pre-commit hook to scan your terraform code for security weaknesses on your desktop before being committed into your repository. 

The setup allows you to quickly check any security issues before they’re introduced into your AWS environment. 

You’ve been using it for a while and you’re pretty happy that it has caught some issues before you accidentally pushed them to your GitHub repository. 

Unfortunately, not all of your co-workers have it installed and some nasty bugs have been committed into one of your feature branches. 

Luckily, terrascan can be used as a step in your continuous integration (CI) pipeline. This would allow you to test your terraform code before any security weaknesses are merged into your master branch. 

How do you do that? 

Let’s create an example repo. 

$ mkdir  terrascan-example && cd terrascan-example
$ git init .

I’ll be using “hub” for this example on my mac. If you don’t have it installed you can follow the instructions for your OS here. Here’s an example using the org “cloud-security-musings” and the repo “terrascan-example”. You’ll need to use your own username/repo combination: 

$ hub create -d "terrascan usage example" cloud-security-musings/terrascan-example

You should now have a new repository created in GitHub and configured as a remote named “origin”. Let’s confirm.

$ git remote -v
origin    git@github.com:cloud-security-musings/terrascan-example.git (fetch)
origin    git@github.com:cloud-security-musings/terrascan-example.git (push)

As in part 1 of this blog series, you need to add a “.pre-commit-config.yaml” file added to the top-level of your repository with the following contents:

repos:
-   repo: https://github.com/cesar-rodriguez/terrascan
    rev: v0.2.0
    hooks:
    -   id: terrascan
        pass_filenames: false
        args: [-l=infra] #NOTE: this command should point to the directory containing your .tf files
        verbose: true

Let’s also add an example terraform file to “infra/s3.tf” containing a security issue, so we can test. 

resource "aws_s3_bucket" "my_s3_bucket" {
  bucket = "my-s3-bucket"
  acl    = "public-read-write"

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        kms_master_key_id = "$"
        sse_algorithm = "aws:kms"
      }
    }
  }

  logging {
    target_bucket = "logging_bucket"
    target_prefix = "log/"
  }

  tags = {
    Name        = "my-s3-bucket"
    Environment = "production"
  }
}

Finally, we will follow the instructions here to run pre-commit as part of CI in a GitHub action. To do this you will add the following code to a file named “.github/workflows/precommit.yaml”:

name: pre-commit
on: [push]
jobs:
  pre-commit:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - uses: actions/setup-python@v1
    - name: set PY
      run: echo "::set-env name=PY::$(python --version --version | sha256sum | cut -d' ' -f1)"
    - uses: actions/cache@v1
      with:
        path: ~/.cache/pre-commit
        key: pre-commit|${  }|${  }
    - uses: pre-commit/action@v1.0.0

Now, let’s push our changes and see what happens:

$ git add .
$ git commit -m "testing github actions"
$ git push --set-upstream origin master

Now the action should run to evaluate your s3.tf file since we configured it to run on every push. You can browse to the GitHub actions tab in your repo to see the output of the action. Here’s what I see for my repo at https://github.com/cloud-security-musings/terrascan-examples/actions.

terrascan-example-github-actions-failed.png

Since we had a security weakness in the s3.tf file, the GitHub action failed. If you click on “pre-commit”, you can see the details of the CI job where the failure is shown:

terrascan-github-action-failure-message.png

As the error message indicates. Our aws_s3_bucket resource has a “public-read-write” ACL. Let’s fix the issue by updating infra/s3.tf with the following:

resource "aws_s3_bucket" "my_s3_bucket" {
  bucket = "my-s3-bucket"
  acl    = "private"

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        kms_master_key_id = "$"
        sse_algorithm = "aws:kms"
      }
    }
  }

  logging {
    target_bucket = "logging_bucket"
    target_prefix = "log/"
  }

  tags = {
    Name        = "my-s3-bucket"
    Environment = "production"
  }
}

Then execute the commands below:

$ git add .
$ git commit -m "fixes public bucket"
$ git push
$ hub browse

As expected, you should see the action now succeed indicated by a green checkmark: 

terrascan-github-action-success.png

What if I don’t use GitHub Actions for CI? 

If you don’t use GitHub or GitHub actions for continuous integration, a similar setup can be accomplished with any CI tool. Here’s documentation on how to run pre-commit in other continuous integration tools: https://pre-commit.com/#usage-in-continuous-integration

What other security checks you perform on your CI builds for infrastructure code?  

Cesar Rodriguez

Cesar Rodriguez is a Cloud Security Architect with 6+ years of experience securing cloud environments in the financial industry and 10+ years working in information security.

Previous
Previous

Securing Your Data Lake Using S3 Access Points

Next
Next

Using Terrascan for Static Code Analysis of Your Infrastructure Code (part 1)