1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeを利用したTerraform入門ハンズオン

1
Last updated at Posted at 2026-05-10

はじめに

こんにちは、しげぞーです。
Terraformの学習を効率的にできないかと思い
Claude Codeを利用してTerraformをステップバイステップで学習できるハンズオンを用意してみました。

以下の要件をClaude Codeに伝えてプロジェクトはClaude Codeに用意してもらいました。

・このプロジェクトはterraformを利用して、ステップバイステップでAWSリソースを作成することを学習するためのものです。
・私はterraformについては初学者です。ローカル環境での設定も全然できていません。
・ハンズオン形式で進められると学習がしやすいので、ローカル環境とAWS環境を利用して一から必要な手順について教えてください。
・AWSリソースは一つずつ追加するようにお願いします。terraformの記述については毎回丁寧にわかりやすく教えてください
・コード規約にterraformのベストプラクティスに沿うような記述をお願いします。
・claude codeのベストプラクティスでセキュリティに考慮した方が良い項目をhooksとpermissionsに記述して
・このプロジェクトにあると初学者が便利なskillsとagentsを一覧化して。

インフラ構成図

今回のハンズオンで最終的に出来上がったインフラ構成は以下になります。
infra-diagram.png

Claude Code設定

プロジェクトの中からCLAUDE.md, skills, subagents, hooks, permissionsをいくつか紹介します。
記載しているskillsとsubagentsはハンズオンを進める上で非常に助けになりました。

CLAUDE.md

# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## プロジェクト概要

Terraform を利用して、ステップバイステップで AWS リソースを作成することを学習するためのプロジェクト。

スキルは .claude/skills/{スキル名}/SKILL.md に記載すること
サブエージェントは .claude/agents/{エージェント名}.md に記載すること

## ユーザーの前提知識

- Terraform、AWS ともに初学者
- ローカル環境のセットアップも未完了の状態から開始

## 学習の進め方

- ハンズオン形式で、ローカル環境構築から一つずつ進める
- AWS リソースは一度に一つずつ追加する
- よく利用されるリソースかつ簡単なものから順に取り組む
- 各ステップで AskUserQuestion を使い選択形式で進行する
- Terraform の記述については毎回丁寧にわかりやすく説明する
- 不明点があればユーザーに質問する

## よく使うコマンド

```bash
terraform init       # 初期化(プロバイダーのダウンロード等)
terraform fmt        # フォーマット
terraform validate   # 構文チェック
terraform plan       # 実行計画の確認
terraform apply      # リソースの作成・変更を適用
terraform destroy    # リソースの削除
```

## コード規約

### ファイル構成

- `main.tf` -- メインのリソース定義
- `variables.tf` -- 入力変数の定義
- `outputs.tf` -- 出力値の定義
- `providers.tf` -- プロバイダーとバージョン制約の設定
- `terraform.tfvars` -- 変数の値(git 管理対象外にする場合あり)
- `locals.tf` -- ローカル値の定義(必要に応じて)
- `data.tf` -- データソースの定義(必要に応じて)

### 命名規則

- リソース名・変数名・出力名はすべてスネークケース(`my_resource_name`)を使用する
- リソース名にプロバイダー名を繰り返さない(`aws_instance.aws_web` ではなく `aws_instance.web`)
- boolean 変数には `is_`、`has_`、`enable_` のプレフィックスを使う
- リソースが単一の場合は `this` または `main` を名前にする

### 変数とハードコード防止

- AWS プロバイダーの `region` はハードコードせず変数化する
- 繰り返し使う値は `locals` ブロックにまとめる
- すべての `variable` に `description` と `type` を必ず記述する
- デフォルト値が適切な場合は `default` を設定する
- 機密情報を含む変数には `sensitive = true` を付与する

### バージョン管理

- `required_providers` でプロバイダーのバージョン制約を明示する(例: `~> 5.0`)
- `required_version` で Terraform 本体のバージョン制約を明示する
- `.terraform.lock.hcl` は git にコミットしてプロバイダーバージョンを固定する
- `.terraform/` ディレクトリは `.gitignore` に追加する

### フォーマットとスタイル

- `terraform fmt` のフォーマットに従う
- `terraform validate` をコード変更後に必ず実行する
- リソースブロック内の引数は論理的にグルーピングし、グループ間に空行を入れる
- `tags` は全リソースに共通タグ(`Name`、`Environment` 等)を付与する

### セキュリティ

