DEV Community

DevOps Start
DevOps Start

Posted on • Originally published at devopsstart.com

How to Automate Terraform Reviews with GitHub Actions

Stop review fatigue and catch IaC security risks before they hit production. This guide was originally published on devopsstart.com.

Introduction

Reviewing Infrastructure as Code (IaC) is a different beast compared to reviewing application logic. When you review a Java or Python PR, you're looking for bugs, race conditions or inefficient algorithms. When you review Terraform, you're looking for "blast radius". A single misplaced character in a resource name or an incorrectly configured count variable can trigger a terraform destroy on a production database, leading to catastrophic downtime.

Despite the stakes, most DevOps teams suffer from "Review Fatigue". Human reviewers often spend 80% of their time pointing out trivial issues: missing tags, inconsistent indentation or hardcoded region strings. By the time they get to the actual architectural flaws—like an S3 bucket missing encryption or a security group open to 0.0.0.0/0—they're mentally exhausted. This creates a dangerous gap where critical infrastructure risks slip into production because the reviewer was too busy complaining about trailing commas.

The goal of this tutorial is to eliminate that toil. You'll learn how to integrate CodeRabbit with GitHub Actions to automate the first pass of your Terraform reviews. CodeRabbit isn't just a generic LLM wrapper; it's designed to understand the context of your repository. By the end of this guide, you'll have an AI-powered reviewer that flags security vulnerabilities, enforces naming conventions and analyzes your terraform plan output to warn you before you accidentally delete your entire VPC.

To make this work, we'll be using Terraform v1.7.0 and GitHub Actions. If you're managing state for a growing team, ensure you've already implemented /blog/terraform-state-locking-a-guide-for-growing-teams to avoid state corruption during these automated workflows.

Prerequisites

Before starting the integration, you need a specific set of tools and access levels. If you're missing any of these, the automation will fail during the handshake between GitHub and the AI engine.

First, you need a GitHub repository containing Terraform HCL code. This repository must be hosted on GitHub (Cloud or Enterprise) because CodeRabbit integrates directly via the GitHub App ecosystem. You should have administrative access to the repository to install apps and configure GitHub Action secrets.

Second, you need a CodeRabbit account. While there is a free trial, you'll need an active account to generate the integration keys required for the AI to read your pull requests.

Third, you must have Terraform v1.7.0 or later installed locally if you plan to test the HCL changes before pushing. We recommend using a version manager like tfenv to ensure consistency across your team.

Finally, a basic grasp of YAML syntax is required. You won't be writing complex scripts, but you'll be editing a .coderabbit.yaml configuration file. This file acts as the "brain" of your AI reviewer, telling it whether to be a strict security auditor or a helpful mentor.

Checklist of requirements:

  • GitHub Account with Repository Admin permissions.
  • CodeRabbit Account.
  • Terraform v1.7.0+.
  • A functioning remote backend (S3, GCS or Azure Blob) for your Terraform state.

Overview

In this tutorial, we are building an automated AI-driven guardrail system for your infrastructure. The objective is to move the "boring" parts of the code review—syntax, tagging and basic security—from the human reviewer to the AI.

The architecture works like this: A developer pushes a branch and opens a Pull Request (PR). This triggers a GitHub Action that runs terraform plan. Simultaneously, the CodeRabbit GitHub App intercepts the PR event. It reads the diff of the HCL files and the output of the terraform plan. Using a customized .coderabbit.yaml file, the AI applies your specific organization's rules (for example, "All AWS resources must have a Project tag").

The AI then posts a series of line-by-line comments on the PR. If it sees an S3 bucket without public_access_block, it won't just say "this is wrong"; it will provide the exact HCL snippet needed to fix it.

The real power comes from the synergy between the static code analysis and the execution plan. While static analysis can see that a resource is being changed, the terraform plan tells the AI if that change will cause a "Replacement" (destroy and recreate). The AI can then warn the reviewer: "Warning: Changing the name attribute of this RDS instance will cause a complete recreation of the database, leading to data loss."

