AWS infrastructure patterns and best practices for Terraform. Provides VPC, IAM, S3, and security group scaffolds. Use when developing AWS infrastructure.
/plugin marketplace add lgbarn/terraform-aws-eks/plugin install lgbarn-terraform-aws-eks-plugins-terraform-aws-eks@lgbarn/terraform-aws-eksThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Terraform patterns for AWS infrastructure development.
ALWAYS use doc-researcher or Terraform MCP to verify current provider schemas.
Use {project}-{environment}-{resource} pattern consistently:
locals {
name_prefix = "${var.project}-${var.environment}"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "${local.name_prefix}-vpc"
cidr = var.vpc_cidr # e.g., "10.0.0.0/16"
azs = data.aws_availability_zones.available.names
private_subnets = [for k, v in local.azs : cidrsubnet(var.vpc_cidr, 4, k)]
public_subnets = [for k, v in local.azs : cidrsubnet(var.vpc_cidr, 8, k + 48)]
intra_subnets = [for k, v in local.azs : cidrsubnet(var.vpc_cidr, 8, k + 52)]
enable_nat_gateway = true
single_nat_gateway = var.environment != "prod"
enable_dns_hostnames = true
enable_dns_support = true
# EKS requirements
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
}
tags = var.tags
}
data "aws_availability_zones" "available" {
state = "available"
}
locals {
azs = slice(data.aws_availability_zones.available.names, 0, 3)
}
module "vpc_endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
version = "~> 5.0"
vpc_id = module.vpc.vpc_id
endpoints = {
s3 = {
service = "s3"
service_type = "Gateway"
route_table_ids = module.vpc.private_route_table_ids
tags = { Name = "${local.name_prefix}-s3-endpoint" }
}
ecr_api = {
service = "ecr.api"
private_dns_enabled = true
subnet_ids = module.vpc.private_subnets
security_group_ids = [aws_security_group.vpc_endpoints.id]
}
ecr_dkr = {
service = "ecr.dkr"
private_dns_enabled = true
subnet_ids = module.vpc.private_subnets
security_group_ids = [aws_security_group.vpc_endpoints.id]
}
sts = {
service = "sts"
private_dns_enabled = true
subnet_ids = module.vpc.private_subnets
security_group_ids = [aws_security_group.vpc_endpoints.id]
}
}
tags = var.tags
}
resource "aws_security_group" "vpc_endpoints" {
name_prefix = "${local.name_prefix}-vpc-endpoints-"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [module.vpc.vpc_cidr_block]
}
tags = merge(var.tags, { Name = "${local.name_prefix}-vpc-endpoints" })
}
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "service" {
name = "${local.name_prefix}-service-role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
tags = var.tags
}
resource "aws_iam_instance_profile" "service" {
name = "${local.name_prefix}-service-profile"
role = aws_iam_role.service.name
}
data "aws_iam_policy_document" "permissions" {
statement {
sid = "S3ReadAccess"
effect = "Allow"
actions = [
"s3:GetObject",
"s3:ListBucket"
]
resources = [
aws_s3_bucket.data.arn,
"${aws_s3_bucket.data.arn}/*"
]
}
statement {
sid = "SecretsManagerAccess"
effect = "Allow"
actions = [
"secretsmanager:GetSecretValue"
]
resources = [
"arn:aws:secretsmanager:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:secret:${var.project}/*"
]
}
}
resource "aws_iam_role_policy" "service" {
name = "${local.name_prefix}-service-policy"
role = aws_iam_role.service.id
policy = data.aws_iam_policy_document.permissions.json
}
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
locals {
account_id = data.aws_caller_identity.current.account_id
region = data.aws_region.current.name
}
resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data-${local.account_id}"
tags = var.tags
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.s3.arn
}
bucket_key_enabled = true
}
}
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_lifecycle_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
id = "transition-to-ia"
status = "Enabled"
transition {
days = 30
storage_class = "STANDARD_IA"
}
transition {
days = 90
storage_class = "GLACIER"
}
noncurrent_version_expiration {
noncurrent_days = 30
}
}
}
# ALB Security Group - Public facing
resource "aws_security_group" "alb" {
name_prefix = "${local.name_prefix}-alb-"
vpc_id = module.vpc.vpc_id
ingress {
description = "HTTPS from internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
tags = merge(var.tags, { Name = "${local.name_prefix}-alb" })
}
# Application Security Group - Only from ALB
resource "aws_security_group" "app" {
name_prefix = "${local.name_prefix}-app-"
vpc_id = module.vpc.vpc_id
ingress {
description = "From ALB"
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
tags = merge(var.tags, { Name = "${local.name_prefix}-app" })
}
# Database Security Group - Only from App
resource "aws_security_group" "db" {
name_prefix = "${local.name_prefix}-db-"
vpc_id = module.vpc.vpc_id
ingress {
description = "PostgreSQL from app"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app.id]
}
lifecycle {
create_before_destroy = true
}
tags = merge(var.tags, { Name = "${local.name_prefix}-db" })
}
resource "aws_kms_key" "main" {
description = "KMS key for ${local.name_prefix}"
deletion_window_in_days = 7
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${local.account_id}:root"
}
Action = "kms:*"
Resource = "*"
}
]
})
tags = var.tags
}
resource "aws_kms_alias" "main" {
name = "alias/${local.name_prefix}-main"
target_key_id = aws_kms_key.main.key_id
}
variable "project" {
description = "Project name for resource naming and tagging"
type = string
}
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "additional_tags" {
description = "Additional tags to apply to all resources"
type = map(string)
default = {}
}
locals {
default_tags = {
Project = var.project
Environment = var.environment
Terraform = "true"
ManagedBy = "terraform"
}
tags = merge(local.default_tags, var.additional_tags)
}
# Current AWS context
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
data "aws_partition" "current" {}
# Availability zones
data "aws_availability_zones" "available" {
state = "available"
}
# Latest Amazon Linux 2 AMI
data "aws_ami" "amazon_linux_2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# SSM Parameter for EKS AMI
data "aws_ssm_parameter" "eks_ami" {
name = "/aws/service/eks/optimized-ami/${var.cluster_version}/amazon-linux-2/recommended/image_id"
}
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.