terraform-style-guide

작성자: hashicorp

HashiCorp의 공식 스타일 규칙을 따라 Terraform 코드를 생성하고 유지 관리합니다. 두 칸 들여쓰기, 소문자 밑줄 명명, terraform.tf, providers.tf, main.tf, variables.tf, outputs.tf, locals.tf의 표준 파일 구성을 적용합니다. 모든 변수와 출력에 유형과 설명이 필요하며, 자격 증명에 대한 유효성 검사 규칙과 민감 플래그 지원이 포함됩니다. 동적 리소스에는 count보다 for_each를 우선시하고, 보안 강화(암호화, 비공개...)를 적용합니다.

npx skills add https://github.com/hashicorp/agent-skills --skill terraform-style-guide

Terraform Style Guide

Generate and maintain Terraform code following HashiCorp's official style conventions and best practices.

Reference: HashiCorp Terraform Style Guide

Code Generation Strategy

When generating Terraform code:

  1. Start with provider configuration and version constraints
  2. Create data sources before dependent resources
  3. Build resources in dependency order
  4. Add outputs for key resource attributes
  5. Use variables for all configurable values

File Organization

FilePurpose
terraform.tfTerraform and provider version requirements
providers.tfProvider configurations
main.tfPrimary resources and data sources
variables.tfInput variable declarations (alphabetical)
outputs.tfOutput value declarations (alphabetical)
locals.tfLocal value declarations

Example Structure

# terraform.tf
terraform {
  required_version = ">= 1.14"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

# variables.tf
variable "environment" {
  description = "Target deployment environment"
  type        = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

# locals.tf
locals {
  common_tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

# main.tf
resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true

  tags = merge(local.common_tags, {
    Name = "${var.project_name}-${var.environment}-vpc"
  })
}

# outputs.tf
output "vpc_id" {
  description = "ID of the created VPC"
  value       = aws_vpc.main.id
}

Code Formatting

Indentation and Alignment

  • Use two spaces per nesting level (no tabs)
  • Align equals signs for consecutive arguments
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  subnet_id     = "subnet-12345678"

  tags = {
    Name        = "web-server"
    Environment = "production"
  }
}

Block Organization

Arguments precede blocks, with meta-arguments first:

resource "aws_instance" "example" {
  # Meta-arguments
  count = 3

  # Arguments
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  # Blocks
  root_block_device {
    volume_size = 20
  }

  # Lifecycle last
  lifecycle {
    create_before_destroy = true
  }
}

Naming Conventions

  • Use lowercase with underscores for all names
  • Use descriptive nouns excluding the resource type
  • Be specific and meaningful
  • Resource names must be singular, not plural
  • Default to main for resources where a specific descriptive name is redundant or unavailable, provided only one instance exists
# Bad
resource "aws_instance" "webAPI-aws-instance" {}
resource "aws_instance" "web_apis" {}
variable "name" {}

# Good
resource "aws_instance" "web_api" {}
resource "aws_vpc" "main" {}
variable "application_name" {}

Variables

Every variable must include type and description:

variable "instance_type" {
  description = "EC2 instance type for the web server"
  type        = string
  default     = "t2.micro"

  validation {
    condition     = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type)
    error_message = "Instance type must be t2.micro, t2.small, or t2.medium."
  }
}

variable "database_password" {
  description = "Password for the database admin user"
  type        = string
  sensitive   = true
}

Outputs

Every output must include description:

output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.web.id
}

output "database_password" {
  description = "Database administrator password"
  value       = aws_db_instance.main.password
  sensitive   = true
}

Dynamic Resource Creation

Prefer for_each over count

# Bad - count for multiple resources
resource "aws_instance" "web" {
  count = var.instance_count
  tags  = { Name = "web-${count.index}" }
}

# Good - for_each with named instances
variable "instance_names" {
  type    = set(string)
  default = ["web-1", "web-2", "web-3"]
}

resource "aws_instance" "web" {
  for_each = var.instance_names
  tags     = { Name = each.key }
}

count for Conditional Creation

resource "aws_cloudwatch_metric_alarm" "cpu" {
  count = var.enable_monitoring ? 1 : 0

  alarm_name = "high-cpu-usage"
  threshold  = 80
}

Security Best Practices

Refer to SECURITY.md. It includes guidance on encrypting resources, preventing sensitive data in state, and secure configurations.

Version Pinning