By the end of this setup, your human reviewers will only need to focus on the "Why" (the architectural intent) rather than the "How" (the syntax and basic security).

Step 1: Installing the CodeRabbit GitHub App

The first step is to bridge the gap between your code and the AI engine. CodeRabbit operates as a GitHub App, which means it doesn't require you to manage complex SSH keys or manual webhooks.

  1. Navigate to the GitHub Marketplace or the CodeRabbit dashboard.
  2. Click "Install" and select the specific repositories you want the AI to monitor. Do not install it on all repositories unless you want AI comments on every single project in your organization.
  3. Grant the necessary permissions. CodeRabbit requires "Read and Write" access to Pull Requests and "Read" access to repository contents. This allows the AI to see the diffs and post suggestions.

Once installed, you can verify the connection by opening a test PR in one of the selected repositories. You should see a CodeRabbit bot join the conversation shortly after the PR is created.

Step 2: Configuring the .coderabbit.yaml for Terraform

Generic AI reviews are often too noisy or too vague. To make the AI a "Senior DevOps Engineer," you need to give it a set of instructions. This is done via a .coderabbit.yaml file placed in the root of your repository.

This file defines the "Persona" and the "Instructions". For Terraform, you want the AI to prioritize stability, security and cost over "clever" code.

Create a file named .coderabbit.yaml in your root directory with the following content:

language: "hcl"
reviews:
  profile: "infrastructure_expert"
  instructions: |
    You are a Senior Platform Engineer specializing in Terraform v1.7.0.
    Your goal is to ensure infrastructure is secure, scalable and maintainable.

    Strictly enforce the following rules:
    1. Tagging: Every resource must have 'Environment', 'Owner' and 'Project' tags.
    2. Security: Flag any security group rule that allows 0.0.0.0/0 on port 22 or 3389.
    3. State Management: Ensure no local state is used; remote backends are mandatory.
    4. Naming: Resources must use kebab-case (e.g., 'web-server-prod').
    5. S3 Buckets: Must have 'versioning' enabled and 'public_access_block' configured.
    6. Secrets: Flag any hardcoded passwords, API keys or tokens. Suggest using AWS Secrets Manager or HashiCorp Vault.
    7. DRY Principle: Suggest the use of modules or `for_each` if the same resource is repeated more than 3 times.

  review_style: "concise"
  focus:
    - security
    - cost_optimization
    - maintainability
Enter fullscreen mode Exit fullscreen mode

In this configuration, the instructions block is where the magic happens. By specifying "S3 Buckets must have versioning enabled", you've turned a generic LLM into a specialized Terraform auditor. When the AI sees an aws_s3_bucket resource without a corresponding aws_s3_bucket_versioning resource, it will now trigger a warning.

Step 3: Setting up the GitHub Actions Workflow

While CodeRabbit handles the AI review of the code, you still need the actual terraform plan to provide context. The AI is much more effective when it knows exactly what Terraform intends to do to your real-world infrastructure.

Create a file at .github/workflows/terraform-review.yml:

name: "Terraform AI Review"

on:
  pull_request:
    branches:
      - main

jobs:
  terraform-plan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

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

      - name: Terraform Init
        run: terraform init
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color > plan_output.txt
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Upload Plan for AI
        uses: actions/upload-artifact@v4
        with:
          name: tf-plan
          path: plan_output.txt
Enter fullscreen mode Exit fullscreen mode

This workflow does three critical things:

  1. It initializes the environment using the official hashicorp/setup-terraform action.
  2. It generates a plan and redirects the output to a text file (plan_output.txt). We use -no-color because AI models struggle with ANSI color codes.
  3. It uploads the plan as an artifact. CodeRabbit can be configured to ingest these artifacts or read the logs from the Action to understand the impact of the change.

If you are deploying complex clusters, you might want to combine this with a tutorial on /tutorials/deploy-eks-cluster-with-terraform to ensure your plan outputs are structured correctly for the AI to parse.

Step 4: Configuring AI Personas for Infrastructure

