Adding Terraform AWS Cost Policies using Infracost and Checkov

Building cloud infrastructure isn’t cheap but it is extremely accessible. While we apply service control policies to limit the accessibility of certain resources for security purposes, can we apply the same tools to examine cost? The answer is, yes.

Infracost is available to provide insights before deployment by examining the Terraform plan. This provides us the opportunity to catch anomalies and review financial impacts before the actual deployment. While Infracost has internal policy management you can integrate with to manage tagging policies and cost policies, it can be beneficial to include these checks in your existing security Policy as Code (PaC) such as Checkov. This can eliminate tool sprawl, keep the workflow streamlined, and still shift left on FinOps. Checkov luckily comes with the ability to add in custom policies.

from __future__ import annotations
import json

from typing import Any

from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories


class InfracostTotalCost(BaseResourceCheck):
    def __init__(self) -> None:
        name = "Ensure Total Cost does not increase more than 10%"
        id = "CKV_COST_999"
        # CheckCategories are defined in models/enums.py
        categories = (CheckCategories.SUPPLY_CHAIN,)
        guideline = "Uses Infracost Output"
        supported_resources = ("aws_vpc*",)
        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, guideline=guideline)

    def scan_resource_conf(self, conf: dict[str, list[Any]]) -> CheckResult:
        """
            Looks for Infracost output file
        :return: <CheckResult>
        """
        file = open("infracost.json", "r")
        data = json.load(file)
        expectedMonthlyCost = float(data['totalMonthlyCost'])
        currentMonthlyCost = float(data['pastTotalMonthlyCost'])
        monthlyCostChange = currentMonthlyCost - expectedMonthlyCost
        if monthlyCostChange/currentMonthlyCost > .1:
            return CheckResult.FAILED
        return CheckResult.PASSED


check = InfracostTotalCost()

We can write a custom policy that allows us to parse through the Infracost JSON output file. In the above code example, this simply looks for cost increases that exceed 10%. This can be tuned for other scenarios where individual resources such as EC2 instance sizes get validated. While we can do checks for instance type with just Checkov alone, we can add in more robust financial modeling accounting for usage constraints and other scenarios. This allows us to say “Don’t spend more than 100$ a month” rather than “Don’t use m5.2xlarge or higher instances”.

For the actual integration, this can be added into an existing pipeline with just one extra line of code.

infracost breakdown --path . --format json --out-file infracost.json
checkov -d . --external-checks-dir infracost_checks

We add in the line to call Infracost and generate the output file. The Infracost checks can be added to your custom check folder if you have one already or added to a new one.

Shifting left on FinOps is beneficial to avoid sticker shock when receiving the monthly bill and can help prevent accidental over-provisioning. An extra 0 on an auto-scaling policy can really ruin someone’s day.