Hacktoberfest contribution spotlight: Securing software delivery pipelines using Checkov JSON scanning

Checkov JSON checks

Hacktoberfest gives the open source community an opportunity to work together on OSS contributions and impact thousands of DevOps teams using Bridgecrew’s tooling. This year we joined in on the Hacktober-festivities to encourage contributions in return for swag‚ÄĒand, of course, bragging rights among Checkov followers ūüėČ. We’ve had incredible participation and with just a week and a half left of Hacktoberfest wanted to highlight one particular contribution of a new capability to Checkov from¬†Brent Souze.¬†

This new capability expands from the policy as code on top of IaC files to be able to scan arbitrary JSON input, allowing Checkov to be integrated in new ways throughout different use cases within the software development lifecycle. One such use case is to manage the configuration of version control systems (VCS).

Collaboration is one of the keys to success in software engineering projects, and this is a key capability in modern VCS. Branches, for example, allow different members of an engineering org to work on different features or bugs within the same project in parallel, submitting it to be merged back to the main branch. Peer reviews by team members prior to merging branches help to make software reliable and encourage a sense of team collaboration.

Tl;dr, thanks to Brent’s contribution:

  • You can now inspect JSON configurations using Checkov.
  • VCS configurations can be retrieved in JSON format.
  • Combined, you can now run policy-as-code to verify the secure configuration of Github, GitLab, and Bitbucket.

Branch protection rules

You can create a branch protection rule (GitHub) or merge request approval rules (GitLab) to enforce specific workflows for one or more branches. For example, you can require an approving review or passing status checks for all pull requests merged into the protected branch. Those protection rules ensure that the right team members have signed off to make sure all code is reviewed, secured, and reliably sourced.

ClickOps is one option: you can go over the merge request menu of GitLab, configure the approval rules with the number of required approvals for each repository. You can audit those settings manually once a month and validate that nothing has changed but that’s manual and error-prone. We need automation.

Auditing approvals with branch protection rules

We can add automated checks for CI/CD configurations using the new Checkov JSON capabilities.

We’ll start by getting our GitLab project ID:

GitLab config menu

Using a GitLab personal access token, we’ll run the following curl command to get the approval configuration using the REST API command to our GitLab server:

curl "https://gitlab.com/api/v4/projects/${PORJECT_ID}/approvals?access_token=${GITLAB_TOKEN}" -o merge_request_approval_conf.json

The response will save the current state of configuration to the file merge_request_approval_conf.json:

{
  "approvals_before_merge": 1,
  "reset_approvals_on_push": true,
  "disable_overriding_approvers_per_merge_request": false,
  "merge_requests_author_approval": true,
  "merge_requests_disable_committers_approval": false,
  "require_password_to_approve": true
}

Now, we will audit that configuration state using a Checkov custom policy. Add the following to a file called MergeRequestApproval.py along with the __init__.py file in a directory called my_gitlab_policies: 

from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.json_doc.base_json_check import BaseJsonCheck
from checkov.json_doc.enums import BlockType

class MergeRequestRequiresApproval(BaseJsonCheck):
   def __init__(self):
       name = "Merge requests should require at least 2 approvals"
       id = "CKV_GITLAB_2"
       categories = [CheckCategories.CONVENTION]
       super().__init__(
           name=name,
           id=id,
           categories=categories,
           supported_entities=["approvals_before_merge"],
           block_type=BlockType.DOCUMENT,
       )

   def scan_entity_conf(self, conf):
       if conf.get("approvals_before_merge",0) < 2:
           return CheckResult.FAILED, conf
       return CheckResult.PASSED, conf

check = MergeRequestRequiresApproval()


Then, run Checkov using the following command:

checkov -d . --external-checks-dir my_gitlab_policies --run-all-external-checks

That will result in the following output showing that our current GitLab settings for the number of approvers do not meet the policy we would like to enforce:

Failed Checkov JSON policy

Now let’s fix the number of required approvals before merging using the following command:

curl "https://gitlab.com/api/v4/projects/${PORJECT_ID}/approvals?access_token=${GITLAB_TOKEN}" -X POST -H 'Content-Type: application/json' -d '{  "approvals_before_merge": 3, "reset_approvals_on_push": true, "disable_overriding_approvers_per_merge_request": false, "merge_requests_author_approval": true, "merge_requests_disable_committers_approval": false, "require_password_to_approve": true }'

And fetch updated configuration and run checkov again to validate:

curl "https://gitlab.com/api/v4/projects/${PORJECT_ID}/approvals?access_token=${GITLAB_TOKEN}" -o merge_request_approval_conf.json

checkov -d . --external-checks-dir my_gitlab_policies --run-all-external-checks

We will get the following output showing that our Checkov policy is passing:

Passed Checkov policy check

We have successfully audited and fixed GitLab’s branch protection rules!

To automate this even further, you can add Checkov to GitLab’s runner configuration by following this guide. 

Other use cases for Checkov JSON scanning

Checkov JSON scanning opens up a world of possibilities for ensuring strong VCS policies. You can inspect that you’ve set up best practices such as:

And various others to reduce code tampering risks and monitor all critical code being added to a VCS.

Read more on how you can participate in Hacktoberfest with Bridgecrew and apply for swag!

Happy Hacktoberfest!