- セキュリティグループのインバウンドルールで `0.0.0.0/0` の使用は最小限にする
- IAM ポリシーは最小権限の原則に従い、`"Action": "*"` や `"Resource": "*"` を避ける
- S3 バケットはパブリックアクセスをデフォルトでブロックする
- RDS 等のパスワードは Terraform コードに直書きせず、変数または AWS Secrets Manager を使う

### ステート管理

- 学習初期はローカルステート(`terraform.tfstate`)で進める
- `terraform.tfstate` と `terraform.tfstate.backup` は `.gitignore` に追加する
- 本格運用時は S3 + DynamoDB による remote backend への移行を検討する

skills

explain - Terraform コードを初学者向けにわかりやすく解説する

---
name: explain
description: Terraform コードを初学者向けにわかりやすく解説する
新たなファイルが作成される度に、そのファイルの内容を解説するためにこのスキルを呼び出す。
user_invocable: true
arguments:
  - name: target
    description: 解説対象のファイルパスまたはリソース名
    required: true
---

# Terraform コード解説スキル

指定された Terraform コードを初学者にもわかるように丁寧に解説する。

## 手順

1. `target` で指定されたファイルまたはリソースを読み込む
2. 以下の構成で解説を出力する

## 解説の構成

### 全体の概要
- このコードが何をするものかを一言で説明する

### ブロックごとの解説
コード内の各ブロック(`resource`、`variable`、`data`、`output`、`locals` 等)について以下を説明する:
- ブロックの種類と役割
- 各引数の意味と設定値の理由
- 他のリソースやモジュールとの依存関係(`depends_on` や参照式がある場合)

### 使われている構文・関数の説明
- 補間構文(`${}`)、参照式(`aws_instance.web.id` 等)の読み方
- 組み込み関数(`lookup`、`join`、`file` 等)が使われていればその動作
- `count`、`for_each`、`dynamic` ブロック等があればその仕組み

### AWS リソースとしての補足
- 作成される AWS リソースが実際のインフラでどのような役割を持つか
- 料金が発生するリソースの場合はその旨を注記する
- 関連する AWS の概念(VPC、サブネット、セキュリティグループ等)の簡単な説明

## 解説のルール

- 専門用語を使う場合は必ず補足説明を添える
- コードの該当箇所を引用しながら説明する
- 「なぜこう書くのか」という理由も含める
- 改善点やベストプラクティスとの差異があれば最後に補足する

glossary - 指定されたTerraformやAWSの用語を初学者にもわかるようにわかりやすく解説する。

---
name: glossary
description: Terraform や AWS の用語を初学者向けにわかりやすく解説する
user_invocable: true
arguments:
  - name: term
    description: 調べたい用語(例: VPC, サブネット, セキュリティグループ, state, provider)
    required: true
---

# Terraform / AWS 用語解説スキル

指定された用語を初学者にもわかるようにわかりやすく解説する。

## 手順

1. `term` で指定された用語を特定する
2. Terraform の用語か AWS の用語かを判別する
3. 以下の構成で解説を出力する

## 解説の構成

### 一言で説明
- その用語が何かを一文で説明する
- 日常的な例えがあれば添える(例: VPC = 「AWS 上の自分専用ネットワーク」)

### 詳細な説明
- 用語の正式名称と略称
- 具体的に何をするものか、なぜ必要か
- 他の概念との関係性(例: VPC の中にサブネットがある)

### Terraform での使い方
- Terraform でその概念を扱うリソースタイプ名
- 簡単なコード例(3-5行程度)
- よく使う引数の説明

### 関連用語
- セットで理解すべき関連用語を 2-3 個挙げる
- 各用語との関係を一言で添える

## 解説のルール

- 英語の技術用語を使う場合はカタカナ表記と原語を併記する
- 「つまりこういうこと」という平易な言い換えを含める
- 公式ドキュメントを丸写しせず、噛み砕いた表現にする

scaffold - 新しい AWS リソースの Terraform ファイル雛形を生成する

---
name: scaffold
description: 新しい AWS リソースの Terraform ファイル雛形を生成する
user_invocable: true
arguments:
  - name: resource
    description: 作成したい AWS リソースの種類(例: s3, ec2, vpc, rds, lambda)
    required: true
---

# Terraform リソース雛形生成スキル

指定された AWS リソースに対して、ベストプラクティスに沿った `.tf` ファイルの雛形を生成する。

## 手順

1. `resource` 引数で指定されたリソースの種類を確認する
2. プロジェクトの CLAUDE.md のコード規約に従い、以下のファイルを生成する

## 生成するファイル

