checkov is a pretty neat tool to verify that your Infrastructure-as-Code (IaC) repo doesn’t do or omit anything that unintentionally impacts your security posture. The best kind of feedback is early and localized feedback, thus better than having a failed test run is a message directly in the PR diff about where something went wrong. Luckily GitHub has decent support for letting Actions provide localized feedback by using the magic format ::error file=$file,line=$line,col=$col::$message (documented here), which we can fairly easily combine with checkov for a pretty good developer experience.
We can write a quick script to bridge these two, which can be run without any arguments to run checks against the entire repo, or by giving it a list of files to check:
import argparse import json import subprocess import sys SKIPPED_CHECKS = [ # I don't like this check 'CKV_AWS_40', ] def main(): args = get_args() result, output = get_checkov_output(args.files) print_github_errors(output) sys.exit(result) def get_checkov_output(files): cmd = ['checkov'] # If any input files are given, run on only those, otherwise run across everything if files: for file in files: cmd.extend(['--file', file]) else: cmd.extend(['--directory', 'terraform/']) cmd.extend([ '--quiet', '--framework', 'terraform', '--output', 'json', '--skip-check', ','.join(SKIPPED_CHECKS), ]) proc = subprocess.run(cmd, stdout=subprocess.PIPE) return proc.returncode, json.loads(proc.stdout.decode('utf-8')) def print_github_errors(checkov_output): for failure in checkov_output['results']['failed_checks']: details = '' if 'guideline' in failure: details = ' Details: %s' % failure['guideline'] print('::error file=%s,line=%s,col=1::%s (%s).%s' % ( failure['repo_file_path'][1:], failure['file_line_range'][0], failure['check_name'], failure['check_id'], details), ) def get_args(): parser = argparse.ArgumentParser() parser.add_argument('files', nargs='*') return parser.parse_args() if __name__ == '__main__': main()
In a GitHub Action we can request to only run this only against changed files in a PR:
name: Checkov on: pull_request: paths: - .github/workflows/checkov.yml - terraform/** - tools/terraform_security_check.py jobs: terraform-security-check: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: fetch-depth: ${{ github.event.pull_request.commits }} - name: Fetch base branch run: | git fetch --no-tags --prune --depth=1 origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} - name: Configure run: pip install checkov - name: Run checkov run: ./tools/terraform_security_check.py $(git diff --name-only "origin/${{ github.base_ref }}.." ./terraform/)
Which lets us get inline feedback like this if a file touched by a PR violates any of the security policies:
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.