Skip to main content
infrastructure-as-code Provides Infrastructure as Code best practices for Terraform, Pulumi, CloudFormation, and OpenTofu. Use when provisioning infrastructure, writing IaC modules, managing cloud resources, scanning for misconfigurations, or when user mentions 'terraform', 'pulumi', 'cloudformation', 'IaC', 'opentofu', 'infrastructure', 'tfsec', 'checkov', 'drift'.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/Tibsfox/gsd-skill-creator --skill infrastructure-as-code명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Use the moment a request is underspecified and you are about to act on an ASSUMED goal. Enumerate the candidate goals the request could mean, project the action or artifact each one implies, and check whether they diverge: if two or more plausible goals lead to materially different actions or artifacts, ask exactly ONE targeted clarifying question; otherwise proceed on the most-likely goal and state the assumption in one line. Clarification is an evidence-producing action, not a delay — but one question, never an interrogation. Distinct from gsd-spec-phase (GSD-phase-bound, emits a heavy SPEC.md) and intent-router (fetch strategy, not goal disambiguation). Backed by agent goal-state inference (arxiv 2606.16813v1). Triggers on acting under an assumed goal when the request admits more than one materially different reading.
Use at write time to vector/embedding memory — Grove content-addressed insertion, chroma/pgvector upserts, memory-consolidation promoting session traces to MEMORY.md, or embedding externally-ingested content. Scores each candidate record against a fixed panel of sentinel queries and quarantines any record that would become the nearest neighbor of too many unrelated queries — a hub — whether from adversarial poisoning or accidental over-generality. This is the memory-record-side sibling of skill-injection-guardian (file-side) and the write-side complement of memory-use-warrant (read-side). Quarantine, never silently drop; a human reviews. Backed by the admission-time hubness gate (arxiv 2606.19692v1). Triggers on inserting into vector memory, consolidating memory, and embedding stranger content.
Run this appropriateness check the moment you are about to integrate a retrieved long-term memory — a Grove content-addressed hit, a chroma/pgvector neighbour, a memory-consolidation digest, or a MEMORY.md line — into a response, especially anything touching private origins, Fox Companies IP, credentials, or Center Camp / consent-governed content. It answers a question intent-router never asks: not WHAT to fetch or HOW, but WHETHER a correctly-retrieved item should reach output. Relevance is not appropriateness — a perfect similarity match can still be a boundary violation. Default is FAIL-CLOSED: if in-context authorization is uncertain, the memory may inform behaviour but must not be surfaced. Backed by RBI-Eval (arxiv 2606.06055v1). Triggers on surfacing recalled sensitive memory into a response.
name infrastructure-as-code description Provides Infrastructure as Code best practices for Terraform, Pulumi, CloudFormation, and OpenTofu. Use when provisioning infrastructure, writing IaC modules, managing cloud resources, scanning for misconfigurations, or when user mentions 'terraform', 'pulumi', 'cloudformation', 'IaC', 'opentofu', 'infrastructure', 'tfsec', 'checkov', 'drift'. type skill category patterns status stable origin tibsfox modified false first_seen "2026-02-07T00:00:00.000Z" first_path examples/infrastructure-as-code/SKILL.md superseded_by null
Infrastructure as Code
Best practices for managing cloud infrastructure declaratively with Terraform, Pulumi, CloudFormation, and OpenTofu. Covers module composition, state management, security scanning, and drift prevention.
IaC Tool Comparison
Choose the right tool based on team skills, cloud strategy, and operational requirements.
Tool Language State Management Multi-Cloud Learning Curve Ecosystem Terraform HCL Remote backend (S3, GCS, etc.) Excellent Medium Largest provider ecosystem OpenTofu HCL Same as Terraform Excellent Medium Fork-compatible with Terraform Pulumi TypeScript, Python, Go, C# Pulumi Cloud or self-managed Excellent Low for developers Growing, SDK-based CloudFormation YAML/JSON AWS-managed AWS only Medium Native AWS integration CDK TypeScript, Python, Java, Go AWS-managed (synths to CFN) AWS only Low for developers Leverages CFN resources
Decision Factor Recommendation Multi-cloud required Terraform or Pulumi AWS-only shop CloudFormation or CDK Team knows TypeScript Pulumi or CDK Need open-source license OpenTofu Existing Terraform codebase Stay Terraform or migrate to OpenTofu Complex logic and loops Pulumi (general-purpose language)
State Management Patterns
State is the source of truth for what IaC has provisioned. Mismanaging state causes orphaned resources, duplicate deployments, and data loss.
+------------------+ +------------------+ +------------------+
| Developer CLI | ----> | Remote Backend | <---- | CI/CD Pipeline |
+------------------+ +------------------+ +------------------+
| - S3 + DynamoDB |
| - GCS + Lock |
| - Terraform Cloud|
+------------------+
Pattern When to Use Implementation Single state file Small projects, <20 resources One backend config State per environment Separate dev/staging/prod Workspace or directory per env State per component Large infra, team boundaries Separate root modules with data sources Hierarchical state Complex multi-team orgs Layers: network -> compute -> app
Terraform Remote State Configuration # backend.tf -- Remote state with locking
terraform {
backend "s3" {
bucket = "myorg-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
# State locking table -- provision FIRST with a bootstrap module
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
# Cross-stack references via remote state data source
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "myorg-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
}
}
resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.network.outputs.private_subnet_ids[0]
}
Module Composition and Versioning Modules are the unit of reuse in Terraform and OpenTofu. Good module design follows the single-responsibility principle.
modules/
vpc/
main.tf # Resources
variables.tf # Input variables with validation
outputs.tf # Output values for consumers
versions.tf # Required providers and versions
environments/
dev/
main.tf # Calls modules with dev parameters
backend.tf # Dev state backend
terraform.tfvars # Dev variable values
prod/
main.tf
backend.tf
terraform.tfvars
Terraform Module Example # modules/vpc/variables.tf
variable "name" {
description = "Name prefix for all VPC resources"
type = string
validation {
condition = length(var.name) <= 24
error_message = "Name must be 24 characters or fewer."
}
}
variable "cidr_block" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "Must be a valid CIDR block."
}
}
variable "availability_zones" {
type = list(string)
}
variable "tags" {
type = map(string)
default = {}
}
# modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, { Name = "${var.name}-vpc" })
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.cidr_block, 8, count.index)
availability_zone = var.availability_zones[count.index]
tags = merge(var.tags, {
Name = "${var.name}-public-${var.availability_zones[count.index]}"
Tier = "public"
})
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.cidr_block, 8, count.index + length(var.availability_zones))
availability_zone = var.availability_zones[count.index]
tags = merge(var.tags, {
Name = "${var.name}-private-${var.availability_zones[count.index]}"
Tier = "private"
})
}
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.this.id
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
# environments/prod/main.tf -- Consuming the module
module "vpc" {
source = "git::https://github.com/myorg/terraform-modules.git//vpc?ref=v2.1.0"
name = "prod"
cidr_block = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
tags = { Environment = "production", Team = "platform" }
}
Versioning Strategy Source Format When to Use Git tag git::https://...?ref=v2.1.0Internal modules, full control Terraform Registry source = "hashicorp/consul/aws" version = "0.1.0"Public modules Local path source = "../../modules/vpc"Monorepo, development S3/GCS archive source = "s3::https://..."Air-gapped environments
Pulumi TypeScript Example Pulumi uses general-purpose languages, giving full IDE support, type checking, and testing capabilities.
import * as pulumi from "@pulumi/pulumi" ;
import * as aws from "@pulumi/aws" ;
const config = new pulumi.Config ();
const env = pulumi.getStack ();
const vpcCidr = config.get ("vpcCidr" ) || "10.0.0.0/16" ;
class VpcComponent extends pulumi.ComponentResource {
public readonly vpcId : pulumi.Output <string >;
public readonly publicSubnetIds : pulumi.Output <string >[];
public readonly privateSubnetIds : pulumi.Output <string >[];
constructor (name : string , args : {
cidr: string ; azCount: number ; enableNat: boolean ;
}, opts ?: pulumi.ComponentResourceOptions ) {
super ("custom:network:Vpc" , name, {}, opts);
const vpc = new aws.ec2 .Vpc (`${name} -vpc` , {
cidrBlock : args.cidr ,
enableDnsHostnames : true ,
enableDnsSupport : true ,
tags : { Name : `${name} -vpc` , Environment : env },
}, { parent : this });
this .vpcId = vpc.id ;
this .publicSubnetIds = [];
this .privateSubnetIds = [];
const azs = aws.getAvailabilityZones ({ state : "available" });
for (let i = 0 ; i < args.azCount ; i++) {
const pub = new aws.ec2 .Subnet (`${name} -public-${i} ` , {
vpcId : vpc.id ,
cidrBlock : `10.0.${i} .0/24` ,
availabilityZone : azs.then (az => az.names [i]),
mapPublicIpOnLaunch : true ,
tags : { Name : `${name} -public-${i} ` , Tier : "public" },
}, { parent : this });
const priv = new aws.ec2 .Subnet (`${name} -private-${i} ` , {
vpcId : vpc.id ,
cidrBlock : `10.0.${i + args.azCount} .0/24` ,
availabilityZone : azs.then (az => az.names [i]),
tags : { Name : `${name} -private-${i} ` , Tier : "private" },
}, { parent : this });
this .publicSubnetIds .push (pub.id );
this .privateSubnetIds .push (priv.id );
}
this .registerOutputs ({ vpcId : this .vpcId });
}
}
const network = new VpcComponent ("main" , {
cidr : vpcCidr, azCount : 3 , enableNat : env === "prod" ,
});
export const vpcId = network.vpcId ;
CloudFormation YAML Example CloudFormation is AWS-native and requires no external state management. Ideal for AWS-only environments with strict compliance requirements.
AWSTemplateFormatVersion: '2010-09-09'
Description: Production VPC with public and private subnets
Parameters:
EnvironmentName:
Type: String
Default: prod
AllowedValues: [dev , staging , prod ]
VpcCIDR:
Type: String
Default: '10.0.0.0/16'
Conditions:
IsProduction: !Equals [!Ref EnvironmentName , prod ]
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-vpc'
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [0 , !Cidr [!Ref VpcCIDR , 6 , 8 ]]
AvailabilityZone: !Select [0 , !GetAZs '' ]
MapPublicIpOnLaunch: true
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [3 , !Cidr [!Ref VpcCIDR , 6 , 8 ]]
AvailabilityZone: !Select [0 , !GetAZs '' ]
NatGateway:
Type: AWS::EC2::NatGateway
Condition: IsProduction
Properties:
AllocationId: !GetAtt NatEIP.AllocationId
SubnetId: !Ref PublicSubnetA
NatEIP:
Type: AWS::EC2::EIP
Condition: IsProduction
Properties:
Domain: vpc
Outputs:
VpcId:
Value: !Ref VPC
Export:
Name: !Sub '${EnvironmentName}-VpcId'
Security Scanning with Checkov and tfsec Scan IaC before apply to catch misconfigurations, policy violations, and security risks.
Tool Focus Language Integration Checkov Multi-framework (TF, CFN, K8s, Helm) Python CLI, CI/CD, IDE tfsec Terraform-specific, fast Go CLI, CI/CD, pre-commit Terrascan Policy-as-code (OPA/Rego) Go CLI, CI/CD Snyk IaC Commercial, wide coverage SaaS CLI, CI/CD, IDE
Checkov Scanning Example
checkov -d ./environments/prod/ --framework terraform --compact
checkov -d ./environments/prod/ --check CKV_AWS_18,CKV_AWS_19
checkov -d ./environments/prod/ --output sarif --output-file results.sarif
name: IaC Security Scan
on:
pull_request:
paths: ['**/*.tf' , '**/*.tfvars' ]
jobs:
checkov:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: bridgecrewio/checkov-action@v12
with:
directory: ./environments/
framework: terraform
output_format: sarif
output_file_path: results.sarif
soft_fail: false
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarif
tfsec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aquasecurity/tfsec-action@v1.0.3
with:
working_directory: ./environments/
Drift Detection and Prevention Drift occurs when actual infrastructure diverges from IaC state. Left unchecked, drift causes failed applies, security gaps, and configuration inconsistencies.
Drift Cause Prevention Manual console changes Lock down console write access; read-only for debugging Auto-scaling events Use lifecycle { ignore_changes } for dynamic attributes External automation Coordinate with IaC or import resources Incomplete IaC coverage Import existing resources before managing them
Drift Detection Strategy
name: Drift Detection
on:
schedule:
- cron: '0 6 * * *'
jobs:
detect-drift:
runs-on: ubuntu-latest
strategy:
matrix:
environment: [dev , staging , prod ]
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7 .0
- name: Terraform Init
working-directory: ./environments/${{ matrix.environment }}
run: terraform init -input=false
- name: Detect Drift
id: plan
working-directory: ./environments/${{ matrix.environment }}
run: |
terraform plan -detailed-exitcode -input=false 2>&1 | tee plan_output.txt
echo "exit_code=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
# Exit code 0 = no changes, 1 = error, 2 = drift detected
continue-on-error: true
- name: Alert on Drift
if: steps.plan.outputs.exit_code == '2'
run: echo "::warning::Drift detected in ${{ matrix.environment }} !"
Preventing Drift with Lifecycle Rules resource "aws_autoscaling_group" "app" {
lifecycle {
ignore_changes = [desired_capacity] # Managed by auto-scaling, not Terraform
}
min_size = 2
max_size = 10
}
resource "aws_security_group" "critical" {
lifecycle {
prevent_destroy = true # Prevent accidental deletion
}
name = "critical-sg"
vpc_id = module.vpc.vpc_id
}
Anti-Patterns Anti-Pattern Problem Fix Local state files No locking, no team access, easy to lose Use remote backend with locking (S3+DynamoDB, GCS) Hardcoded provider credentials Secrets in version control Use environment variables, OIDC, or vault Monolithic root module Slow plans, blast radius covers everything Split into composable modules per service or layer No variable validation Invalid inputs cause cryptic errors at apply Add validation blocks on all input variables terraform apply without planNo review of changes before execution Always plan -out=plan.tfplan then apply plan.tfplan Ignoring state drift Manual changes accumulate, next apply fails Schedule daily drift detection; alert and remediate No module versioning Breaking changes propagate immediately Pin module versions with git tags or registry versions Inline resources instead of modules Copy-paste across environments, divergence Extract reusable modules, parameterize with variables Storing secrets in tfvars Credentials committed to git Use vault, SSM Parameter Store, or Secrets Manager No import before manage Terraform tries to create existing resources terraform import existing resources firstWildcard provider versions Upgrades break without warning Pin versions with ~> constraints in versions.tf No prevent_destroy on stateful resources Accidental deletion of databases, buckets Add lifecycle { prevent_destroy = true } Running apply from laptops No audit trail, credential exposure Run all applies through CI/CD with approval gates
Security and Compliance Checklist