### main.tf
- リソース定義本体
- 必須の引数をすべて含める
- セキュリティのベストプラクティスに沿った初期設定を適用する
- 共通タグ(Name, Environment)を付与する

### variables.tf
- リソースに必要な変数を定義する
- すべての variable に `description` と `type` を記述する
- 適切なデフォルト値を設定する
- 機密情報には `sensitive = true` を付与する

### outputs.tf
- よく参照される属性(ID、ARN 等)を出力として定義する
- すべての output に `description` を記述する

### providers.tf(未作成の場合のみ)
- AWS プロバイダーの設定
- `required_providers` と `required_version` を含める

## 生成後の対応

- 生成したコードの各ブロックについて簡潔に説明する
- `terraform init` と `terraform validate` の実行を案内する
- そのリソース固有の注意点(料金、セキュリティ等)があれば補足する

サブエージェント

learning-guide.md - 次に学ぶべき AWS リソースを提案し、ハンズオン学習を進行するエージェント

---
name: learning-guide
description: 次に学ぶべき AWS リソースを提案し、ハンズオン学習を進行するエージェント
---

# 学習ガイドエージェント

ユーザーの現在の学習状況を把握し、次に取り組むべき AWS リソースを提案してハンズオンを進行する。

## 学習ロードマップ

以下の順序を基本とし、ユーザーの状況に応じて調整する:

### ステップ 1: 基礎環境
1. Terraform / AWS CLI のインストールと初期設定
2. AWS プロバイダーの設定(providers.tf)
3. S3 バケットの作成(最もシンプルなリソース)

### ステップ 2: ネットワーク基礎
4. VPC の作成
5. サブネット(パブリック / プライベート)の作成
6. インターネットゲートウェイの作成
7. ルートテーブルの作成

### ステップ 3: コンピューティング
8. セキュリティグループの作成
9. EC2 インスタンスの起動
10. Elastic IP の割り当て

### ステップ 4: 応用
11. IAM ユーザー / ロール / ポリシーの作成
12. RDS の作成
13. Lambda 関数の作成
14. CloudWatch アラームの設定

## 進行方法

1. 現在のディレクトリの `.tf` ファイルと `terraform state list` から学習済みリソースを把握する
2. ロードマップに基づき次のリソースを提案する
3. AskUserQuestion で進め方を確認する
4. scaffold スキルと同様の手順で雛形を生成する
5. explain スキルと同様の手順でコードを解説する
6. `terraform plan` の内容を説明し、`terraform apply` を案内する

## 各ステップで必ず含める内容

- そのリソースの AWS における役割の説明
- Terraform コードの各行の解説
- apply 後の確認方法(AWS コンソールでの確認手順)
- 料金に関する注意(無料枠の範囲か否か)
- 学習のポイントとなる概念の補足

Hooks, permissions

settings.jsonに以下を記載することで意図しないコマンド実行やファイル操作に制限をかけています。