Beyond the .coderabbit.yaml file, you can refine how the AI communicates. You don't want the AI to sound like a bot; you want it to sound like a colleague who has seen a hundred production outages.

In the CodeRabbit dashboard, you can adjust the "System Prompt" or the "Persona". For infrastructure, I recommend a "Conservative Auditor" persona. This persona is programmed to be pessimistic. It assumes that if a change looks risky, it probably is.

For example, if you change a vm_size in Azure or an instance_type in AWS, a "helpful" AI might say "Great, you're upgrading the CPU!". A "Conservative Auditor" AI will say "Warning: Changing the instance type may cause a reboot of the instance. Ensure your application handles this gracefully or perform this during a maintenance window."

To implement this, add a context section to your .coderabbit.yaml:

  context: |
    Always assume the environment is production unless the branch name contains 'dev'.
    Prioritize availability over cost.
    If a change causes a resource replacement, mark the comment as 'Critical'.
Enter fullscreen mode Exit fullscreen mode

This prevents the AI from suggesting "cost-saving" measures that might degrade performance in a production environment.

Step 5: The Workflow in Action (The "Bad PR" Test)

To verify your setup, let's intentionally create a "Bad PR". This will test if the AI is actually following the rules we set in Step 2.

Create a new branch and add the following "anti-pattern" code to your main.tf:

# BAD PRACTICE: Hardcoded secret
resource "aws_db_instance" "database" {
  allocated_storage    = 20
  engine               = "mysql"
  instance_class       = "db.t3.micro"
  username             = "admin"
  password             = "supersecret123" # AI should flag this
  skip_final_snapshot  = true
}

# BAD PRACTICE: Wide open security group
resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh"
  description = "Allow SSH inbound traffic"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # AI should flag this
  }
}

# BAD PRACTICE: Missing mandatory tags
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  # Missing Environment, Owner and Project tags
}
Enter fullscreen mode Exit fullscreen mode

Push this code and open a Pull Request. Within seconds, you should see the following behavior:

  1. Secret Detection: CodeRabbit will highlight the password = "supersecret123" line. It will comment: "Critical: Hardcoded secret detected. Please use AWS Secrets Manager or a variable marked as sensitive = true."
  2. Security Audit: It will flag the cidr_blocks = ["0.0.0.0/0"] for port 22. It will suggest: "Security Risk: SSH is open to the world. Restrict this to your company's VPN CIDR range."
  3. Policy Enforcement: It will note that the aws_instance.web resource is missing the mandatory tags defined in your .coderabbit.yaml. It will provide a code block:
   tags = {
     Environment = "prod",
     Owner       = "platform-team",
     Project     = "web-app"
   }

Enter fullscreen mode Exit fullscreen mode

Step 6: Integrating with terraform plan for Risk Analysis

The most powerful feature of this setup is the AI's ability to read the terraform plan output. Static analysis can tell you that you changed a line of code, but only the plan tells you if that change will destroy a resource.

Consider this scenario: You change the name of an S3 bucket in your HCL.

Static analysis sees: bucket = "my-old-bucket" $\rightarrow$ bucket = "my-new-bucket". This looks like a simple string change.

However, the terraform plan output will say:
-/+ destroy and then create replacement

When CodeRabbit analyzes this plan output, it will post a high-priority warning:
"🚨 Destructive Change Detected: Changing the bucket name will cause Terraform to destroy the existing S3 bucket and create a new one. This will result in the loss of all existing data in my-old-bucket unless you have a backup or use the terraform state mv command."

This is the difference between a generic AI and an IaC-aware AI. To ensure this works, make sure your GitHub Action outputs the plan in a way that the AI can access. If you use a tool like tfplan or terraform-pr, the AI can read the JSON output of the plan, which is even more precise.

Step 7: Verification and Iteration via AI Chat

One of the biggest frictions in code reviews is the "ping-pong" of comments.
Reviewer: "Can you change this to a module?"
Developer: "Why?"
Reviewer: "Because we have five of these."
Developer: "Okay, I'll do it."

With CodeRabbit, you can use the "Chat with AI" feature directly in the PR. Instead of waiting for a human, the developer can ask the AI to implement the suggestion.

