Universal Infrastructure as Code (IaC) agent skill for authoring, securing, and managing cloud infrastructure across Terraform, Pulumi, CloudFormation, Ansible, and Bicep. Provides cross-tool security hardening, state management best practices, cost optimization, drift detection, and CI/CD integration. Covers AWS, Azure, GCP, and hybrid-cloud environments with a unified workflow that spans the full IaC lifecycle—from greenfield module authoring through production hardening audits to multi-tool migration planning. Designed for DevOps engineers who switch between IaC tools daily: includes a decision tree for tool selection, per-tool authoring guidelines (HCL patterns, Pulumi TypeScript/Python idioms, CloudFormation YAML conventions, Ansible playbook structure, Bicep DSL tips), security checklist aligned to CIS benchmarks and SOC 2, drift detection workflows that catch configuration skew before it causes outages, and cost-optimization guardrails built into the authoring phase. The skill bridges the gap left by s
Universal Infrastructure as Code (IaC) agent skill for authoring, securing, and managing cloud infrastructure across Terraform, Pulumi, CloudFormation, Ansible, and Bicep. Provides cross-tool security hardening, state management best practices, cost optimization, drift detection, and CI/CD integration. Covers AWS, Azure, GCP, and hybrid-cloud environments with a unified workflow that spans the full IaC lifecycle—from greenfield module authoring through production hardening audits to multi-tool migration planning. Designed for DevOps engineers who switch between IaC tools daily: includes a decision tree for tool selection, per-tool authoring guidelines (HCL patterns, Pulumi TypeScript/Python idioms, CloudFormation YAML conventions, Ansible playbook structure, Bicep DSL tips), security checklist aligned to CIS benchmarks and SOC 2, drift detection workflows that catch configuration skew before it causes outages, and cost-optimization guardrails built into the authoring phase. The skill bridges the gap left by single-tool IaC skills—HashiCorp's focus is Terraform-only, Pulumi's official guidance stays within its own ecosystem—by providing a tool-agnostic framework that treats IaC as a discipline, not a product silo.
AWSTemplateFormatVersion:"2010-09-09"Description:>
Production VPC stack with public/private subnets, NAT gateways,
and VPC endpoints for S3 and DynamoDB. (SOC 2 compliant)
Parameters:Environment:Type:StringAllowedValues: [dev, staging, prod]
Description:DeploymentenvironmentnameVpcCidr:Type:StringDefault:"10.0.0.0/16"AllowedPattern:"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$"Mappings:SubnetConfig:us-east-1:PublicA:"10.0.1.0/24"PrivateA:"10.0.10.0/24"Conditions:IsProduction:!Equals [!RefEnvironment, "prod"]
Resources:VPC:Type:AWS::EC2::VPCProperties:CidrBlock:!RefVpcCidrEnableDnsHostnames:trueEnableDnsSupport:trueTags:-Key:EnvironmentValue:!RefEnvironment-Key:ManagedByValue:CloudFormationOutputs:VpcId:Value:!RefVPCExport:Name:!Sub"${AWS::StackName}-VpcId"
CloudFormation Rules:
Always use !Sub over Fn::Join for readability
Export stack outputs with unique names: ${AWS::StackName}-ResourceId
Use Mappings for region-specific values; Conditions for environment branching
Enable TerminationProtection on production stacks
Use AWS::CloudFormation::StackSet for multi-region/multi-account deployments
Run cfn-lint and cfn-nag in pre-commit; integrate into CI pipeline
Avoid embedding secrets in Parameters—use AWS::SecretsManager::Secret or resolve:ssm-secure:/path
Ansible
Playbook Structure:
---# site.yml — Entry-point playbook-name:Configureproductionwebservershosts:webserversbecome:truevars_files:-vars/production.ymlroles:-common-nginx-node_exporterpre_tasks:-name:Verifyminimumdiskspaceansible.builtin.assert:that:ansible_mounts|selectattr('mount','equalto','/')|map(attribute='size_available')|first>1073741824fail_msg:"Insufficient disk space on / "post_tasks:-name:Senddeploymentnotificationansible.builtin.uri:url:"{{ slack_webhook_url }}"method:POSTbody:'{"text": "Deployment complete on {{ inventory_hostname }}"}'
Ansible IaC Patterns:
Use ansible.builtin.* FQCNs for all modules (future-proof against collections changes)
Separate inventory by environment: inventories/production/hosts.yml
Encrypt secrets with ansible-vault; never store plaintext in vars files
Use check_mode: true for dry-run validation before production applies
--diff flag for configuration change previews (acts as drift detection)
Idempotency is mandatory—every task must produce the same result on repeat runs
Use ansible-lint with production ruleset; integrate into pre-commit hooks
Auto-scaling configured with min/max bounds (not static instance counts)
Reserved Instances / Savings Plans for predictable workloads
S3 lifecycle policies: transition to IA/Glacier, expire old versions
NAT Gateway count minimized (use single-AZ for dev, multi-AZ for prod)
RDS: stop-dev-instances automation for non-production after hours
Lambda: memory and timeout tuned (not default 128MB/3s for everything)
State Management Best Practices
Terraform / OpenTofu
Remote State is Mandatory. No local state files in production repos. Use S3 + DynamoDB (AWS), Azure Storage (Azure), GCS (GCP).
State File Isolation. One state file per environment (dev/staging/prod), per region, and per logical boundary (networking, compute, data).
State Locking. Always enable DynamoDB locks (AWS) or equivalent. Prevents concurrent applies that corrupt state.
State Encryption. Enable server-side encryption on state storage. encrypt = true in backend config.
Workspace Strategy. Use separate backends or directory separation. Avoid terraform workspace for long-lived environments—they share the same backend and credentials.
State Access Control. Restrict state bucket access to CI/CD service roles and senior engineers. No developer IAM users with direct state read/write.
State Versioning. Enable bucket versioning on state storage for rollback capability.
State Import Hygiene.terraform import should be followed immediately by cleanup of manual resource configs. Document every import in a migration log.
State Refresh. Run terraform apply -refresh-only before plan to reconcile external changes.
Never Edit State Files. Use terraform state mv, terraform state rm, terraform state pull—never edit JSON state manually.
Pulumi
Pulumi Cloud or Self-Managed Backend. Pulumi Cloud (SaaS) is the default and recommended. For self-managed, use S3/Azure/GCS with the Pulumi service managing locking.
Stack Configuration. Separate stacks per environment. Use pulumi config set --secret for sensitive values.
State Export.pulumi stack export for backup; pulumi stack import for recovery.
Resource Protection.protect: true on stateful resources (RDS, DynamoDB) to prevent accidental deletion.
State History. Pulumi Cloud retains deployment history; self-managed backends use object versioning.
CloudFormation
Change Sets. Always create a Change Set and review before executing. Never direct-update production stacks.
Stack Policies. Define stack policies that prevent updates/replacements of stateful resources during routine changes.
Nested Stacks. Use nested stacks for large deployments to stay within resource limits (500 resources per stack). Export shared outputs via Fn::ImportValue.
StackSets. For multi-account/multi-region: use StackSets with service-managed permissions.
Cross-Cutting Rules
Never share state between tools. A resource created by Terraform should not be managed by Pulumi in the same state.
State backup is non-negotiable. Automate daily state file backups to a separate, immutable bucket.
State access audit. Log all state file reads/writes. Alert on unexpected access patterns.
Drift Detection Workflow
Drift = configuration in code ≠ actual infrastructure state. Drift causes outages, security gaps, and compliance failures.
Standard Workflow
1. IDENTIFY
├─ Terraform: terraform plan -detailed-exitcode
├─ Pulumi: pulumi refresh --diff
├─ CFn: aws cloudformation detect-stack-drift
├─ Bicep: az deployment group what-if
└─ Ansible: ansible-playbook --check --diff site.yml
2. CLASSIFY
├─ EXPECTED DRIFT (auto-scaling events, tag auto-updates)
│ └─ Update code to match reality (terraform import / pulumi import)
└─ UNEXPECTED DRIFT (manual console changes, security group widens)
└─ Investigate audit logs → Reconcile or revert
3. RECONCILE
├─ Prefer code-as-truth: update infrastructure to match code
├─ Import manual changes: terraform import / pulumi import / CFn resource import
└─ Document exceptions: lifecycle { ignore_changes = [...] }
4. PREVENT
├─ Restrict console access (break-glass only, with auto-revert)
├─ Run drift detection on schedule (hourly for prod, daily for staging)
├─ Alert on drift via CloudWatch/PagerDuty/Slack
└─ Auto-remediate with AWS Config rules or OPA policies
Alternatively: former2 (ex-cloudformer) → generates Terraform/AWS CDK from existing infra
Post-import: terraform plan to verify no diffs; then remove CloudFormation stack after confirming resources are imported (use DeletionPolicy: Retain during transition)
Terraform → Pulumi
Use pulumi import with Terraform state:
pulumi import --from terraform terraform.tfstate
Use tf2pulumi to convert HCL to TypeScript/Python: tf2pulumi ./modules/*.tf
Validate with pulumi preview before going live
ARM → Bicep
bicep decompile for automated conversion: az bicep decompile --file template.json
Manual review required—Bicep decompilation is not lossless for complex templates
Quick Reference
Terraform One-Liners
terraform fmt -recursive -diff # Format all .tf files, show diffs
terraform validate # Syntax check
terraform plan -out=tfplan # Generate plan file
terraform apply tfplan # Apply from plan (safe)
terraform plan -detailed-exitcode # Returns 2 if drift exists
terraform state list # List all managed resources
terraform state rm resource.addr # Stop managing (don't destroy)
terraform import resource.addr resource-id # Adopt existing resource
terraform output -json # Machine-readable outputs
terraform console # Interactive REPL
terraform graph | dot -Tpng > graph.png # Dependency visualization
Pulumi One-Liners
pulumi preview --json # Machine-readable plan
pulumi up --yes --skip-preview # Quick apply (with caution)
pulumi refresh --diff # Detect drift
pulumi stack export --file state.json # Backup state
pulumi config set aws:region us-east-1 # Set config
pulumi config set --secret dbPassword # Set secret
pulumi import --from terraform state.tfstate # Migrate from Terraform
pulumi policy pack # Generate policy pack skeleton
1. Hardcoded Secrets (CRITICAL — #1 cause of security incidents)
Symptoms: passwords, API keys, private keys in .tf, .ts, .yaml files.
Fix: Use Vault dynamic secrets, AWS Secrets Manager, Pulumi ESC, or Azure Key Vault with data-source lookups.
Detection:gitleaks detect --source . --verbose
2. Overly Permissive IAM (CRITICAL)
Symptoms:"Action": "*", "Resource": "*" in IAM policy documents.
Fix: Explicit action lists; resource ARN constraints; IAM Access Analyzer validation.
Tool:checkov -d . --check CKV_AWS_* for Terraform; cfn_nag_scan for CloudFormation.
3. Missing Lifecycle Rules (HIGH)
Symptoms: Database destroyed during routine update because prevent_destroy was absent.
Fix: Every stateful resource needs:
lifecycle {
prevent_destroy = true
}
4. No Remote State (HIGH)
Symptoms:terraform.tfstate in git repository; state file conflicts between teammates.
Fix: Configure remote backend with locking before the first terraform apply.
5. State-Only Changes Without Infrastructure Updates (MEDIUM)
Symptoms:terraform state rm used to "fix" issues instead of updating code.
Fix: Always update .tf files first; only use state manipulation as an emergency bridge.
6. Unpinned Provider Versions (MEDIUM)
Symptoms: CI pipeline breaks because provider released a breaking change.
Fix: Pin both Terraform core and provider versions with required_providers blocks.
7. Monolithic State Files (MEDIUM)
Symptoms: Plan times >10 minutes; blast radius covers entire infrastructure.
Fix: Split state by environment, region, and logical domain. Use terraform output and data sources for cross-state references.
8. Ignoring Drift (MEDIUM)
Symptoms:terraform plan shows unexpected changes long after initial apply.
Fix: Schedule drift checks; restrict console access; use SCPs to prevent manual modifications.
Symptoms: Untaggable resources lead to untracked cloud spend.
Fix: Enforce tags with Terraform default_tags on provider block or Pulumi transformations. Cost allocation tags in AWS Billing.
10. Inappropriate count Usage (LOW)
Symptoms: Changing a list element reorders resources and triggers destroy/recreate.
Fix: Use for_each with a map or toset()—deterministic keys prevent cascading changes.
SEO Metadata
Primary Keywords
infrastructure as code
IaC security hardening
Terraform best practices
Pulumi patterns
drift detection IaC
IaC state management
CloudFormation to Terraform migration
IaC CI/CD pipeline
Secondary Keywords
Bicep module patterns
Ansible playbook structure
IaC cost optimization
IaC compliance checklist
CIS benchmark IaC
least privilege IAM IaC
OpenTofu migration
Crossplane compositions
Search Intent Alignment
Informational: "What is the best IaC tool for multi-cloud?" → Decision Tree section
Tutorial: "How to secure Terraform code" → Security Hardening Checklist
Comparative: "Terraform vs Pulumi vs CloudFormation" → Comparison Matrix
Troubleshooting: "How to fix Terraform drift" → Drift Detection Workflow
Migration: "How to migrate CloudFormation to Terraform" → Migration Patterns