mcpField
T
terraform-best-practices

terraform-best-practices

github.com/c0x12c云与 DevOps110105 次安装19 周前更新
代码仓库

关于 terraform-best-practices

面向编写 Terraform 配置的开发者,提供文件组织、命名、模块、状态管理、安全与 CI/CD 的实践参考。重点是可复用模块、版本固定和避免常见配置风险。

主要功能

  1. 01Terraform 文件组织规范
  2. 02资源与变量命名约定
  3. 03可复用模块使用模式
  4. 04S3 状态与远程状态参考
  5. 05安全检查与反模式清单
  6. 06CI/CD 工作流规则

适用场景

  1. 01规划新 Terraform 项目的目录结构
  2. 02审查模块与 Provider 的配置
  3. 03设置状态存储和跨栈引用
  4. 04制定基础设施代码的安全规范

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/c0x12c/ai-toolkit --skill terraform-best-practices

安装后在 Claude Code 中输入/terraform-best-practices确认已加载。

详细介绍

Terraform 最佳实践 — 快速参考

文件组织

terraform/
  live/                    # Orchestration — providers, backend, module calls
    terraform.tf           # backend + provider (ONLY place for providers)
    variables.tf           # all input variables
    locals.tf              # computed values, remote state refs
    outputs.tf             # exported values
    {resource-group}.tf    # module invocations grouped by concern
  modules/{name}/          # Reusable — no providers, no hardcoded values
    main.tf                # locals, data sources
    variables.tf           # inputs with descriptions + types
    outputs.tf             # consumed values only
    versions.tf            # required_providers
    {resource}.tf          # one file per resource type
  envs/{env}/              # Per-environment config
    state.config           # backend partial config
    terraform.tfvars       # non-sensitive values
    secrets.tfvars         # sensitive values (gitignored)

命名

对象约定示例
资源前缀{project}-{service}-{env}acme-payments-prod
变量snake_caseinstance_class
局部值snake_casename_prefix
输出snake_caserepository_url
资源this(主要资源)或描述性名称aws_db_instance.this
安全组name_prefix(而非 name)"${local.name_prefix}-app-"
文件{resource-type}.tfrds.tf、sg.tf、ecr.tf
模块kebab-case 目录modules/ecs-service/
标签PascalCase 键Project、Environment、ManagedBy

模块模式

使用 c0x12c Terraform Registry 中的模块。 每个模块源都遵循 c0x12c/{name}/aws 格式,支持的模块和版本请参阅注册表。

# Calling a registry module — always version-pin
module "database" {
  source  = "c0x12c/rds/aws"
  version = "~> 0.6.6"

  name       = "${local.name_prefix}-db"
  vpc_id     = local.vpc_id
  subnet_ids = local.private_subnet_ids
  tags       = local.common_tags
}

# Inside a module — no provider, explicit interface
# versions.tf
terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0"
    }
  }
}

# variables.tf — every var has description + type
variable "name" {
  description = "Resource name prefix"
  type        = string
}

# outputs.tf — only what consumers need
output "endpoint" {
  description = "Connection endpoint"
  value       = aws_db_instance.this.endpoint
}

状态管理

# Backend config — S3 + DynamoDB locking
terraform {
  backend "s3" {}
}

# envs/dev/state.config
bucket         = "{project}-terraform-state"
key            = "{service}/dev/terraform.tfstate"
region         = "us-east-1"
dynamodb_table = "{project}-terraform-locks"
encrypt        = true

# Init with partial config
# terraform init -backend-config=../envs/dev/state.config
# Remote state for cross-stack references
data "terraform_remote_state" "infra" {
  backend = "s3"
  config = {
    bucket = "{project}-terraform-state"
    key    = "infra/terraform.tfstate"
    region = var.region
  }
}

locals {
  vpc_id = data.terraform_remote_state.infra.outputs.vpc_id
}

安全检查清单

# Sensitive variables
variable "db_password" {
  type      = string
  sensitive = true
}

# S3 — block public, encrypt, version
module "s3" {
  versioning              = true
  server_side_encryption  = { sse_algorithm = "aws:kms" }
  block_public_access     = {
    block_public_acls       = true
    block_public_policy     = true
    ignore_public_acls      = true
    restrict_public_buckets = true
  }
}

# RDS — encrypt, private subnet, protect
resource "aws_db_instance" "this" {
  storage_encrypted   = true
  deletion_protection = var.env == "prod"
  publicly_accessible = false  # ALWAYS false
}

# Security groups — source SG, not CIDR
resource "aws_security_group_rule" "app_to_db" {
  source_security_group_id = aws_security_group.app.id  # not cidr_blocks
  from_port                = 5432
  to_port                  = 5432
}

# Default tags at provider level
provider "aws" {
  default_tags {
    tags = {
      Project     = var.project
      Service     = var.service
      Environment = var.env
      ManagedBy   = "terraform"
    }
  }
}

常见反模式

# WRONG — provider in module
# modules/rds/main.tf
provider "aws" { region = "us-east-1" }  # NEVER in a module

# WRONG — no version pin
module "rds" {
  source = "git::https://github.com/{project}/terraform-modules.git//rds"
  # missing ?ref=vX.Y.Z
}

# WRONG — hardcoded values
resource "aws_s3_bucket" "assets" {
  bucket = "acme-prod-assets"  # use ${local.name_prefix}-assets
}

# WRONG — secrets in code
resource "aws_db_instance" "main" {
  password = "hunter2"  # use var.db_password (sensitive)
}

# WRONG — wildcard IAM
resource "aws_iam_policy" "app" {
  policy = jsonencode({
    Statement = [{ Action = "*", Resource = "*", Effect = "Allow" }]
  })
}

# WRONG — public database
resource "aws_db_instance" "main" {
  publicly_accessible = true  # NEVER for databases
}

# WRONG — no state locking
terraform {
  backend "s3" {
    # missing dynamodb_table for locking
  }
}

# WRONG — all resources in one file
# main.tf with 500+ lines of mixed RDS, S3, SQS, IAM...
# Split into rds.tf, s3.tf, sqs.tf, iam.tf

CI/CD 模式

# Standard workflow
# PR: fmt check → validate → plan (comment on PR)
# Merge to main: init → plan → apply

# Key rules:
# - Never auto-apply on PR
# - Always post plan output as PR comment
# - Lock state during apply (DynamoDB)
# - Inject secrets via CI environment variables
# - Pin Terraform version in CI to match team

应避免的做法

  • 在模块中定义 Provider 块
  • 不固定模块版本
  • 硬编码名称、ID 或账户编号
  • 在 .tf 文件或已提交的 .tfvars 中存放密钥
  • 使用通配符 IAM 策略(* 用于 *)
  • 使用公开数据库或缓存
  • 未对存储启用加密
  • 使用单体文件(按资源类型拆分)
  • 在自动化中使用 terraform import(改用 import 块)
  • 变量和输出缺少 description
  • 嵌套的局部值映射(保持扁平)
  • 对条件资源使用 count(改用包含集合的 for_each)

评论

支持 Markdown