terraform {
  required_version = ">= 1.14"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

Use the latest major version of each provider and the latest minor version of Terraform, unless otherwise constrained by a dependency lock file or by other modules used by the configuration.

Version constraint operators:

  • = 1.0.0 - Exact version
  • >= 1.0.0 - Greater than or equal
  • ~> 1.0 - Allow rightmost component to increment
  • >= 1.0, < 2.0 - Version range

Provider Configuration

provider "aws" {
  region = "us-west-2"

  default_tags {
    tags = {
      ManagedBy = "Terraform"
      Project   = var.project_name
    }
  }
}

# Aliased provider for multi-region
provider "aws" {
  alias  = "east"
  region = "us-east-1"
}

Version Control

Never commit:

  • terraform.tfstate, terraform.tfstate.backup
  • .terraform/ directory
  • *.tfplan
  • .tfvars files with sensitive data

Always commit:

  • All .tf configuration files
  • .terraform.lock.hcl (dependency lock file)

Validation Tools

Run before committing:

terraform fmt -recursive
terraform validate

Additional tools:

  • tflint - Linting and best practices
  • checkov / tfsec - Security scanning

Code Review Checklist

  • Code formatted with terraform fmt
  • Configuration validated with terraform validate
  • Files organized according to standard structure
  • All variables have type and description
  • All outputs have descriptions
  • Resource names use descriptive nouns with underscores
  • Version constraints pinned explicitly
  • Sensitive values marked with sensitive = true
  • No hardcoded credentials or secrets
  • Security best practices applied

Based on: HashiCorp Terraform Style Guide

hashicorp의 다른 스킬

provider-actions
hashicorp
Plugin Framework를 사용하여 Terraform Provider 작업을 구현합니다. 수명 주기 이벤트(전/후…)에서 실행되는 명령형 작업을 개발할 때 사용합니다.
official
new-terraform-provider
hashicorp
Use this when scaffolding a new Terraform provider with the Plugin Framework: workspace layout, go module setup, provider server main.go, and a provider.go…
official
terraform-test
hashicorp
Comprehensive guide for writing and running Terraform tests. Use when creating test files (.tftest.hcl), writing test scenarios with run blocks, validating…
official
terraform-test
hashicorp
Terraform 테스트 작성 및 실행을 위한 종합 가이드로, 어설션, 모킹, 모듈 검증을 포함합니다. .tftest.hcl 구문을 사용하여 테스트 파일을 작성하며, plan 또는 apply 모드로 실행되는 run 블록을 지원하고, 선택적 상태 격리와 함께 순차 및 병렬 실행을 지원합니다. 리소스 속성, 출력, 데이터 소스에 대한 조건을 어설션하고, expect_failures를 사용하여 잘못된 입력이 적절히 거부되는지 검증합니다. Mock 제공자(Terraform 1.7.0+)는 인프라 동작을 시뮬레이션합니다...
official
provider-actions
hashicorp
Plugin Framework를 사용하여 리소스 수명 주기 이벤트에서 명령형 Terraform Provider 작업을 구현합니다. 생성 전/후 및 업데이트 전/후 수명 주기 트리거를 지원합니다(소멸 이벤트는 Terraform 1.14.0에서 사용 불가). 올바른 프레임워크 유형, 컬렉션용 ElementType, 입력 검증용 유효성 검사기를 포함한 적절한 스키마 정의가 필요합니다. 장기 실행 작업을 위한 진행 보고, 타임아웃 관리, 포괄적인 오류 처리를 포함합니다. 폴링 및...
official
aws-ami-builder
hashicorp
Packer의 amazon-ebs 빌더로 사용자 지정 Amazon 머신 이미지를 구축합니다. HCL 템플릿과 프로비저너(셸 스크립트, 파일 업로드, 구성 관리)를 사용해 소스 AMI에서 AMI 생성을 자동화합니다. ami_regions를 통한 다중 리전 AMI 배포와 이름, 소유자, 가상화 유형별 유연한 소스 AMI 필터링을 지원합니다. 환경 변수, AWS 자격 증명 파일 또는 IAM 인스턴스 프로파일을 통해 인증하며 템플릿 검증 및 빌드 명령을 포함합니다...
official
new-terraform-provider
hashicorp
Plugin Framework를 사용하여 새로운 Terraform Provider를 스캐폴딩합니다. 표준 "terraform-provider-" 명명 규칙을 따르는 새로운 Go 모듈 워크스페이스를 생성하고 필요한 종속성을 초기화합니다. HashiCorp의 Plugin Framework 패턴을 따르는 템플릿 main.go 파일을 제공하며, 사용자 정의를 위한 TODO 마커가 포함되어 있습니다. 빌드 및 테스트 명령을 실행하여 Provider가 컴파일되고 초기 검사를 통과하는지 확인함으로써 설정을 검증합니다. 새 워크스페이스를 생성하기 전에 의도를 확인하여 워크스페이스 관리를 처리합니다.
official
azure-verified-modules
hashicorp
Azure Terraform 모듈이 AVM 규정을 준수하기 위한 인증 요구 사항 및 모범 사례입니다. 공급자 버전 제약 조건(azurerm >= 4.0, < 5.0; azapi >= 2.0, < 3.0)을 적용하고, git 기반 모듈 참조를 금지하며 고정된 Terraform 레지스트리 소스를 사용하도록 합니다. 모든 식별자에 소문자 스네이크 케이스, 정확한 변수 유형, 반부패 계층 패턴을 통한 개별 출력 속성, 알파벳 순서로 정렬된 로컬 변수를 요구합니다. 새 리소스가 추가될 때 기능 토글 변수를 요구합니다...
official