For example, if the AI suggests using a module for repeated resources, the developer can reply to the comment:
@coderabbitai please rewrite these three aws_instance resources into a single module call using for_each.

The AI will then generate the updated HCL code, including the module definition and the call. The developer can simply click "Commit Suggestion" to apply the change. This reduces the PR cycle time from hours (or days) to minutes.

Troubleshooting

Even with a straightforward setup, you'll likely encounter a few common issues. Here is how to solve them.

AI is too noisy (Too many comments)

If the AI is flagging things that are actually acceptable in your environment, your .coderabbit.yaml is too vague.
Fix: Be more specific in your instructions. Instead of saying "Flag security issues," say "Flag security group rules that allow 0.0.0.0/0, but ignore these rules if the resource is tagged as PublicLoadBalancer."

AI cannot see the Terraform Plan

If the AI is giving generic advice but not mentioning resource destruction, it's not reading your GitHub Action output.
Fix: Ensure your GitHub Action is running before the AI completes its review. You can use the workflow_run trigger or ensure the AI is configured to wait for the terraform-plan job to finish. Check that the plan output is not being truncated by GitHub's log limits (which is why uploading as an artifact is preferred).

"Permission Denied" during Terraform Init

Your GitHub Action might fail at the terraform init step.
Fix: This is almost always a secret management issue. Ensure AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are defined in your GitHub Repository Secrets. If you're using OIDC (which is recommended), use the aws-actions/configure-aws-credentials action instead of static keys.

AI suggests outdated Terraform syntax

LLMs are trained on data that might be a year old. It might suggest resource "aws_s3_bucket_policy" syntax that has changed in the latest AWS provider.
Fix: In your .coderabbit.yaml, explicitly state the provider versions. Add: "Use AWS Provider v5.0+ syntax. Do not use deprecated attributes like acl inside the aws_s3_bucket resource; use the aws_s3_bucket_acl resource instead."

FAQ

Does CodeRabbit have access to my actual AWS/Azure credentials?
No. CodeRabbit only has access to the code diffs and the text output of the terraform plan generated by GitHub Actions. Your cloud credentials remain securely stored in GitHub Secrets and are only used by the GitHub Runner.

Can I use this with Terraform Cloud or Spacelift?
Yes. Instead of running terraform plan in a GitHub Action, you can configure the CI/CD tool to post the plan output as a comment on the PR. CodeRabbit will then analyze that comment as part of its review process.

Will the AI automatically merge my PRs?
No. CodeRabbit is a reviewer, not a merger. It provides suggestions and flags risks, but the final decision to approve and merge always stays with your human engineers.

How does this handle different environments (Dev vs Prod)?
You can handle this by using different .coderabbit.yaml profiles or by adding logic to your context block (as shown in Step 4) that tells the AI to treat branches like main or prod with higher strictness than feature/* branches.

Conclusion

By automating your Terraform reviews with GitHub Actions and CodeRabbit, you've shifted the burden of quality control from your most expensive resource—your senior engineers—to an AI that doesn't get tired or overlook a missing tag.

You've implemented a system that:

  • Enforces organization-wide tagging and naming standards automatically.
  • Catches "low-hanging fruit" security vulnerabilities before they reach a human.
  • Analyzes terraform plan outputs to prevent accidental data loss through resource replacement.
  • Accelerates the development loop by allowing developers to iterate with the AI via chat.

The next step for your team is to expand these rules. Start by auditing your last ten production incidents. For every incident that was caused by a misconfiguration (e.g., a missing lifecycle { prevent_destroy = true } block), add a corresponding rule to your .coderabbit.yaml.

As your infrastructure grows, you might also want to explore GitOps patterns to further automate the deployment of these reviewed changes. For a complete pipeline, check out /tutorials/how-to-set-up-argo-cd-gitops-for-kubernetes-automation to learn how to sync your approved Terraform changes directly to your clusters.

Now, go delete those hardcoded secrets and start automating your guardrails.

Top comments (0)