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:
- 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.
- 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.
- 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:
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:
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.
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.
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.
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: