terraform-patterns
Terraform インフラストラクチャコードのエージェントスキルおよび Claude Code、Codex、Gemini CLI、Cursor、OpenClaw 用プラグインです。モジュール設計パターン、ステート管理戦略、プロバイダー設定、セキュリティ強化、Sentinel/OPA によるポリシーアズコード、CI/CD の plan/apply ワークフローをカバーしています。ユーザーが Terraform インフラストラクチャの構築、管理、最適化に関するサポートを必要とする場合に使用できます。
description の原文を見る
Terraform infrastructure-as-code agent skill and plugin for Claude Code, Codex, Gemini CLI, Cursor, OpenClaw. Covers module design patterns, state management strategies, provider configuration, security hardening, policy-as-code with Sentinel/OPA, and CI/CD plan/apply workflows. Use when: user wa...
SKILL.md 本文
Terraform パターン
予測可能なインフラストラクチャ。安全な状態管理。構成可能なモジュール。ドリフトなし。
複雑に広がったHCLを適切に構造化された、安全で本番環境対応のインフラストラクチャコードに変換する、意見のあるTerraformワークフロー。モジュール設計、状態管理、プロバイダーパターン、セキュリティ強化、CI/CD統合をカバーします。
Terraformチュートリアルではなく、午前3時に破綻しないインフラストラクチャコードの書き方に関する具体的な意思決定の集合です。
スラッシュコマンド
| コマンド | 機能 |
|---|---|
/terraform:review | アンチパターン、セキュリティ問題、構造的な問題についてTerraformコードを分析します |
/terraform:module | 適切なインプット、アウトプット、構成を持つTerraformモジュールを設計またはリファクタリングします |
/terraform:security | セキュリティ脆弱性、シークレット露出、IAM設定ミスについてTerraformコードを監査します |
このスキルが起動するタイミング
ユーザーのこれらのパターンを認識します:
- 「このTerraformコードをレビューして」
- 「〜向けのTerraformモジュールを設計して」
- 「私のTerraform状態は…」
- 「リモート状態バックエンドをセットアップする」
- 「マルチリージョンTerraform構成」
- 「Terraformセキュリティレビュー」
- 「モジュール構造のベストプラクティス」
- 「Terraform CI/CDパイプライン」
.tfファイル、HCL、Terraformモジュール、状態管理、プロバイダー設定、Infrastructure-as-Codeに関連するあらゆるリクエスト
ユーザーが .tf ファイルを持っているか、Terraformでインフラストラクチャをプロビジョニングしたい場合 → このスキルが適用されます。
ワークフロー
/terraform:review — Terraformコードレビュー
-
現在の状態を分析
- 対象ディレクトリ内のすべての
.tfファイルを読み込む - モジュール構造を特定(フラット vs ネストされた)
- リソース、データソース、変数、アウトプットを数える
- 命名規則をチェックする
- 対象ディレクトリ内のすべての
-
レビューチェックリストを適用
モジュール構造 ├── 変数は説明と型制約を持つ ├── アウトプットはコンシューマーが必要なもののみ公開 ├── リソースは一貫した命名を使用: {プロバイダー}_{型}_{目的} ├── ローカルは計算値とDRY表現に使用 └── ハードコーディングされた値なし — すべてパラメータ化またはローカルに 状態とバックエンド ├── リモートバックエンドが構成済み(S3、GCS、Azure Blob、Terraform Cloud) ├── 状態ロックが有効(S3ではDynamoDB、その他はネイティブ) ├── 保存時の状態暗号化が有効 ├── 状態にシークレットが保存されていない(または状態アクセスが制限されている) └── 環境用のワークスペースまたはディレクトリ分離 プロバイダー ├── バージョン制約は悲観的演算子を使用: ~> 5.0 ├── terraform {} ブロックに必須プロバイダーブロック ├── マルチリージョンまたはマルチアカウント用プロバイダーエイリアス └── 子モジュールにプロバイダー設定なし セキュリティ ├── ハードコーディングされたシークレット、キー、パスワードなし ├── IAMは最小権限の原則に従う ├── ストレージ、データベース、シークレットの暗号化が有効 ├── セキュリティグループは過度に寛容でない(機密ポートへのインバウンド0.0.0.0/0なし) └── センシティブ変数は sensitive = true でマーク -
レポートを生成
python3 scripts/tf_module_analyzer.py ./terraform -
セキュリティスキャンを実行
python3 scripts/tf_security_scanner.py ./terraform
/terraform:module — モジュール設計
-
モジュールのスコープを特定
- 単一責任:1つのモジュール = 1つの論理グループ
- インプット(変数)、アウトプット、リソース境界を決定
- 決定:フラットモジュール(単一ディレクトリ)vs ネストされたもの(子モジュール呼び出し)
-
モジュール設計チェックリストを適用
構造 ├── main.tf — プライマリリソース ├── variables.tf — 説明と型を含むすべてのインプット変数 ├── outputs.tf — 説明を含むすべてのアウトプット ├── versions.tf — required_providers を含む terraform {} ブロック ├── locals.tf — 計算値と命名規則 ├── data.tf — データソース(あれば) └── README.md — 使用例と変数ドキュメント 変数 ├── すべての変数が必要:説明、型、検証(該当する場合) ├── センシティブ値をマーク:sensitive = true ├── オプション設定にはデフォルト値を提供 ├── オブジェクト型を使用して関連設定:variable "config" { type = object({...}) } └── 検証を使用: validation { condition = ... } アウトプット ├── ID、ARN、エンドポイント — コンシューマーが必要なもの ├── すべてのアウトプットに説明を含める ├── センシティブアウトプットをマーク:sensitive = true └── リソース全体をアウトプットしない — 特定の属性のみ 構成 ├── ルートモジュールが子モジュールを呼び出す ├── 子モジュールは他の子モジュールを呼び出さない ├── 値を明示的に渡す — 子モジュール内の隠れたデータソースルックアップなし ├── プロバイダー設定はルートモジュールのみ └── module "name" { source = "./modules/name" } を使用 -
モジュールスキャフォルドを生成
- ボイラープレート付きのファイル構造をアウトプット
- 変数検証ブロックを含める
- 必要に応じてライフサイクルルールを追加
/terraform:security — セキュリティ監査
-
コードレベルの監査
チェック 重大度 修正 .tfファイル内にハードコーディングされたシークレット重大 sensitive = true の変数またはVaultを使用 *アクション付きのIAMポリシー重大 特定のアクションとリソースにスコープ化 ポート22/3389の0.0.0.0/0付きセキュリティグループ 重大 既知のCIDRブロックに制限するか、SSM/要塞を使用 暗号化なしのS3バケット 高 server_side_encryption_configurationブロックを追加パブリックアクセス付きのS3バケット 高 aws_s3_bucket_public_access_blockを追加暗号化なしのRDS 高 storage_encrypted = trueを設定パブリックアクセス可能なRDS 高 publicly_accessible = falseを設定CloudTrailが有効でない 中 aws_cloudtrailリソースを追加ステートフルリソースに prevent_destroyがない中 lifecycle { prevent_destroy = true }を追加シークレット用に sensitive = trueがない変数中 シークレット変数に sensitive = trueを追加 -
状態セキュリティ監査
チェック 重大度 修正 ローカル状態ファイル 重大 暗号化付きリモートバックエンドに移行 暗号化なしのリモート状態 高 バックエンド上で暗号化を有効化(SSE-S3、KMS) 状態ロックなし 高 S3用DynamoDBを有効化、TF Cloud用はネイティブ すべてのチームメンバーがアクセス可能な状態 中 IAMポリシーまたはTF Cloudチームで制限 -
セキュリティレポートを生成
python3 scripts/tf_security_scanner.py ./terraform python3 scripts/tf_security_scanner.py ./terraform --output json
ツール
scripts/tf_module_analyzer.py
Terraformディレクトリ構造とモジュール品質を分析するCLIユーティリティ。
機能:
- リソースとデータソースのカウント
- 変数とアウトプットの分析(説明、型、検証の欠落)
- 命名規則チェック
- モジュール構成検出
- ファイル構造検証
- JSONとテキスト出力
使用方法:
# Terraformディレクトリを分析
python3 scripts/tf_module_analyzer.py ./terraform
# JSON出力
python3 scripts/tf_module_analyzer.py ./terraform --output json
# 特定のモジュールを分析
python3 scripts/tf_module_analyzer.py ./modules/vpc
scripts/tf_security_scanner.py
.tf ファイルで一般的なセキュリティ問題をスキャンするCLIユーティリティ。
機能:
- ハードコーディングされたシークレット検出(AWSキー、パスワード、トークン)
- 過度に寛容なIAMポリシー検出
- 開かれたセキュリティグループ検出(機密ポートの0.0.0.0/0)
- 暗号化なしチェック(S3、RDS、EBS)
- パブリックアクセス検出(S3、RDS、EC2)
- センシティブ変数監査
- JSONとテキスト出力
使用方法:
# Terraformディレクトリをスキャン
python3 scripts/tf_security_scanner.py ./terraform
# JSON出力
python3 scripts/tf_security_scanner.py ./terraform --output json
# ストリクトモード(警告を昇格)
python3 scripts/tf_security_scanner.py ./terraform --strict
モジュール設計パターン
パターン1:フラットモジュール(小〜中規模プロジェクト)
infrastructure/
├── main.tf # すべてのリソース
├── variables.tf # すべてのインプット
├── outputs.tf # すべてのアウトプット
├── versions.tf # プロバイダー要件
├── terraform.tfvars # 環境値(コミットされない)
└── backend.tf # リモート状態設定
最適用途:単一アプリケーション、20未満のリソース、1つのチームがすべてを所有。
パターン2:ネストされたモジュール(中〜大規模プロジェクト)
infrastructure/
├── environments/
│ ├── dev/
│ │ ├── main.tf # devパラメーターでモジュールを呼び出し
│ │ ├── backend.tf # dev状態バックエンド
│ │ └── terraform.tfvars
│ ├── staging/
│ │ └── ...
│ └── prod/
│ └── ...
├── modules/
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── compute/
│ │ └── ...
│ └── database/
│ └── ...
└── versions.tf
最適用途:複数環境、共有インフラストラクチャパターン、チーム協働。
パターン3:Terragruntを使用したモノレポ
infrastructure/
├── terragrunt.hcl # ルート設定
├── modules/ # 再利用可能なモジュール
│ ├── vpc/
│ ├── eks/
│ └── rds/
├── dev/
│ ├── terragrunt.hcl # dev上書き
│ ├── vpc/
│ │ └── terragrunt.hcl # モジュール呼び出し
│ └── eks/
│ └── terragrunt.hcl
└── prod/
├── terragrunt.hcl
└── ...
最適用途:大規模、多数の環境、DRY設定、チームレベルの分離。
プロバイダー設定パターン
バージョンピンニング
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 5.xを許可、6.0をブロック
}
random = {
source = "hashicorp/random"
version = "~> 3.5"
}
}
}
マルチリージョンとエイリアス
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "west"
region = "us-west-2"
}
resource "aws_s3_bucket" "primary" {
bucket = "my-app-primary"
}
resource "aws_s3_bucket" "replica" {
provider = aws.west
bucket = "my-app-replica"
}
仮定ロール付きマルチアカウント
provider "aws" {
alias = "production"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::PROD_ACCOUNT_ID:role/TerraformRole"
}
}
状態管理デシジョンツリー
単一開発者、小規模プロジェクト?
├── はい → ローカル状態(ただしすぐにリモートに移行)
└── いいえ
├── Terraform Cloud/Enterpriseを使用中?
│ └── はい → TF Cloudネイティブバックエンド(組み込みロック、暗号化、RBAC)
└── いいえ
├── AWS?
│ └── S3 + DynamoDB(暗号化、ロック、バージョニング)
├── GCP?
│ └── GCSバケット(ネイティブロック、暗号化)
├── Azure?
│ └── Azure Blob Storage(ネイティブロック、暗号化)
└── その他?
└── ConsulまたはPostgreSQLバックエンド
環境分離戦略:
├── 環境ごとに個別の状態ファイル(推奨)
│ ├── オプションA:個別ディレクトリ(dev/、staging/、prod/)
│ └── オプションB:Terraformワークスペース(より簡潔だが分離が少ない)
└── すべての環境用の単一状態ファイル(絶対にしないこと)
CI/CD統合パターン
GitHub Actions Plan/Apply
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
paths: ['terraform/**']
push:
branches: [main]
paths: ['terraform/**']
jobs:
plan:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform validate
- run: terraform plan -out=tfplan
- run: terraform show -json tfplan > plan.json
# Plan をPRコメントとしてポスト
apply:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform apply -auto-approve
ドリフト検出
# スケジュールでドリフトを検出
name: Drift Detection
on:
schedule:
- cron: '0 6 * * 1-5' # 平日午前6時
jobs:
detect:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: |
terraform plan -detailed-exitcode -out=drift.tfplan 2>&1 | tee drift.log
EXIT_CODE=$?
if [ $EXIT_CODE -eq 2 ]; then
echo "ドリフトが検出されました — drift.log を確認"
# アラートを送信(Slack、PagerDuty等)
fi
プロアクティブなトリガー
尋ねられなくても次のようなことにフラグを立てます:
- リモートバックエンドが構成されていない → ロックと暗号化を備えたS3/GCS/Azure Blobに移行。
- バージョン制約のないプロバイダー →
version = "~> X.0"を追加して、破壊的なアップグレードを防止。 - .tf ファイル内にハードコーディングされたシークレット →
sensitive = trueの変数を使用するか、Vault/SSMを統合。 "Action": "*"を持つIAMポリシー → 特定のアクションにスコープ化。本番環境でワイルドカードアクションなし。- SSH/RDPでセキュリティグループが0.0.0.0/0に開かれている → 要塞CIDRに制限するか、SSM Session Managerを使用。
- 状態ロックなし → S3バックエンド用DynamoDBテーブルを有効化するか、TF Cloudを使用。
- タグのないリソース → プロバイダーブロック内にdefault_tagsを追加。タグは費用追跡に必須。
- データベース/ストレージに
prevent_destroyがない → ライフサイクルブロックを追加して偶発的な削除を防止。
マルチクラウドプロバイダー設定
単一のルートモジュールがAWS、Azure、GCP全体で同時にプロビジョニングする必要がある場合。
プロバイダーエイリアスパターン
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
}
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
}
プロバイダー全体で共有変数
variable "environment" {
description = "すべてのプロバイダーで使用される環境名"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "dev、staging、または prodである必要があります。"
}
}
locals {
common_tags = {
environment = var.environment
managed_by = "terraform"
project = var.project_name
}
}
マルチクラウドを使用するタイミング
- はい:規制要件でプロバイダー全体でのデータレジデンシーが必須、または組織が複数のクラウドに既存のワークロードを持つ。
- いいえ:単なる「ベンダーロックインを回避する」は十分な正当性ではありません。マルチクラウドは運用複雑性を2倍にします。具体的なビジネス要件がない限り、単一クラウドを推奨。
OpenTofu互換性
OpenTofuはLinux Foundation傘下のMPL 2.0ライセンスで保守されるTerraformのオープンソースフォーク。
TerraformからOpenTofuへの移行
# 1. OpenTofuをインストール
brew install opentofu # macOS
snap install --classic tofu # Linux
# 2. バイナリを置き換え — 状態ファイルは互換性あり
tofu init # OpenTofuで再初期化
tofu plan # 同一のplan出力
tofu apply # 同じapplyワークフロー
ライセンス考慮事項
| Terraform(1.6以降) | OpenTofu | |
|---|---|---|
| ライセンス | BSL 1.1(ソース利用可能) | MPL 2.0(オープンソース) |
| 商用利用 | 競争製品に対して制限 | 無制限 |
| コミュニティガバナンス | HashiCorp | Linux Foundation |
機能パリティ
OpenTofuはTerraform 1.6.xの機能を追跡します。OpenTofu固有の主な追加機能:
- クライアント側の状態暗号化(
tofu init -encryption) - 初期変数/ローカル評価
- プロバイダー定義関数
OpenTofuを選択するタイミング
- サプライチェーンに完全なオープンソースライセンスが必要。
- Terraform Cloudなしでクライアント側の状態暗号化を希望。
- その他の場合は、どちらのツールでも機能します — HCL構文とプロバイダーエコシステムは同一。
Infracost統合
Infracostはリソースがプロビジョニングされる前にTerraformコードからクラウドコストを推定します。
PRワークフロー
# 現在のコードのコスト内訳を表示
infracost breakdown --path .
# 現在のブランチとmainの間のコスト差を比較
infracost diff --path . --compare-to infracost-base.json
GitHub Actions費用コメント
# .github/workflows/infracost.yml
name: Infracost
on: [pull_request]
jobs:
cost:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: infracost/actions/setup@v3
with:
api-key: ${{ secrets.INFRACOST_API_KEY }}
- run: infracost breakdown --path ./terraform --format json --out-file /tmp/infracost.json
- run: infracost comment github --path /tmp/infracost.json --repo $GITHUB_REPOSITORY --pull-request ${{ github.event.pull_request.number }} --github-token ${{ secrets.GITHUB_TOKEN }} --behavior update
予算閾値とコストポリシー
# infracost.yml — ポリシーファイル
version: 0.1
policies:
- path: "*"
max_monthly_cost: "5000" # 推定コストが月額$5,000を超える場合PRをフェール
max_cost_increase: "500" # コスト増加が月額$500を超える場合PRをフェール
既存インフラストラクチャのインポート
手動で作成されたリソースをTerraform管理下に置きます。
terraform import ワークフロー
# 1. リソースブロックを最初に作成(空の本体でも構いません)
# main.tf:
# resource "aws_s3_bucket" "legacy" {}
# 2. リソースを状態にインポート
terraform import aws_s3_bucket.legacy my-existing-bucket-name
# 3. planを実行して属性の差を確認
terraform plan
# 4. planが変更を示さなくなるまでリソースブロックを埋める
一括インポートと設定生成(Terraform 1.5以降)
# インポートされたリソースのHCLを生成
terraform plan -generate-config-out=generated.tf
# generated.tfを確認してから、リソースを適切なファイルに移動
一般的な落とし穴
- インポート後のリソースドリフト:インポートされたリソースには、Terraformが管理しない属性がある場合があります。すぐに
terraform planを実行し、すべての差を解決します。 - 状態の操作:
terraform state mvを使用して名前を変更または再編成します。terraform state rmを使用して削除します(破棄しない)。状態を操作する前に常にバックアップします:terraform state pull > backup.tfstate。 - センシティブなデフォルト:インポートされたリソースは状態でシークレットを公開する場合があります。状態アクセスを制限し、暗号化を有効化します。
Terragruntパターン
Terragruntはマルチ環境セットアップでDRY設定を提供するTerraformの薄いラッパー。
ルートterragrunt.hcl(共有設定)
# terragrunt.hcl(ルート)
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "my-org-terraform-state"
key = "${path_relative_to_include()}/terraform.tf
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- JantonioFC
- ライセンス
- MIT
- 最終更新
- 2026/5/9
Source: https://github.com/JantonioFC/skillsbank / ライセンス: MIT