mcpField
T
terraform-iac-expert

terraform-iac-expert

github.com/curiositechクラウド・DevOps257165 回インストール2 日前に更新
リポジトリ

terraform-iac-expert について

terraform-iac-expertは、TerraformとOpenTofuを使うインフラエンジニア向けのスキルです。モジュール設計、状態管理、マルチクラウド環境に加え、環境構成、セキュリティ、CI/CD連携を扱います。

主な機能

  1. 01再利用可能なTerraformモジュールの設計
  2. 02リモート状態とロックの設定
  3. 03複数環境のインフラ管理
  4. 04状態の移行とドリフトへの対応
  5. 05シークレットとIAMのセキュリティ設計
  6. 06CI/CDワークフローとの連携

活用シーン

  1. 01Terraformプロジェクト構成の作成
  2. 02開発・ステージング・本番環境の設定
  3. 03既存リソースの状態へのインポート
  4. 04状態ドリフトやプラン失敗の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/curiositech/some_claude_skills --skill terraform-iac-expert

インストール後、Claude Code で/terraform-iac-expertを入力して読み込まれたか確認します。

同梱ファイル.claude-plugin/plugin.json

詳細

Terraform IaC エキスパート

概要

Terraform と OpenTofu を使用した Infrastructure as Code のエキスパートです。モジュール設計、状態管理、マルチクラウドへのデプロイ、CI/CD 連携を専門としています。複数環境のセットアップ、リモート状態バックエンド、セキュアなシークレット管理など、複雑なインフラストラクチャパターンに対応します。

使用する場面

  • 新しい Terraform プロジェクトやワークスペースのセットアップ
  • 再利用可能な Terraform モジュールの設計
  • 状態ファイルとリモートバックエンドの管理
  • 複数環境(dev/staging/prod)のインフラストラクチャの実装
  • 既存のインフラストラクチャの Terraform への移行
  • 状態のドリフトや plan の失敗のトラブルシューティング
  • Terraform と CI/CD パイプラインの連携
  • セキュリティのベストプラクティス(シークレット、IAM、ポリシー)の実装

機能

プロジェクト構成
  • モジュールベースのアーキテクチャ設計
  • ワークスペースとディレクトリ構成の戦略
  • 変数と出力の整理
  • プロバイダーの設定とバージョン制約
  • リモート状態用のバックエンド設定
モジュール開発
  • 再利用可能なモジュールパターン
  • 入力の検証と型制約
  • モジュールの組み合わせを考慮した出力設計
  • ローカルモジュールとレジストリモジュール
  • モジュールのバージョン管理と公開
状態管理
  • リモート状態バックエンド(S3、GCS、Azure Blob、Terraform Cloud)
  • 状態ロックの仕組み
  • 状態の移行と操作
  • 既存リソースのインポート
  • 状態のドリフトへの対処
複数環境のパターン
  • ワークスペースベースの環境
  • ディレクトリベースの環境
  • DRY なインフラストラクチャを実現する Terragrunt
  • 環境固有の変数
  • 環境昇格のワークフロー
セキュリティ
  • 機密変数の取り扱い
  • Terraform 用 IAM ロールの設計
  • Policy as Code(Sentinel、OPA)
  • シークレット管理との連携(Vault、AWS Secrets Manager)
  • 最小権限の原則
CI/CD 連携
  • Terraform 用 GitHub Actions
  • PR ベースのワークフロー向け Atlantis
  • Terraform Cloud/Enterprise
  • Plan/Apply の自動化
  • コスト見積もりとの連携

依存関係

以下と相性よく連携します:

  • aws-solutions-architect - AWS リソースのパターン
  • kubernetes-orchestrator - K8s インフラストラクチャ
  • github-actions-pipeline-builder - CI/CD の自動化
  • site-reliability-engineer - 本番環境のインフラストラクチャ

例

プロジェクト構成
terraform/
├── modules/
│   ├── vpc/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── eks/
│   └── rds/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── terraform.tfvars
│   │   └── backend.tf
│   ├── staging/
│   └── prod/
└── shared/
    └── provider.tf
