Cloud Cost Optimization GitHub

The Problem with Manual Cloud Cost Reviews

Most engineering teams discover their cloud bill has ballooned on the first of the month when finance sends an alarmed Slack message. By then, orphan EBS volumes, oversized development Kubernetes nodes, and forgotten test databases have been running unchecked for 30 days. Traditional cloud cost optimization relies on manual dashboard checking in AWS Cost Explorer or GCP Billing, which fails because engineers write code daily but review costs monthly.

At techsolss, when we build infrastructure for startups and enterprises, we bake financial visibility directly into the version control system. If an engineer opens a pull request that provisions an oversized EC2 instance, the feedback loop should happen before the code reaches production, not after the invoice arrives. This is where embedding cloud cost optimization into GitHub workflows becomes a non-negotiable practice.

Shifting Cost Checks Left with GitHub Actions

To catch waste before deployment, you need to analyze your Infrastructure as Code (IaC) within GitHub Actions. Tools like Infracost parse Terraform plans and output estimated monthly cost deltas directly into pull request comments. This gives reviewers immediate context: “This PR increases our monthly AWS bill by $320/month due to an added RDS Multi-AZ instance.”

Here is a working GitHub Actions workflow that runs Infracost on every pull request targeting your main branch. It uses OIDC (OpenID Connect) authentication to assume an IAM role securely without storing long-lived AWS credentials in GitHub secrets.

name: Infracost PR Cost Check

        on:
          pull_request:
            branches: [main]
            paths:
              - 'terraform/**'

        permissions:
          id-token: write
          contents: read
          pull-requests: write

        jobs:
          infracost:
            name: Cost Estimation
            runs-on: ubuntu-latest
            steps:
              - name: Checkout Code
                uses: actions/checkout@v4

              - name: Setup Terraform
                uses: hashicorp/setup-terraform@v3

              - name: Setup Infracost
                uses: infracost/actions/setup@v3
                with:
                  api-key: \${{ secrets.INFRACOST_API_KEY }}

              - name: Configure AWS Credentials via OIDC
                uses: aws-actions/configure-aws-credentials@v4
                with:
                  role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsInfracostRole
                  aws-region: us-east-1

              - name: Generate Infracost Cost Breakdown
                run: |
                  infracost breakdown --path=terraform/
                    --format=json
                    --out-file=infracost.json

              - name: Post Infracost Comment
                uses: infracost/actions/comment@v3
                with:
                  infracost-json: infracost.json
                  behavior: update
        

By placing this check in your CI/CD pipeline, you eliminate the guesswork. Developers take ownership of cloud spend because the financial impact is visible right alongside lint errors and unit test failures.

Automating Resource Cleanup with Scheduled GitHub Workflows

Pull request validation stops new waste, but what about existing environments? Non-production clusters in staging and development environments are notorious for running 24/7 even though developers only work 40 hours a week. Running idle resources over the weekend accounts for nearly 30% of wasted cloud spend in typical setups.

Instead of paying for cloud resources on Saturday and Sunday, you can use scheduled GitHub Actions to scale down Kubernetes deployments, stop non-production RDS instances, or terminate untagged EC2 instances. Below is a cron-driven workflow that triggers an automated cleanup script every Friday evening to stop non-prod workloads, and another that spins them back up on Monday morning.

name: Non-Prod Weekend Shutdown

        on:
          schedule:
            # Runs every Friday at 18:00 UTC
            - cron: '0 18 * * 5'

        jobs:
          shutdown-staging:
            runs-on: ubuntu-latest
            steps:
              - name: Checkout Repository
                uses: actions/checkout@v4

              - name: Set up Python
                uses: actions/setup-python@v5
                with:
                  python-version: '3.11'

              - name: Install Boto3
                run: pip install boto3

              - name: Configure AWS Credentials
                uses: aws-actions/configure-aws-credentials@v4
                with:
                  aws-access-key-id: \${{ secrets.AWS_ACCESS_KEY_ID }}
                  aws-secret-access-key: \${{ secrets.AWS_SECRET_ACCESS_KEY }}
                  aws-region: us-east-1

              - name: Execute Shutdown Script
                run: python scripts/stop_non_prod.py
        

The corresponding Python script (scripts/stop_non_prod.py) uses Boto3 to target instances marked with a specific tag (e.g., Environment: Staging):

import boto3

        def stop_staging_instances():
            ec2 = boto3.client('region', region_name='us-east-1')
            ec2 = boto3.client('ec2')

            response = ec2.describe_instances(
                Filters=[
                    {'Name': 'tag:Environment', 'Values': ['Staging']},
                    {'Name': 'instance-state-name', 'Values': ['running']}
                ]
            )

            instance_ids = []
            for reservation in response['Reservations']:
                for instance in reservation['Instances']:
                    instance_ids.append(instance['InstanceId'])

            if instance_ids:
                ec2.stop_instances(InstanceIds=instance_ids)
                print(f"Successfully stopped staging instances: {instance_ids}")
            else:
                print("No running staging instances found.")

        if __name__ == "__main__":
            stop_staging_instances()
        

When scaling this across multiple cloud providers or complex microservices architectures, managing individual scripts can become cumbersome. For a broader look at structuring these initiatives, check out our guide on cloud cost optimization for startups: a devops playbook as well as our foundational overview on what is cloud cost optimization? a practical guide.

Enforcing FinOps Guardrails via Policy-as-Code

Detecting cost anomalies after they happen or stopping them in PRs is useful, but enforcing hard organizational limits requires Policy-as-Code. Using Open Policy Agent (OPA) or Checkov inside your GitHub repository ensures that specific cost-inefficient resource configurations are rejected outright before they can be merged.

For example, you might want to prevent engineers from provisioning expensive GPU instances or unencrypted high-IOPS EBS volumes in non-production workspaces. Here is a simple Checkov configuration check or OPA Rego rule integrated into your GitHub Action runner that flags non-compliant resource types:

name: Policy-as-Code Guardrails

        on: [pull_request]

        jobs:
          checkov:
            runs-on: ubuntu-latest
            steps:
              - name: Checkout Repo
                uses: actions/checkout@v4

              - name: Run Checkov Cloud Cost & Security Guardrails
                uses: bridgecrewio/checkov-action@master
                with:
                  framework: terraform
                  soft_fail: false
                  output_format: cli
        

By codifying these rules, your engineering team moves away from reactive firefighting and toward proactive financial governance. If you are comparing how to structure your operational model to support these practices, review our analysis on platform engineering vs devops: what actually changes?.

Summary: Making GitHub the Single Source of Truth for Cloud Spend

Cloud cost optimization is not a one-time project; it is a continuous engineering discipline. By bringing cost checks into GitHub through Infracost, scheduling automated shutdowns for non-prod environments, and enforcing Policy-as-Code guardrails, you transform version control into your primary financial dashboard.

Whether you are managing traditional microservices or deploying heavy MLOps pipelines—which often incur massive GPU overhead—automation in GitHub keeps your burn rate under tight control without slowing down your developers.

Want help with this in your own stack?

We build and run this in production for clients — and we’ll tell you honestly what it will take in yours. Book a free 20-minute call.

Book a free 20-min call