IaC Change Review
Analyze Infrastructure as Code changes from Terraform, Pulumi, or CDK to produce a Risk Summary and Operator-Friendly Change Summary.
Workflow Definition
name: iac-reviewdescription: | Analyze Infrastructure as Code changes (Terraform, Pulumi, CDK) to produce a risk assessment and operator-friendly change summary. Identifies dangerous changes, security implications, and provides clear explanations of what's changing.version: "1.0"
inputs: - name: working_dir type: string required: false default: "." description: Path to IaC project directory
- name: tool type: string required: false default: "terraform" description: IaC tool (terraform, pulumi, cdk)
- name: plan_output type: string required: false description: Pre-generated plan output (skips running the plan command)
- name: environment type: string required: false default: "unknown" description: Target environment (dev, staging, production)
- name: strict_mode type: boolean required: false default: false description: Fail on any HIGH or CRITICAL risk findings
steps: # Step 1: Generate the plan (if not provided) - id: generate_plan name: Generate IaC Plan condition: "{{not .inputs.plan_output}}" shell.run: command: | cd {{.inputs.working_dir}} {{if eq .inputs.tool "terraform"}} terraform plan -no-color -detailed-exitcode 2>&1 || true {{else if eq .inputs.tool "pulumi"}} pulumi preview --diff --non-interactive 2>&1 || true {{else if eq .inputs.tool "cdk"}} cdk diff 2>&1 || true {{else}} echo "Unsupported tool: {{.inputs.tool}}" && exit 1 {{end}} timeout: 300
# Step 2: Risk Analysis - identify dangerous changes - id: risk_analysis name: Risk Analysis type: llm model: balanced system: | You are an infrastructure security expert analyzing IaC plan output.
Identify and flag the following risk categories:
**CRITICAL Risks (block deployment):** - Destruction of production databases or persistent storage - Removal of backup configurations - Security group changes exposing sensitive ports (22, 3389, databases) to 0.0.0.0/0 - IAM policy changes granting admin/* or overly permissive access - Disabling encryption on storage or transit - Removing audit logging or monitoring - Changes to authentication/authorization systems
**HIGH Risks (requires approval):** - Any resource destruction in production - Scaling down (reducing instance counts, memory, CPU) - Network topology changes (VPC, subnets, routing) - Certificate or secret rotation - DNS record modifications - Load balancer configuration changes - Database configuration changes (even non-destructive)
**MEDIUM Risks (review recommended):** - New IAM roles or policies - Security group modifications (not critical) - New resources being created - Tag changes on critical resources - Environment variable changes
**LOW Risks (informational):** - Documentation/description updates - Tag additions - Non-critical resource updates
**Anomaly Detection:** - Flag unexpected changes (resources being modified that shouldn't be) - Identify drift (resources changing that weren't in the commit) - Note unusually large change counts - Highlight resources changing for the first time
For each finding, provide: 1. Risk level (CRITICAL/HIGH/MEDIUM/LOW) 2. Resource affected (type and name/ID) 3. What's changing 4. Why it's risky 5. Recommended action prompt: | Analyze this {{.inputs.tool}} plan for risks:
**Environment:** {{.inputs.environment}}
**Plan Output:** ``` {{if .inputs.plan_output}}{{.inputs.plan_output}}{{else}}{{.steps.generate_plan.stdout}}{{end}} ```
Provide a structured risk assessment. Group findings by severity. Include a risk score (0-100) and deployment recommendation.
Format as:
## Risk Score: X/100
## Deployment Recommendation [PROCEED / PROCEED_WITH_CAUTION / REQUIRES_APPROVAL / BLOCK]
## Critical Risks ...
## High Risks ...
## Medium Risks ...
## Low Risks / Informational ...
## Anomalies Detected ... timeout: 60 retry: max_attempts: 2 backoff_base: 2 backoff_multiplier: 2.0
# Step 3: Operator-Friendly Change Summary - id: change_summary name: Change Summary for Operators type: llm model: fast system: | You are a technical writer creating infrastructure change summaries for network operators and on-call engineers who need to understand changes quickly.
Write in plain English. Avoid IaC jargon. Focus on operational impact:
**What operators care about:** - What endpoints/services are affected? - Will there be downtime or degraded performance? - What ports/protocols are changing? - Are there IP address changes? - What monitoring/alerting might fire? - What rollback steps exist? - Are there dependencies that need coordination?
**Format guidelines:** - Use bullet points for easy scanning - Group by service/application affected - Include before/after for key changes - Highlight anything requiring manual intervention - Note if changes are reversible vs destructive
**Avoid:** - Terraform/Pulumi/CDK resource type names - ARNs or resource IDs (use friendly names) - Implementation details (use outcomes) prompt: | Create an operator-friendly summary of these infrastructure changes:
**Environment:** {{.inputs.environment}}
**Raw Plan:** ``` {{if .inputs.plan_output}}{{.inputs.plan_output}}{{else}}{{.steps.generate_plan.stdout}}{{end}} ```
Write a clear summary that a network operator can understand at 3 AM during an incident.
Format as:
## Summary [One sentence: what's changing and why it matters]
## Services Affected - [Service name]: [what's changing]
## Network Changes - [Any connectivity, routing, DNS changes]
## Potential Impact - [Downtime expectations] - [Performance implications] - [Monitoring alerts to expect]
## Action Required - [Any manual steps needed] - [Coordination required]
## Rollback - [Is this reversible?] - [Rollback steps if needed] timeout: 45 retry: max_attempts: 2 backoff_base: 2 backoff_multiplier: 2.0
# Step 4: Consolidate into final report - id: final_report name: Generate Final Report type: llm model: fast system: | You are combining a risk analysis and change summary into a single deployment review document. Keep both sections intact but add:
1. An executive summary at the top (2-3 sentences) 2. A clear GO/NO-GO recommendation 3. Required approvals based on risk level prompt: | Combine these analyses into a final IaC change review:
**Risk Analysis:** {{.steps.risk_analysis.response}}
**Operator Summary:** {{.steps.change_summary.response}}
Create a final report with: 1. Executive Summary (2-3 sentences) 2. GO/NO-GO Recommendation 3. Required Approvals (based on {{.inputs.environment}} and risk level) 4. Risk Analysis (from above) 5. Operator Summary (from above)
For production + CRITICAL/HIGH risks, recommend approval from: - Platform team lead - Security team (for security-related changes) - Database team (for data changes) timeout: 30
outputs: - name: report type: string value: "{{.steps.final_report.response}}" description: Complete IaC change review report
- name: risk_score type: string value: "{{.steps.risk_analysis.response}}" description: Detailed risk analysis
- name: operator_summary type: string value: "{{.steps.change_summary.response}}" description: Operator-friendly change summary
- name: recommendation type: string value: "{{.steps.final_report.response}}" description: GO/NO-GO recommendation with required approvalsWhy Use an LLM for This?
IaC plan outputs are verbose and technical. Important changes hide in walls of text:
- A security group rule change is just one line among hundreds
- Resource destruction looks the same as resource creation at a glance
- The operational impact of changes isn’t obvious from resource diffs
This workflow uses LLM reasoning to:
- Identify risks - Flag dangerous changes that humans might miss
- Assess context - Understand that deleting a database in production is worse than in dev
- Translate for operators - Convert technical diffs into “what does this mean at 3 AM?”
Features
- Multi-tool support: Terraform, Pulumi, CDK
- Risk scoring: 0-100 score with GO/NO-GO recommendation
- Anomaly detection: Flags unexpected changes and drift
- Operator summaries: Plain English explanations for on-call engineers
- Environment awareness: Different thresholds for dev vs production
- Approval routing: Recommends who needs to approve based on risk
Usage
Basic Usage - Run Plan Inline
# Terraform projectconductor run examples/iac-review \ --input working_dir=./infrastructure \ --input tool=terraform \ --input environment=production
# Pulumi projectconductor run examples/iac-review \ --input working_dir=./infra \ --input tool=pulumi \ --input environment=staging
# CDK projectconductor run examples/iac-review \ --input working_dir=./cdk \ --input tool=cdk \ --input environment=devProvide Pre-Generated Plan
If you’ve already run the plan, pass it directly:
# Terraformterraform plan -no-color > plan.txtconductor run examples/iac-review \ --input plan_output="$(cat plan.txt)" \ --input tool=terraform \ --input environment=production
# Pulumipulumi preview --diff > preview.txtconductor run examples/iac-review \ --input plan_output="$(cat preview.txt)" \ --input tool=pulumi \ --input environment=productionCI/CD Integration
GitHub Actions
name: IaC Reviewon: pull_request: paths: - 'terraform/**' - 'infrastructure/**'
jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup Terraform uses: hashicorp/setup-terraform@v3
- name: Terraform Init run: terraform init working-directory: ./terraform
- name: Generate Plan id: plan run: terraform plan -no-color -out=tfplan 2>&1 | tee plan.txt working-directory: ./terraform continue-on-error: true
- name: IaC Review id: review run: | conductor run examples/iac-review \ --input plan_output="$(cat terraform/plan.txt)" \ --input tool=terraform \ --input environment=${{ github.base_ref == 'main' && 'production' || 'staging' }} \ --output-json > review.json
- name: Comment on PR uses: actions/github-script@v7 with: script: | const fs = require('fs'); const review = JSON.parse(fs.readFileSync('review.json', 'utf8')); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: review.report });
- name: Block on Critical run: | if grep -q "BLOCK" review.json; then echo "::error::Critical risks detected. Deployment blocked." exit 1 fiGitLab CI
iac-review: stage: validate script: - terraform init - terraform plan -no-color > plan.txt - | conductor run examples/iac-review \ --input plan_output="$(cat plan.txt)" \ --input tool=terraform \ --input environment=${CI_ENVIRONMENT_NAME:-staging} \ --output-json > review.json - cat review.json | jq -r '.report' artifacts: reports: dotenv: review.env paths: - review.json rules: - changes: - "terraform/**/*"Jenkins Pipeline
pipeline { agent any stages { stage('IaC Review') { steps { dir('terraform') { sh 'terraform init' sh 'terraform plan -no-color > plan.txt' } sh ''' conductor run examples/iac-review \ --input plan_output="$(cat terraform/plan.txt)" \ --input tool=terraform \ --input environment=${ENVIRONMENT} \ --output-json > review.json ''' script { def review = readJSON file: 'review.json' if (review.report.contains('BLOCK')) { error('Critical risks detected. Deployment blocked.') } } } } }}Example Output
## Executive Summary
This change modifies the production RDS instance configuration and updatessecurity group rules. Risk score: 72/100. Requires platform team approvalbefore proceeding.
## Recommendation: PROCEED_WITH_CAUTION
### Required Approvals- Platform team lead (database configuration change)- Security team (security group modification)
---
## Risk Score: 72/100
## Critical RisksNone detected.
## High Risks
### 1. RDS Instance Modification- **Resource:** aws_db_instance.production- **Change:** Modifying instance class from db.r5.large to db.r5.xlarge- **Risk:** Database restart required, potential 5-10 minute downtime- **Recommendation:** Schedule during maintenance window
### 2. Security Group Update- **Resource:** aws_security_group.api_servers- **Change:** Adding ingress rule for port 443 from 10.0.0.0/8- **Risk:** Expands network access to internal CIDR- **Recommendation:** Verify source CIDR is expected
## Medium Risks
### 1. New IAM Role- **Resource:** aws_iam_role.lambda_execution- **Change:** Creating new role with S3 read access- **Risk:** New permissions being introduced- **Recommendation:** Review policy document
---
## Services Affected- **API Service**: Security group rules changing, may affect connectivity- **Database**: Configuration update, expect brief restart
## Network Changes- New ingress rule allowing 10.0.0.0/8 to reach API servers on port 443- No DNS changes- No routing changes
## Potential Impact- 5-10 minute database restart during RDS modification- No expected API downtime (security group changes are immediate)- CloudWatch may alert on RDS metric gaps during restart
## Action Required- Schedule change during maintenance window (recommended: 2-4 AM)- Notify on-call that RDS restart is expected- No manual intervention needed
## Rollback- RDS instance class change is reversible (another restart required)- Security group rule can be removed immediately- IAM role can be deleted if unusedConfiguration Options
| Input | Type | Default | Description |
|---|---|---|---|
working_dir | string | . | Path to IaC project directory |
tool | string | terraform | IaC tool: terraform, pulumi, cdk |
plan_output | string | - | Pre-generated plan (skips running plan command) |
environment | string | unknown | Target environment: dev, staging, production |
strict_mode | boolean | false | Exit non-zero on HIGH or CRITICAL risks |
Customization
Adjust Risk Thresholds
Modify the risk_analysis step’s system prompt to adjust what’s considered CRITICAL vs HIGH:
# In workflow.yaml, adjust the system prompt:system: | # Add your organization's specific risk criteria **CRITICAL Risks:** - Changes to PCI-scoped resources - Modifications to SOC2 audit logging - Your custom criteria...Add Team-Specific Routing
Extend the final_report step to route to your teams:
prompt: | ... For database changes, require DBA approval. For network changes, require NetOps approval. For IAM changes, require Security approval.Integrate with Approval Systems
Use the JSON output to drive approval workflows:
# Get recommendationrecommendation=$(conductor run examples/iac-review ... --output-json | jq -r '.recommendation')
case $recommendation in *BLOCK*) echo "Deployment blocked" exit 1 ;; *REQUIRES_APPROVAL*) # Create approval request in your system create_approval_request "$recommendation" ;; *PROCEED*) echo "Safe to proceed" ;;esacRelated Examples
- Security Audit - Code security analysis
- Code Review - Multi-persona code review