settings.json
{
  "permissions": {
    "allow": [
      "Bash(terraform fmt:*)",
      "Bash(terraform validate:*)",
      "Bash(terraform plan:*)",
      "Bash(terraform init:*)",
      "Bash(terraform state list:*)",
      "Bash(terraform state show:*)",
      "Bash(terraform output:*)",
      "Bash(terraform version:*)",
      "Bash(terraform providers:*)",
      "Bash(find:*)",
      "Bash(ls:*)",
      "Bash(cat:*)",
      "Bash(grep:*)",
      "Bash(git status:*)",
      "Bash(git log:*)",
      "Bash(git diff:*)",
      "Bash(git branch:*)",
      "Bash(aws sts get-caller-identity:*)",
      "Bash(aws configure list:*)"
    ],
    "deny": [
      "Bash(terraform apply -auto-approve:*)",
      "Bash(terraform destroy -auto-approve:*)",
      "Bash(rm -rf:*)",
      "Bash(rm -r:*)",
      "Bash(git push --force:*)",
      "Bash(git push --force-with-lease:*)",
      "Bash(git reset --hard:*)",
      "Bash(git clean:*)",
      "Bash(chmod 777:*)",
      "Bash(chown:*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *terraform\\ apply\\ -auto-approve*|*terraform\\ destroy\\ -auto-approve*) echo 'BLOCK: -auto-approve は禁止されています。必ずユーザーが確認してから適用してください。' && exit 2 ;; esac",
            "description": "terraform apply/destroy の -auto-approve をブロック"
          },
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *rm\\ -rf*|*rm\\ -r\\ /*) echo 'BLOCK: 広範囲の削除コマンドは禁止されています。' && exit 2 ;; esac",
            "description": "広範囲の rm コマンドをブロック"
          },
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *\\.env*|*credentials*|*secrets*|*\\.pem*|*\\.key*|*tfstate*) case \"$CLAUDE_TOOL_INPUT\" in *cat\\ *|*head\\ *|*tail\\ *|*less\\ *|*more\\ *|*nano\\ *|*vim\\ *|*code\\ *) echo 'BLOCK: 機密ファイルの読み取りは禁止されています。' && exit 2 ;; esac ;; esac",
            "description": "機密ファイルの内容読み取りをブロック"
          },
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *curl\\ *-X\\ POST*|*curl\\ *-X\\ PUT*|*curl\\ *-X\\ PATCH*|*curl\\ *--data*|*curl\\ *-d\\ *|*wget\\ --post*) echo 'BLOCK: 外部サービスへのデータ送信は禁止されています。' && exit 2 ;; esac",
            "description": "外部へのデータ送信をブロック"
          },
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *npm\\ install*|*pip\\ install*|*brew\\ install*|*apt\\ install*|*cargo\\ install*) echo 'BLOCK: パッケージのインストールはユーザーの許可が必要です。' && exit 2 ;; esac",
            "description": "パッケージの自動インストールをブロック"
          }
        ]
      },
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *\\.env*|*credentials*|*secrets*|*service-account*|*\\.pem*|*\\.key*|*\\.p12*|*\\.pfx*|*tfstate*|*\\.ssh*|*\\.gnupg*|*\\.aws/credentials*) echo 'BLOCK: 機密ファイルの読み取りは禁止されています。' && exit 2 ;; esac",
            "description": "Read ツールによる機密ファイルの読み取りをブロック"
          }
        ]
      },
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *\\.env*|*credentials*|*secrets*|*service-account*|*\\.pem*|*\\.key*|*tfstate*) echo 'BLOCK: 機密ファイルの編集は禁止されています。' && exit 2 ;; esac",
            "description": "Edit ツールによる機密ファイルの編集をブロック"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "case \"$CLAUDE_TOOL_INPUT\" in *.tf|*.tf.json) cd /Users/shigezou46/Project/infra/infra-terraform-learning && terraform fmt -check -diff \"$(echo $CLAUDE_TOOL_INPUT | grep -o '[^ ]*\\.tf[^ ]*')\" 2>/dev/null || echo 'WARNING: terraform fmt のフォーマットと差異があります。terraform fmt を実行してください。' ;; esac; exit 0",
            "description": ".tf ファイル書き込み後にフォーマットチェック"
          }
        ]
      }
    ]
  }
}

ハンズオン

ハンズオンはサブエージェントの学習ガイドに沿って進めます。

### ステップ 1: 基礎環境
1. Terraform / AWS CLI のインストールと初期設定
2. AWS プロバイダーの設定(providers.tf)
3. S3 バケットの作成(最もシンプルなリソース)

### ステップ 2: ネットワーク基礎
4. VPC の作成
5. サブネット(パブリック / プライベート)の作成
6. インターネットゲートウェイの作成
7. ルートテーブルの作成

### ステップ 3: コンピューティング
8. セキュリティグループの作成
9. EC2 インスタンスの起動
10. Elastic IP の割り当て

### ステップ 4: 応用
11. IAM ユーザー / ロール / ポリシーの作成
12. RDS の作成
13. Lambda 関数の作成
14. CloudWatch アラームの設定

各ステップについて以下のように進めていきました。

  1. 学習するAWSリソースが選択形式で提示されるので選択
  2. AWSリソースの解説
  3. わからない用語があれば質問して確認
  4. 理解できたら、terraformコードの生成と解説
  5. 解説でわからないところは深掘りをして確認
  6. terraform planで変更を確認
  7. terraform applyでAWSに反映(手動で実行)
  8. 反映が確認したら、次の学習するAWSリソースが選択形式で提示されるので選択
    1に戻る

学習を終了するタイミングで毎回terraform destroyを実行してリソースを削除(手動で実行)
消し忘れるとお金がかかりますので、忘れずに消しましょう!
学習を終了することをClaudeCodeに伝えるとterrafor destroyを提案されるので忘れる心配もありません。

まとめ

Terraformの学習を進めるにあたり、ハンズオンの作成から実施までClaude Codeを利用して行いましたが、効率的に学習を進められたと思います。
他の技術のキャッチアップの際にもまた活用してみようと思います。

リポジトリ

こちらにプロジェクトを用意しておりますので、よければ試してみてください!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?