Locals を使ったルートモジュール
# environments/prod/main.tf
terraform {
  required_version = ">= 1.5.0"

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

  backend "s3" {
    bucket         = "mycompany-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-west-2"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

locals {
  environment = "prod"
  project     = "myapp"

  common_tags = {
    Environment = local.environment
    Project     = local.project
    ManagedBy   = "terraform"
  }
}

module "vpc" {
  source = "../../modules/vpc"

  environment = local.environment
  cidr_block  = "10.0.0.0/16"
  tags        = local.common_tags
}

module "eks" {
  source = "../../modules/eks"

  environment       = local.environment
  vpc_id            = module.vpc.vpc_id
  private_subnet_ids = module.vpc.private_subnet_ids
  cluster_version   = "1.29"
  tags              = local.common_tags
}
入力検証を備えた再利用可能なモジュール
# modules/vpc/variables.tf
variable "environment" {
  type        = string
  description = "Environment name (dev, staging, prod)"

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

variable "cidr_block" {
  type        = string
  description = "VPC CIDR block"

  validation {
    condition     = can(cidrhost(var.cidr_block, 0))
    error_message = "Must be a valid CIDR block."
  }
}

variable "availability_zones" {
  type        = list(string)
  description = "List of AZs to use"
  default     = ["us-west-2a", "us-west-2b", "us-west-2c"]
}

variable "enable_nat_gateway" {
  type        = bool
  description = "Enable NAT Gateway for private subnets"
  default     = true
}

variable "tags" {
  type        = map(string)
  description = "Tags to apply to all resources"
  default     = {}
}
動的ブロックを使ったモジュール
# modules/security-group/main.tf
resource "aws_security_group" "this" {
  name        = var.name
  description = var.description
  vpc_id      = var.vpc_id

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
      description = ingress.value.description
    }
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(var.tags, {
    Name = var.name
  })
}
リモート状態のデータソース
# Reference another environment's state
data "terraform_remote_state" "shared" {
  backend = "s3"

  config = {
    bucket = "mycompany-terraform-state"
    key    = "shared/terraform.tfstate"
    region = "us-west-2"
  }
}

# Use outputs from shared state
resource "aws_instance" "app" {
  ami           = data.terraform_remote_state.shared.outputs.base_ami_id
  instance_type = "t3.medium"
  subnet_id     = data.terraform_remote_state.shared.outputs.private_subnet_id
}
GitHub Actions による CI/CD
# .github/workflows/terraform.yml
name: Terraform

on:
  pull_request:
    paths:
      - 'terraform/**'
  push:
    branches: [main]
    paths:
      - 'terraform/**'

env:
  TF_VERSION: 1.6.0
  AWS_REGION: us-west-2

jobs:
  plan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
      id-token: write  # For OIDC

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/terraform-github-actions
          aws-region: ${{ env.AWS_REGION }}

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Init
        working-directory: terraform/environments/prod
        run: terraform init

      - name: Terraform Plan
        working-directory: terraform/environments/prod
        run: terraform plan -out=tfplan

      - name: Upload Plan
        uses: actions/upload-artifact@v4
        with:
          name: tfplan
          path: terraform/environments/prod/tfplan

  apply:
    needs: plan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    environment: production

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/terraform-github-actions
          aws-region: ${{ env.AWS_REGION }}

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Download Plan
        uses: actions/download-artifact@v4
        with:
          name: tfplan
          path: terraform/environments/prod

      - name: Terraform Apply
        working-directory: terraform/environments/prod
        run: terraform apply -auto-approve tfplan
既存リソースのインポート
# Import existing AWS resource into state
terraform import aws_s3_bucket.existing my-existing-bucket

# Import using for_each key
terraform import 'aws_iam_user.users["alice"]' alice

# Generate configuration from import (Terraform 1.5+)
terraform plan -generate-config-out=generated.tf
機密値の取り扱い
# Reference secrets from AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "prod/db/password"
}

resource "aws_db_instance" "main" {
  # ... other config ...
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

# Mark outputs as sensitive
output "db_connection_string" {
  value     = "postgres://admin:${aws_db_instance.main.password}@${aws_db_instance.main.endpoint}"
  sensitive = true
}

ベストプラクティス

  1. リモート状態を使用する - チームで使うプロジェクトでは、状態をローカルに保存しないでください
  2. 状態ロックを有効にする - 同時変更を防止します
  3. プロバイダーのバージョンを固定する - >= ではなく ~> 制約を使用します
  4. 環境を分離する - ブランチではなく、ディレクトリまたはワークスペースを使用します
  5. 再利用可能なものはモジュール化する - ただし、過度な抽象化は避けます
  6. 入力を検証する - 変数の検証ブロックを使用します
  7. データソースを使用する - ハードコードする代わりに既存のリソースを参照します
  8. すべてのリソースにタグを付ける - コスト追跡のため、一貫したタグを適用します
  9. プランを慎重に確認する - 特に破棄操作を確認します

よくある落とし穴

  • 状態ファイルの競合 - 複数の人が同時に terraform を実行する
  • 値のハードコード - 環境ごとの違いに変数を使用しない
  • 循環依存 - リソース同士が相互に依存する
  • 依存関係の指定漏れ - 暗黙の依存関係だけでは不十分な場合に depends_on を使用しない
  • 状態ファイルの肥大化 - 大規模なインフラストラクチャを分割しない
  • 状態内のシークレット - 状態に機密値が含まれるため、保存時に暗号化する
  • プロバイダーバージョンの不一致 - チームメンバーごとに異なるバージョンを使用する
  • -target の不注意な使用 - ドリフトの原因になる可能性があるため、必要な場合に限って使用する

コメント