Using Yor and Checkov to authorize IaC modifiers from CI/CD

Yor + Checkov logos

Cloud resource tags are essential to modern cloud management. They can append important informational metadata to resources and—as we’ll demonstrate in this post—can even be used to track and authorize IaC resource modifiers straight from your CI/CD pipeline.

In runtime, you can achieve authorization with IAM policies, but it isn’t as straightforward for infrastructure as code (IaC). To use cloud resources tags to authorize IaC modifiers, you need three things in place:

  1. A consistent IaC tagging mechanism. Tags need to be applied at the code level on a consistent basis and follow consistent conventions. For example, if multiple teams want to tag code with the owners of each microservice, but each team uses a different tag key (e.g., “owner,” “owners,” “ownership”), their value is greatly diminished. This is where our open source tool, Yor, comes in, making it easy to ensure all IaC resources get the right tags.
  2. A way to enforce tags on all resources. Your tagging strategy is only as strong as the enforcement you put in place around it. Without tagging governance in place, anyone is able to create and modify tags at will, or resources may not get tagged at all.
  3. Policies in place to authorize resource modifiers within your CI/CD pipeline. Once you have the right tags, you can write custom rules to check recent code modifiers against a list of verified users.

In this post, we’ll show you how to use Yor in combination with Checkov, our open source policy-as-code engine, to ensure resources are consistently tagged in IaC templates. Those tags are then used to enforce who can modify which resources.

The importance of tag governance

AWS, Azure, GCP, Alibaba Cloud, and Oracle Cloud Infrastructure (yes, Yor supports AliCloud and OCI!) offer a variety of tools to help implement proactive tag governance practices to ensure tags are applied every time resources are created. Some cloud providers have gone as far as defining a new role such as “tag administrator, while most have shared views on processes and procedures to maintain good tagging practices.

Similarly, infrastructure as code (IaC) frameworks such as Terraform and CloudFormation provide a common method to proactively tag cloud resources with the “tags/tag” resource property so that deployed resources from those code files also contain the appropriate tags. This provides multiple avenues to enforce tagging policies so that all cloud resources meet compliance standards when tagging for filtering, cost allocation, and access control.

Tagging governance is the practice of enforcing rules for tagging cloud resources. Governance practices typically mandate that every cloud resource contains specific tags (e.g., owner, cost center, environment) and that those tags are consistently formatted (e.g., same spelling, case).

The goal is to consistently classify cloud resources to satisfy compliance demands, security needs, operations, finances, and more. To do that, we annotate a new tag (or label in Google Cloud) for functionality and scope. Once you’ve settled on a tagging strategy for your organization, you will need to adapt as you scale and learn new things during day-to-day operations. Over time, requests for new tags will surface and will need to be addressed.

Here is what impact analysis, approval, and implementation should look like:

flow chart of impact analysis, approval, and implementation

Automated tag governance using Checkov and Yor

We can enforce our resource classification process using policy-as-code tools like Checkov. We can check that resources are properly tagged in IaC templates and continuously monitor runtime environments using bridgecrew for resources without proper tags using the same policies in runtime.

Let’s take a look at the following example that ensures all of our AWS resources have all of the tagging requirements in place. Our tagging requirements have a `team_ownership` tag for access management, a `git_repo` tag for operations, and a `pci_scope` tag for compliance needs.

We’ll create a Checkov custom policy that validates the existence of those tags:

metadata:
id: "CKV_OWNERSHIP_1"
name: "RDS instances should only be managed by Application Engineering team"
guidelines: "Please reach out to application_engineering@acme.com"
category: "general"
severity: "low"
scope:
provider: "aws"
definition:
cond_type: "attribute"
resource_types:
- "aws_db_instance"
attribute: "tags.team_ownership"
operator: "equals"
value: "application"

Using the Bridgecrew policy code editor, we can quickly hit “Test” to find resources that do not have the required `aws_instance` tag:

screenshot of policy code editor

We can then add that policy as a hard fail policy in our CI pipeline to prevent IaC templates from being added without the required tags. That way, Checkov can continuously verify that we have tagging enforced in each step of our CI pipeline.

screenshot of githubTo make this experience even more seamless, we can define the tagging policy upfront and have auto-remediation when tagging does not exist. Yor and custom YAML configurations can do exactly that by automatically enriching the tagging section in IaC with context sourced in git or configuration files.

