Scaffold Terraform 1.9+ infrastructure with provider configuration (AWS/GCP/Azure), modular structure, remote state, variables, outputs, workspaces, and common resource patterns.
79
Quality
73%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./infrastructure/terraform-starter/SKILL.mdScaffold Terraform 1.9+ infrastructure with provider configuration (AWS/GCP/Azure), modular structure, remote state, variables, outputs, workspaces, and common resource patterns.
mkdir -p infra/{modules,environments/dev,environments/staging,environments/production}
# Root module
touch infra/main.tf infra/variables.tf infra/outputs.tf infra/providers.tf infra/backend.tf infra/versions.tf
# Module scaffolds
mkdir -p infra/modules/{networking,compute,database,storage}
touch infra/modules/networking/{main.tf,variables.tf,outputs.tf}
touch infra/modules/compute/{main.tf,variables.tf,outputs.tf}
touch infra/modules/database/{main.tf,variables.tf,outputs.tf}
# Environment tfvars
touch infra/environments/dev/terraform.tfvars
touch infra/environments/staging/terraform.tfvars
touch infra/environments/production/terraform.tfvars
# Gitignore for Terraform
cat <<'EOF' > infra/.gitignore
.terraform/
*.tfstate
*.tfstate.backup
*.tfplan
.terraform.lock.hcl
*.auto.tfvars
EOFinfra/
main.tf # Root module — composes child modules
variables.tf # Input variables
outputs.tf # Outputs from root module
providers.tf # Provider configuration
backend.tf # Remote state backend
versions.tf # Required providers and Terraform version
modules/
networking/
main.tf # VPC, subnets, NAT gateway, security groups
variables.tf
outputs.tf
compute/
main.tf # ECS/EC2/GKE/AKS clusters
variables.tf
outputs.tf
database/
main.tf # RDS/CloudSQL/CosmosDB
variables.tf
outputs.tf
storage/
main.tf # S3/GCS buckets
variables.tf
outputs.tf
environments/
dev/
terraform.tfvars # Dev-specific variable values
staging/
terraform.tfvars
production/
terraform.tfvarsterraform.tfvars files per environment, selected via -var-file.versions.tf.locals for computed values. Keep variables.tf for user-supplied inputs.${var.project}-${var.environment}-<resource>.Project, Environment, ManagedBy=terraform..tfvars files. Use sensitive = true variables or data sources from secret managers.terraform fmt before every commit.versions.tf)terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}backend.tf)terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "myapp/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}backend.tf)terraform {
backend "gcs" {
bucket = "mycompany-terraform-state"
prefix = "myapp"
}
}providers.tf)provider "aws" {
region = var.aws_region
default_tags {
tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
}
}
}variables.tf)variable "project" {
description = "Project name used as resource prefix"
type = string
}
variable "environment" {
description = "Environment name (dev, staging, production)"
type = string
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "Environment must be one of: dev, staging, production."
}
}
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}main.tf)locals {
name_prefix = "${var.project}-${var.environment}"
}
module "networking" {
source = "./modules/networking"
name_prefix = local.name_prefix
vpc_cidr = var.vpc_cidr
environment = var.environment
}
module "database" {
source = "./modules/database"
name_prefix = local.name_prefix
subnet_ids = module.networking.private_subnet_ids
security_group_ids = [module.networking.db_security_group_id]
environment = var.environment
db_instance_class = var.db_instance_class
}
module "compute" {
source = "./modules/compute"
name_prefix = local.name_prefix
subnet_ids = module.networking.private_subnet_ids
security_group_ids = [module.networking.app_security_group_id]
database_url = module.database.connection_url
environment = var.environment
}modules/networking/main.tf)data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = { Name = "${var.name_prefix}-vpc" }
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = { Name = "${var.name_prefix}-public-${count.index}" }
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = { Name = "${var.name_prefix}-private-${count.index}" }
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = { Name = "${var.name_prefix}-igw" }
}
resource "aws_eip" "nat" {
domain = "vpc"
tags = { Name = "${var.name_prefix}-nat-eip" }
}
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public[0].id
tags = { Name = "${var.name_prefix}-nat" }
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = { Name = "${var.name_prefix}-public-rt" }
}
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main.id
}
tags = { Name = "${var.name_prefix}-private-rt" }
}
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
count = length(aws_subnet.private)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private.id
}modules/database/main.tf)resource "aws_db_subnet_group" "main" {
name = "${var.name_prefix}-db-subnet"
subnet_ids = var.subnet_ids
tags = { Name = "${var.name_prefix}-db-subnet" }
}
resource "aws_db_instance" "main" {
identifier = "${var.name_prefix}-db"
engine = "postgres"
engine_version = "16.4"
instance_class = var.db_instance_class
allocated_storage = 20
max_allocated_storage = 100
storage_encrypted = true
db_name = var.db_name
username = var.db_username
password = var.db_password
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = var.security_group_ids
multi_az = var.environment == "production"
skip_final_snapshot = var.environment != "production"
backup_retention_period = var.environment == "production" ? 7 : 1
tags = { Name = "${var.name_prefix}-db" }
}modules/storage/main.tf)resource "aws_s3_bucket" "main" {
bucket = "${var.name_prefix}-${var.bucket_suffix}"
tags = { Name = "${var.name_prefix}-${var.bucket_suffix}" }
}
resource "aws_s3_bucket_versioning" "main" {
bucket = aws_s3_bucket.main.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "main" {
bucket = aws_s3_bucket.main.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_s3_bucket_public_access_block" "main" {
bucket = aws_s3_bucket.main.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}environments/dev/terraform.tfvars)project = "myapp"
environment = "dev"
aws_region = "us-east-1"
vpc_cidr = "10.0.0.0/16"
db_instance_class = "db.t4g.micro"outputs.tf)output "vpc_id" {
description = "VPC ID"
value = module.networking.vpc_id
}
output "database_endpoint" {
description = "RDS endpoint"
value = module.database.endpoint
sensitive = true
}# Initialize (download providers, configure backend)
terraform -chdir=infra init
# Format all files
terraform -chdir=infra fmt -recursive
# Validate configuration
terraform -chdir=infra validate
# Plan with environment-specific vars
terraform -chdir=infra plan -var-file=environments/dev/terraform.tfvars -out=dev.tfplan
# Apply a saved plan
terraform -chdir=infra apply dev.tfplan
# Destroy (dev only)
terraform -chdir=infra destroy -var-file=environments/dev/terraform.tfvars
# Import existing resource
terraform -chdir=infra import module.networking.aws_vpc.main vpc-abc123
# Show current state
terraform -chdir=infra show
# List resources in state
terraform -chdir=infra state list
# Upgrade providers
terraform -chdir=infra init -upgradekubernetes-manifests skill. Terraform provisions the cluster (EKS/GKE/AKS); kubectl/kustomize manages workloads.github-actions-ci skill. Run terraform plan on PR, terraform apply on merge. Use OIDC for cloud auth.aws_secretsmanager_secret / google_secret_manager_secret for runtime secrets. Reference them in compute modules via IAM roles, not hardcoded values.181fcbc
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.