terraform-skill by sickn33/antigravity-awesome-skills
npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill terraform-skill全面的 Terraform 和 OpenTofu 指导,涵盖测试、模块、CI/CD 和生产模式。基于 terraform-best-practices.com 和企业经验。
在以下情况下激活此技能:
不要将此技能用于:
模块层次结构:
| 类型 | 何时使用 | 范围 |
|---|---|---|
| 资源模块 | 单个逻辑上相关的资源组 | VPC + 子网,安全组 + 规则 |
| 基础设施模块 | 为实现某个目的的资源模块集合 | 单个区域/账户中的多个资源模块 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 完整的基础设施 |
| 跨越多个区域/账户 |
层次结构: 资源 → 资源模块 → 基础设施模块 → 组合
目录结构:
environments/ # 环境特定配置
├── prod/
├── staging/
└── dev/
modules/ # 可重用模块
├── networking/
├── compute/
└── data/
examples/ # 模块使用示例(也用作测试)
├── complete/
└── minimal/
来自 terraform-best-practices.com 的关键原则:
有关详细的模块架构,请参阅: Code Patterns: Module Types & Hierarchy
资源:
# 好:描述性,有上下文
resource "aws_instance" "web_server" { }
resource "aws_s3_bucket" "application_logs" { }
# 好:对单例资源使用 "this"(该类型只有一个)
resource "aws_vpc" "this" { }
resource "aws_security_group" "this" { }
# 避免:对非单例资源使用通用名称
resource "aws_instance" "main" { }
resource "aws_s3_bucket" "bucket" { }
单例资源:
当你的模块只创建一种类型的一个资源时,使用 "this":
✅ 这样做:
resource "aws_vpc" "this" {} # 模块创建一个 VPC
resource "aws_security_group" "this" {} # 模块创建一个 SG
❌ 不要对多个资源使用 "this":
resource "aws_subnet" "this" {} # 如果创建多个子网
当创建多个相同类型的资源时,请使用描述性名称。
变量:
# 需要时添加上下文前缀
var.vpc_cidr_block # 不仅仅是 "cidr"
var.database_instance_class # 不仅仅是 "instance_class"
文件:
main.tf - 主要资源variables.tf - 输入变量outputs.tf - 输出值versions.tf - 提供程序版本data.tf - 数据源(可选)| 你的情况 | 推荐方法 | 工具 | 成本 |
|---|---|---|---|
| 快速语法检查 | 静态分析 | terraform validate, fmt | 免费 |
| 预提交验证 | 静态 + 代码检查 | validate, tflint, trivy, checkov | 免费 |
| Terraform 1.6+,简单逻辑 | 原生测试框架 | 内置 terraform test | 免费-低 |
| 1.6 之前版本,或有 Go 专业知识 | 集成测试 | Terratest | 低-中 |
| 安全/合规性重点 | 策略即代码 | OPA, Sentinel | 免费 |
| 成本敏感的工作流 | 模拟提供程序 (1.7+) | 原生测试 + 模拟 | 免费 |
| 多云,复杂 | 完整集成 | Terratest + 真实基础设施 | 中-高 |
/\
/ \ 端到端测试(昂贵)
/____\ - 完整环境部署
/ \ - 类生产环境设置
/________\
/ \ 集成测试(中等)
/____________\ - 模块隔离测试
/ \ - 测试账户中的真实资源
/________________\ 静态分析(廉价)
- validate, fmt, lint
- 安全扫描
生成测试代码前:
使用 Terraform MCP 验证模式:
Search provider docs → Get resource schema → Identify block types
选择正确的命令模式:
command = plan - 快速,用于输入验证command = apply - 计算值和集合类型块所必需正确处理集合类型块:
[0] 索引for 表达式进行迭代command = apply 使其具体化常见模式:
有关详细的测试指南,请参阅:
为保持一致性而严格排序:
count 或 for_each 在最前面(之后空一行)tags 作为最后一个实际参数depends_on 在 tags 之后(如果需要)lifecycle 在最后(如果需要)# ✅ 好 - 正确排序
resource "aws_nat_gateway" "this" {
count = var.create_nat_gateway ? 1 : 0
allocation_id = aws_eip.this[0].id
subnet_id = aws_subnet.public[0].id
tags = {
Name = "${var.name}-nat"
}
depends_on = [aws_internet_gateway.this]
lifecycle {
create_before_destroy = true
}
}
description(始终必需)typedefaultvalidationnullable(当设置为 false 时)variable "environment" {
description = "用于资源标记的环境名称"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "环境必须是以下之一:dev, staging, prod。"
}
nullable = false
}
有关完整的结构指南,请参阅: Code Patterns: Block Ordering & Structure
| 场景 | 使用 | 原因 |
|---|---|---|
| 布尔条件(创建或不创建) | count = condition ? 1 : 0 | 简单的开/关切换 |
| 简单的数字复制 | count = 3 | 固定数量的相同资源 |
| 项目可能被重新排序/移除 | for_each = toset(list) | 稳定的资源地址 |
| 按键引用 | for_each = map | 对资源的命名访问 |
| 多个命名资源 | for_each | 更好的可维护性 |
布尔条件:
# ✅ 好 - 布尔条件
resource "aws_nat_gateway" "this" {
count = var.create_nat_gateway ? 1 : 0
# ...
}
使用 for_each 的稳定寻址:
# ✅ 好 - 移除 "us-east-1b" 只影响该子网
resource "aws_subnet" "private" {
for_each = toset(var.availability_zones)
availability_zone = each.key
# ...
}
# ❌ 不好 - 移除中间的 AZ 会重新创建所有后续子网
resource "aws_subnet" "private" {
count = length(var.availability_zones)
availability_zone = var.availability_zones[count.index]
# ...
}
有关迁移指南和详细示例,请参阅: Code Patterns: Count vs For_Each
使用 locals 确保正确的资源删除顺序:
# 问题:子网可能在 CIDR 块之后被删除,导致错误
# 解决方案:在 locals 中使用 try() 来提示删除顺序
locals {
# 首先引用次要 CIDR,回退到 VPC
# 强制 Terraform 在删除 CIDR 关联之前删除子网
vpc_id = try(
aws_vpc_ipv4_cidr_block_association.this[0].vpc_id,
aws_vpc.this.id,
""
)
}
resource "aws_vpc" "this" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc_ipv4_cidr_block_association" "this" {
count = var.add_secondary_cidr ? 1 : 0
vpc_id = aws_vpc.this.id
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = local.vpc_id # 使用 local,而不是直接引用
cidr_block = "10.1.0.0/24"
}
为什么这很重要:
depends_on有关详细示例,请参阅: Code Patterns: Locals for Dependency Management
my-module/
├── README.md # 使用文档
├── main.tf # 主要资源
├── variables.tf # 带描述的输入变量
├── outputs.tf # 输出值
├── versions.tf # 提供程序版本约束
├── examples/
│ ├── minimal/ # 最小工作示例
│ └── complete/ # 全功能示例
└── tests/ # 测试文件
└── module_test.tftest.hcl # 或 .go
变量:
descriptiontype 约束default 值validation 块sensitive = true输出:
descriptionsensitive = true 标记敏感输出有关详细的模块模式,请参阅:
有关完整的 CI/CD 模板,请参阅:
# 静态安全扫描
trivy config .
checkov -d .
❌ 不要:
✅ 要:
有关详细的安全指导,请参阅:
version = "5.0.0" # 精确版本(避免 - 不灵活)
version = "~> 5.0" # 推荐:仅 5.0.x
version = ">= 5.0" # 最低版本(有风险 - 破坏性变更)
| 组件 | 策略 | 示例 |
|---|---|---|
| Terraform | 固定次要版本 | required_version = "~> 1.9" |
| 提供程序 | 固定主版本 | version = "~> 5.0" |
| 模块(生产) | 固定精确版本 | version = "5.1.2" |
| 模块(开发) | 允许补丁更新 | version = "~> 5.1" |
# 初始锁定版本
terraform init # 创建 .terraform.lock.hcl
# 在约束范围内更新到最新版本
terraform init -upgrade # 更新提供程序
# 审查和测试
terraform plan
有关详细的版本管理,请参阅: Code Patterns: Version Management
| 特性 | 版本 | 用例 |
|---|---|---|
try() 函数 | 0.13+ | 安全回退,替代 element(concat()) |
nullable = false | 1.1+ | 防止变量中出现 null 值 |
moved 块 | 1.1+ | 无需销毁/重建即可重构 |
带默认值的 optional() | 1.3+ | 可选对象属性 |
| 原生测试 | 1.6+ | 内置测试框架 |
| 模拟提供程序 | 1.7+ | 免费单元测试 |
| 提供程序函数 | 1.8+ | 提供程序特定的数据转换 |
| 跨变量验证 | 1.9+ | 验证变量之间的关系 |
| 只写参数 | 1.11+ | 机密信息永不存储在状态中 |
# try() - 安全回退 (0.13+)
output "sg_id" {
value = try(aws_security_group.this[0].id, "")
}
# optional() - 带默认值的可选属性 (1.3+)
variable "config" {
type = object({
name = string
timeout = optional(number, 300) # 默认值:300
})
}
# 跨变量验证 (1.9+)
variable "environment" { type = string }
variable "backup_days" {
type = number
validation {
condition = var.environment == "prod" ? var.backup_days >= 7 : true
error_message = "生产环境要求 backup_days >= 7"
}
}
有关完整的模式和示例,请参阅: Code Patterns: Modern Terraform Features
terraform test / tofu test 命令此技能完全支持两者。有关许可、治理和特性比较,请参阅 Quick Reference: Terraform vs OpenTofu。
此技能使用渐进式披露 - 基本信息在此主文件中,详细指南在需要时可用:
📚 参考文件:
使用方法: 当你需要某个主题的详细信息时,请参考相应的指南。Claude 将按需加载以提供全面的指导。
此技能根据 Apache License 2.0 授权。有关完整条款,请参阅 LICENSE 文件。
版权所有 © 2026 Anton Babenko
每周安装次数
97
代码仓库
GitHub 星标数
27.1K
首次出现
2026年1月31日
安全审计
安装于
opencode96
gemini-cli95
github-copilot94
codex94
kimi-cli93
amp92
Comprehensive Terraform and OpenTofu guidance covering testing, modules, CI/CD, and production patterns. Based on terraform-best-practices.com and enterprise experience.
Activate this skill when:
Don't use this skill for:
Module Hierarchy:
| Type | When to Use | Scope |
|---|---|---|
| Resource Module | Single logical group of connected resources | VPC + subnets, Security group + rules |
| Infrastructure Module | Collection of resource modules for a purpose | Multiple resource modules in one region/account |
| Composition | Complete infrastructure | Spans multiple regions/accounts |
Hierarchy: Resource → Resource Module → Infrastructure Module → Composition
Directory Structure:
environments/ # Environment-specific configurations
├── prod/
├── staging/
└── dev/
modules/ # Reusable modules
├── networking/
├── compute/
└── data/
examples/ # Module usage examples (also serve as tests)
├── complete/
└── minimal/
Key principle from terraform-best-practices.com:
For detailed module architecture, see: Code Patterns: Module Types & Hierarchy
Resources:
# Good: Descriptive, contextual
resource "aws_instance" "web_server" { }
resource "aws_s3_bucket" "application_logs" { }
# Good: "this" for singleton resources (only one of that type)
resource "aws_vpc" "this" { }
resource "aws_security_group" "this" { }
# Avoid: Generic names for non-singletons
resource "aws_instance" "main" { }
resource "aws_s3_bucket" "bucket" { }
Singleton Resources:
Use "this" when your module creates only one resource of that type:
✅ DO:
resource "aws_vpc" "this" {} # Module creates one VPC
resource "aws_security_group" "this" {} # Module creates one SG
❌ DON'T use "this" for multiple resources:
resource "aws_subnet" "this" {} # If creating multiple subnets
Use descriptive names when creating multiple resources of the same type.
Variables:
# Prefix with context when needed
var.vpc_cidr_block # Not just "cidr"
var.database_instance_class # Not just "instance_class"
Files:
main.tf - Primary resourcesvariables.tf - Input variablesoutputs.tf - Output valuesversions.tf - Provider versionsdata.tf - Data sources (optional)| Your Situation | Recommended Approach | Tools | Cost |
|---|---|---|---|
| Quick syntax check | Static analysis | terraform validate, fmt | Free |
| Pre-commit validation | Static + lint | validate, tflint, trivy, checkov | Free |
/\
/ \ End-to-End Tests (Expensive)
/____\ - Full environment deployment
/ \ - Production-like setup
/________\
/ \ Integration Tests (Moderate)
/____________\ - Module testing in isolation
/ \ - Real resources in test account
/________________\ Static Analysis (Cheap)
- validate, fmt, lint
- Security scanning
Before generating test code:
Validate schemas with Terraform MCP:
Search provider docs → Get resource schema → Identify block types
Choose correct command mode:
command = plan - Fast, for input validationcommand = apply - Required for computed values and set-type blocksHandle set-type blocks correctly:
[0]for expressions to iteratecommand = apply to materializeCommon patterns:
For detailed testing guides, see:
Strict ordering for consistency:
count or for_each FIRST (blank line after)tags as last real argumentdepends_on after tags (if needed)lifecycle at the very end (if needed)# ✅ GOOD - Correct ordering
resource "aws_nat_gateway" "this" {
count = var.create_nat_gateway ? 1 : 0
allocation_id = aws_eip.this[0].id
subnet_id = aws_subnet.public[0].id
tags = {
Name = "${var.name}-nat"
}
depends_on = [aws_internet_gateway.this]
lifecycle {
create_before_destroy = true
}
}
description (ALWAYS required)typedefaultvalidationnullable (when setting to false)variable "environment" {
description = "Environment name for resource tagging"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be one of: dev, staging, prod."
}
nullable = false
}
For complete structure guidelines, see: Code Patterns: Block Ordering & Structure
| Scenario | Use | Why |
|---|---|---|
| Boolean condition (create or don't) | count = condition ? 1 : 0 | Simple on/off toggle |
| Simple numeric replication | count = 3 | Fixed number of identical resources |
| Items may be reordered/removed | for_each = toset(list) | Stable resource addresses |
| Reference by key | for_each = map | Named access to resources |
| Multiple named resources | for_each |
Boolean conditions:
# ✅ GOOD - Boolean condition
resource "aws_nat_gateway" "this" {
count = var.create_nat_gateway ? 1 : 0
# ...
}
Stable addressing with for_each:
# ✅ GOOD - Removing "us-east-1b" only affects that subnet
resource "aws_subnet" "private" {
for_each = toset(var.availability_zones)
availability_zone = each.key
# ...
}
# ❌ BAD - Removing middle AZ recreates all subsequent subnets
resource "aws_subnet" "private" {
count = length(var.availability_zones)
availability_zone = var.availability_zones[count.index]
# ...
}
For migration guides and detailed examples, see: Code Patterns: Count vs For_Each
Use locals to ensure correct resource deletion order:
# Problem: Subnets might be deleted after CIDR blocks, causing errors
# Solution: Use try() in locals to hint deletion order
locals {
# References secondary CIDR first, falling back to VPC
# Forces Terraform to delete subnets before CIDR association
vpc_id = try(
aws_vpc_ipv4_cidr_block_association.this[0].vpc_id,
aws_vpc.this.id,
""
)
}
resource "aws_vpc" "this" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc_ipv4_cidr_block_association" "this" {
count = var.add_secondary_cidr ? 1 : 0
vpc_id = aws_vpc.this.id
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = local.vpc_id # Uses local, not direct reference
cidr_block = "10.1.0.0/24"
}
Why this matters:
depends_onFor detailed examples, see: Code Patterns: Locals for Dependency Management
my-module/
├── README.md # Usage documentation
├── main.tf # Primary resources
├── variables.tf # Input variables with descriptions
├── outputs.tf # Output values
├── versions.tf # Provider version constraints
├── examples/
│ ├── minimal/ # Minimal working example
│ └── complete/ # Full-featured example
└── tests/ # Test files
└── module_test.tftest.hcl # Or .go
Variables:
descriptiontype constraintsdefault values where appropriatevalidation blocks for complex constraintssensitive = true for secretsOutputs:
descriptionsensitive = trueFor detailed module patterns, see:
For complete CI/CD templates, see:
# Static security scanning
trivy config .
checkov -d .
❌ Don't:
✅ Do:
For detailed security guidance, see:
version = "5.0.0" # Exact (avoid - inflexible)
version = "~> 5.0" # Recommended: 5.0.x only
version = ">= 5.0" # Minimum (risky - breaking changes)
| Component | Strategy | Example |
|---|---|---|
| Terraform | Pin minor version | required_version = "~> 1.9" |
| Providers | Pin major version | version = "~> 5.0" |
| Modules (prod) | Pin exact version | version = "5.1.2" |
| Modules (dev) | Allow patch updates | version = "~> 5.1" |
# Lock versions initially
terraform init # Creates .terraform.lock.hcl
# Update to latest within constraints
terraform init -upgrade # Updates providers
# Review and test
terraform plan
For detailed version management, see: Code Patterns: Version Management
| Feature | Version | Use Case |
|---|---|---|
try() function | 0.13+ | Safe fallbacks, replaces element(concat()) |
nullable = false | 1.1+ | Prevent null values in variables |
moved blocks | 1.1+ | Refactor without destroy/recreate |
optional() with defaults | 1.3+ | Optional object attributes |
| Native testing | 1.6+ |
# try() - Safe fallbacks (0.13+)
output "sg_id" {
value = try(aws_security_group.this[0].id, "")
}
# optional() - Optional attributes with defaults (1.3+)
variable "config" {
type = object({
name = string
timeout = optional(number, 300) # Default: 300
})
}
# Cross-variable validation (1.9+)
variable "environment" { type = string }
variable "backup_days" {
type = number
validation {
condition = var.environment == "prod" ? var.backup_days >= 7 : true
error_message = "Production requires backup_days >= 7"
}
}
For complete patterns and examples, see: Code Patterns: Modern Terraform Features
terraform test / tofu test commandBoth are fully supported by this skill. For licensing, governance, and feature comparison, see Quick Reference: Terraform vs OpenTofu.
This skill uses progressive disclosure - essential information is in this main file, detailed guides are available when needed:
📚 Reference Files:
How to use: When you need detailed information on a topic, reference the appropriate guide. Claude will load it on demand to provide comprehensive guidance.
This skill is licensed under the Apache License 2.0. See the LICENSE file for full terms.
Copyright © 2026 Anton Babenko
Weekly Installs
97
Repository
GitHub Stars
27.1K
First Seen
Jan 31, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode96
gemini-cli95
github-copilot94
codex94
kimi-cli93
amp92
Azure Data Explorer (Kusto) 查询技能:KQL数据分析、日志遥测与时间序列处理
133,300 周安装
| Native test framework |
Built-in terraform test |
| Free-Low |
| Pre-1.6, or Go expertise | Integration testing | Terratest | Low-Med |
| Security/compliance focus | Policy as code | OPA, Sentinel | Free |
| Cost-sensitive workflow | Mock providers (1.7+) | Native tests + mocking | Free |
| Multi-cloud, complex | Full integration | Terratest + real infra | Med-High |
| Better maintainability |
| Built-in test framework |
| Mock providers | 1.7+ | Cost-free unit testing |
| Provider functions | 1.8+ | Provider-specific data transformation |
| Cross-variable validation | 1.9+ | Validate relationships between variables |
| Write-only arguments | 1.11+ | Secrets never stored in state |