Using tags to authorize resource modifiers within your CI/CD pipeline

In runtime, change approval processes can be managed in IAM policies where only specific users or roles have policies attached to modify specific resources. In build-time, we can enforce this change approval process using “CI/CD authorization” via tags. This process uses tags and policy-as-code to authorize who can modify a resource managed in IaC by failing a build if a user has modified a resource they are not allowed to modify.

For example, Alice edits an S3 bucket in Terraform but is not part of the team that owns the S3 bucket, so once that code is committed and runs through CI, the build would fail.

flow chart of user modifying an iac resource

Automated CI/CD authorization using Checkov and Yor

In the following example, we will run Yor and Checkov together in a CI/CD pipeline (a GitHub Action in this case) to verify that the person (me) that is modifying the following `aws_db_instance` resource is indeed authorized to.


resource "aws_db_instance" "default" {
  allocated_storage    = 10
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t3.micro"
  name                 = "mydb"
  username             = "foo"
  password             = "foobarbaz"
  parameter_group_name = "default.mysql5.7"
  skip_final_snapshot  = true
}

We’ll use Yor to tag the cloud infrastructure, including who modified the resource, and Checkov to verify that the code passes all policies, including a custom policy that ensures only authorized users can modify the code.

To make it easier to dictate tagging logic we’ll use tag groups auto determine which team each `git_modifier` is part of:


tag_groups:
  - name: ownership # map infrastructure to owner or owning team
    tags:
      - name: env
        value:
          default: ${env:GITHUB_HEAD_REF} # environment name would be the name of the feature_branch
      - name: team_ownership
        value:
          default: sre # SRE are the default owning team of cloud resources
          matches:
            - security_engineering:
                tags:
                  git_modifiers: # security engineering team member's GitHub handles
                    - rotemavni
                    - tronxd
                    - nimrodkor
            - platform_engineering:
                tags:
                  git_modifiers: # platform engineering team member's GitHub handles
                    - milkana
                    - nofar
            - application:
                tags:
                  git_modifiers:
                    - schosterbarak

Next, we’ll run Checkov via GitHub Actions with the custom policy we wrote earlier that verifies that only users with `team_ownership:application` are allowed to modify networking configurations.

name: Validate IaC

on:
  # Triggers the workflow on push or pull request events but only for the main branch
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]

jobs:
  yor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        name: Checkout repo
        with:
          fetch-depth: 0
          ref: ${{ github.head_ref }}
      - name: Run yor action
        uses: bridgecrewio/yor-action@main
        with:
          config_file: tag_groups.yaml
      - name: Run Checkov action
        id: checkov
        uses: bridgecrewio/checkov-action@master
        with:
          external_checks_dirs: checkov_extra_checks/

Once that runs, the resource will have the following tags, including `git_modifiers` and `team_ownership`, which will be verified against one another by our Checkov custom policy.


resource "aws_db_instance" "default" {
  allocated_storage    = 10
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t3.micro"
  name                 = "mydb"
  username             = "foo"
  password             = "foobarbaz"
  parameter_group_name = "default.mysql5.7"
  skip_final_snapshot  = true
  tags = {
    git_commit           = "29f6e5cb88751c422671c3e828094688f8f69923"
    git_file             = "newdb.tf"
    git_last_modified_at = "2021-06-30 15:54:09"
    git_last_modified_by = "schosterbarak@gmail.com"
    git_modifiers        = "schosterbarak"
    git_org              = "schosterbarak"
    git_repo             = "yor-demo"
    yor_trace            = "1ebc3ee8-a006-4578-90d7-bec9e5d69d9b"
    team_ownership       = "application"
  }
}

Since I, `schosterbarak`, am indeed part of the application team and the application team owns this resource, Checkov passes this check.

screenshot of checkov

For all future pull requests, Yor will continue to tag resources with `git_modifiers`, and Checkov’s custom ownership policies will verify that those listed are part of the authorized `team_ownership`. This new approach enables us to add authorization steps to IaC changes in a flexible, version controlled way.

Try it yourself by using Yor and Checkov together in your CI/CD pipelines! 

If you found this helpful, you’ll probably like these other Yor blog posts: