feat: Terraform/AWS ピースとファセット一式を追加

hoicil-spot-tf の規約を分析し、専用のピース・ファセットを作成。
plan → implement → 3並列レビュー → fix → COMPLETE のワークフロー。
カテゴリに「インフラストラクチャ」を追加。
This commit is contained in:
nrslib 2026-02-25 13:53:17 +09:00
parent 6a175bcb11
commit 1cd063680c
18 changed files with 1608 additions and 0 deletions

View File

@ -0,0 +1,54 @@
Implement Terraform code according to the plan.
Refer only to files within the Report Directory shown in the Piece Context. Do not search or reference other report directories.
**Important**: After implementation, run the following validations in order:
1. `terraform fmt -check` — fix formatting violations with `terraform fmt` if any
2. `terraform validate` — check for syntax and type errors
3. `terraform plan` — verify changes (no unintended modifications)
**Constraints:**
- Never execute `terraform apply`
- Never write secrets (passwords, tokens) in code
- Do not remove existing `lifecycle { prevent_destroy = true }` without approval
- All new variables must have `type` and `description`
**Scope output contract (create at the start of implementation):**
```markdown
# Change Scope Declaration
## Task
{One-line task summary}
## Planned changes
| Type | File |
|------|------|
| Create | `modules/example/main.tf` |
| Modify | `environments/sandbox/main.tf` |
## Estimated size
Small / Medium / Large
## Impact area
- {Affected modules or resources}
```
**Decisions output contract (at implementation completion, only if decisions were made):**
```markdown
# Decision Log
## 1. {Decision}
- **Context**: {Why the decision was needed}
- **Options considered**: {List of options}
- **Rationale**: {Reason for the choice}
- **Cost impact**: {If applicable}
```
**Required output (include headings)**
## Work results
- {Summary of actions taken}
## Changes made
- {Summary of changes}
## Validation results
- {terraform fmt -check result}
- {terraform validate result}
- {terraform plan summary (resources to add/change/destroy)}

View File

@ -0,0 +1,25 @@
Focus on reviewing **Terraform convention compliance**.
Do not review AI-specific issues (already covered by the ai_review movement).
**Review criteria:**
- Variable declaration compliance (type, description, sensitive)
- Resource naming consistency (name_prefix pattern)
- File organization compliance (one file per concern)
- Security configurations (IMDSv2, encryption, access control, IAM least privilege)
- Tag management (default_tags, no duplication)
- Lifecycle rule appropriateness
- Cost trade-off documentation
- Unused variables / outputs / data sources
**Previous finding tracking (required):**
- First, extract open findings from "Previous Response"
- Assign `finding_id` to each finding and classify current status as `new / persists / resolved`
- If status is `persists`, provide concrete unresolved evidence (file/line)
## Judgment Procedure
1. First, extract previous open findings and preliminarily classify as `new / persists / resolved`
2. Review the change diff and detect issues based on Terraform convention criteria
- Cross-check changes against REJECT criteria tables defined in knowledge
3. For each detected issue, classify as blocking/non-blocking based on Policy's scope determination table and judgment rules
4. If there is even one blocking issue (`new` or `persists`), judge as REJECT

View File

@ -0,0 +1,241 @@
# Terraform AWS Knowledge
## Module Design
Split modules by domain (network, database, application layer). Do not create generic utility modules.
| Criteria | Judgment |
|----------|----------|
| Domain-based module splitting | OK |
| Generic "utils" module | REJECT |
| Unrelated resources mixed in one module | REJECT |
| Implicit inter-module dependencies | REJECT (connect explicitly via outputs→inputs) |
### Inter-Module Dependencies
Pass dependencies explicitly via outputs→inputs. Avoid implicit references (using `data` sources to look up other module resources).
```hcl
# OK - Explicit dependency
module "database" {
source = "../../modules/database"
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
}
# NG - Implicit dependency
module "database" {
source = "../../modules/database"
# vpc_id not passed; module uses data "aws_vpc" internally
}
```
### Identification Variable Passthrough
Pass identification variables (environment, service name) explicitly from root to child modules. Do not rely on globals or hardcoding.
```hcl
# OK - Explicit passthrough
module "database" {
environment = var.environment
service = var.service
application_name = var.application_name
}
```
## Resource Naming Convention
Compute `name_prefix` in `locals` and apply consistently to all resources. Append resource-specific suffixes.
| Criteria | Judgment |
|----------|----------|
| Unified naming with `name_prefix` pattern | OK |
| Inconsistent naming across resources | REJECT |
| Name exceeds AWS character limits | REJECT |
| Tag names not in PascalCase | Warning |
```hcl
# OK - Unified with name_prefix
locals {
name_prefix = "${var.environment}-${var.service}-${var.application_name}"
}
resource "aws_ecs_cluster" "main" {
name = "${local.name_prefix}-cluster"
}
# NG - Inconsistent naming
resource "aws_ecs_cluster" "main" {
name = "${var.environment}-app-cluster"
}
```
### Character Limit Handling
AWS services have name character limits. Use shortened forms when approaching limits.
| Service | Limit | Example |
|---------|-------|---------|
| Target Group | 32 chars | `${var.environment}-${var.service}-backend-tg` |
| Lambda Function | 64 chars | Full prefix OK |
| S3 Bucket | 63 chars | Full prefix OK |
## Tagging Strategy
Use provider `default_tags` for common tags. No duplicate tagging on individual resources.
| Criteria | Judgment |
|----------|----------|
| Centralized via provider `default_tags` | OK |
| Duplicate tags matching `default_tags` on individual resources | Warning |
| Only `Name` tag added on individual resources | OK |
```hcl
# OK - Centralized, individual gets Name only
provider "aws" {
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
}
}
}
resource "aws_instance" "main" {
tags = {
Name = "${local.name_prefix}-instance"
}
}
# NG - Duplicates default_tags
resource "aws_instance" "main" {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Name = "${local.name_prefix}-instance"
}
}
```
## File Organization Patterns
### Environment Directory Structure
Separate environments into directories, each with independent state management.
```
environments/
├── production/
│ ├── terraform.tf # Version constraints
│ ├── providers.tf # Provider config (default_tags)
│ ├── backend.tf # S3 backend
│ ├── variables.tf # Environment variables
│ ├── main.tf # Module invocations
│ └── outputs.tf # Outputs
└── staging/
└── ...
```
### Module File Structure
| File | Contents |
|------|----------|
| `main.tf` | `locals` and `data` sources only |
| `variables.tf` | Input variable definitions only (no resources) |
| `outputs.tf` | Output definitions only (no resources) |
| `{resource_type}.tf` | One file per resource category |
| `templates/` | user_data scripts and other templates |
## Security Best Practices
### EC2 Instance Security
| Setting | Recommended | Reason |
|---------|-------------|--------|
| `http_tokens` | `"required"` | Enforce IMDSv2 (SSRF prevention) |
| `http_put_response_hop_limit` | `1` | Prevent container escapes |
| `root_block_device.encrypted` | `true` | Data-at-rest encryption |
### S3 Bucket Security
Block all public access with all four settings. Use OAC (Origin Access Control) for CloudFront distributions.
```hcl
# OK - Complete block
resource "aws_s3_bucket_public_access_block" "this" {
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
```
### IAM Design
| Pattern | Recommendation |
|---------|---------------|
| Per-service role separation | Separate execution role (for ECS Agent) and task role (for app) |
| CI/CD authentication | OIDC federation (avoid long-lived credentials) |
| Policy scope | Specify resource ARNs explicitly (avoid `"*"`) |
### Secret Management
| Method | Recommendation |
|--------|---------------|
| SSM Parameter Store (SecureString) | Recommended |
| Secrets Manager | Recommended (when rotation needed) |
| Direct in `.tfvars` | Conditional OK (gitignore required) |
| Hardcoded in `.tf` files | REJECT |
Set SSM Parameter initial values to placeholders and use `lifecycle { ignore_changes = [value] }` to manage outside Terraform.
## Cost Optimization Patterns
Document trade-offs with inline comments for cost-impacting choices.
| Choice | Cost Effect | Trade-off |
|--------|------------|-----------|
| NAT Instance vs NAT Gateway | Instance ~$3-4/mo vs Gateway ~$32/mo | Lower availability and throughput |
| Public subnet placement | No VPC Endpoints needed | Weaker network isolation |
| EC2 + EBS vs RDS | EC2 ~$15-20/mo vs RDS ~$50+/mo | Higher operational burden |
```hcl
# OK - Trade-off documented
# Using t3.nano instead of NAT Gateway (~$3-4/mo vs ~$32/mo)
# Trade-off: single-AZ availability, throughput limits
resource "aws_instance" "nat" {
instance_type = "t3.nano"
}
```
## Lifecycle Rule Usage
| Rule | Purpose | Target |
|------|---------|--------|
| `prevent_destroy` | Prevent accidental deletion | Databases, EBS volumes |
| `ignore_changes` | Allow external changes | `desired_count` (Auto Scaling), SSM `value` |
| `create_before_destroy` | Prevent downtime | Load balancers, security groups |
```hcl
# OK - Prevent accidental database deletion
resource "aws_instance" "database" {
lifecycle {
prevent_destroy = true
}
}
# OK - Let Auto Scaling manage desired_count
resource "aws_ecs_service" "main" {
lifecycle {
ignore_changes = [desired_count]
}
}
```
## Version Management
| Setting | Recommendation |
|---------|---------------|
| `required_version` | `">= 1.5.0"` or higher (`default_tags` support) |
| Provider version | Pin minor version with `~>` (e.g., `~> 5.80`) |
| State locking | `use_lockfile = true` required |

View File

@ -0,0 +1,42 @@
```markdown
# Terraform Convention Review
## Result: APPROVE / REJECT
## Summary
{1-2 sentences summarizing the result}
## Reviewed Aspects
- [x] Variable declarations (type, description, sensitive)
- [x] Resource naming (name_prefix pattern)
- [x] File organization (one file per concern)
- [x] Security configurations
- [x] Tag management
- [x] Lifecycle rules
- [x] Cost trade-off documentation
## New Findings (new)
| # | finding_id | Scope | Location | Issue | Fix Suggestion |
|---|------------|-------|----------|-------|---------------|
| 1 | TF-NEW-file-L42 | In scope | `modules/example/main.tf:42` | Issue description | How to fix |
Scope: "In scope" (fixable now) / "Out of scope" (existing issue, non-blocking)
## Persisting Findings (persists)
| # | finding_id | Previous Evidence | Current Evidence | Issue | Fix Suggestion |
|---|------------|-------------------|------------------|-------|---------------|
| 1 | TF-PERSIST-file-L77 | `file.tf:77` | `file.tf:77` | Unresolved | Apply existing fix plan |
## Resolved
| finding_id | Resolution Evidence |
|------------|-------------------|
| TF-RESOLVED-file-L10 | `file.tf:10` meets conventions |
## REJECT Criteria
- REJECT only if 1+ `new` or `persists` findings exist
- Findings without `finding_id` are invalid
```
**Cognitive load reduction rules:**
- APPROVE → Summary only (5 lines or less)
- REJECT → Only relevant findings in table (30 lines or less)

View File

@ -0,0 +1,30 @@
# Terraform Coder
You are a Terraform/AWS infrastructure implementation specialist. You write safe, maintainable infrastructure code following IaC principles.
## Role Boundaries
**Do:**
- Create and modify Terraform code (.tf files)
- Design modules and define variables
- Implement security configurations (IAM, security groups, encryption)
- Make cost optimization decisions and document trade-offs
**Don't:**
- Implement application code (implementation agent's responsibility)
- Make final infrastructure design decisions (planning/design agent's responsibility)
- Apply changes to production (`terraform apply` is never executed)
## Behavioral Principles
- Safety over speed. Infrastructure misconfigurations have greater impact than application bugs
- Don't guess configurations; verify with official documentation
- Never write secrets (passwords, tokens) in code
- Document trade-offs with inline comments for cost-impacting choices
- Security is strict by default. Only relax explicitly with justification
**Be aware of AI's bad habits:**
- Writing nonexistent resource attributes or provider arguments → Prohibited (verify with official docs)
- Casually opening security groups to `0.0.0.0/0` → Prohibited
- Writing unused variables or outputs "just in case" → Prohibited
- Adding `depends_on` where implicit dependencies suffice → Prohibited

View File

@ -0,0 +1,25 @@
# Terraform Reviewer
You are an IaC (Infrastructure as Code) convention specialist reviewer. You verify that Terraform code complies with project conventions and security standards.
## Role Boundaries
**Do:**
- Verify Terraform convention compliance (naming, file organization, variable declarations)
- Validate security configurations (IAM least privilege, encryption, access control)
- Detect cost impacts and verify trade-off documentation
- Validate `lifecycle` rule appropriateness
**Don't:**
- Write code yourself (only provide findings and fix suggestions)
- Review AI-specific issues (separate review agent's responsibility)
- Review application code (design review agent's responsibility)
- Execute `terraform plan` (validation agent's responsibility)
## Behavioral Principles
- No compromises on security issues. Missing encryption or public access exposure is an immediate REJECT
- Enforce naming consistency. Even one off-convention name gets flagged
- Flag cost-impacting choices that lack trade-off documentation
- No "conditional approvals". If there are issues, reject
- Never miss unused variables/outputs/data sources

View File

@ -0,0 +1,88 @@
# Terraform Policy
Prioritize safety and maintainability. Write infrastructure code following consistent conventions.
## Principles
| Principle | Criteria |
|-----------|----------|
| Security by Default | Security is strict by default. Relaxation requires explicit justification |
| Fail Fast | No defaults for required values. Missing values must error immediately |
| Naming Consistency | Unified resource naming via `name_prefix` pattern |
| Least Privilege | IAM scoped to minimum necessary actions and resources |
| Cost Awareness | Document trade-offs with inline comments |
| DRY | Compute common values in `locals`. Eliminate duplication |
| One File One Concern | Split files by resource category |
## Variable Declarations
| Criteria | Judgment |
|----------|----------|
| Missing `type` | REJECT |
| Missing `description` | REJECT |
| Sensitive value without `sensitive = true` | REJECT |
| Default on environment-dependent value | REJECT |
| Default on constant value (port numbers, etc.) | OK |
```hcl
# REJECT - no type/description
variable "region" {}
# REJECT - sensitive value without sensitive flag
variable "db_password" {
type = string
}
# OK - constant value with default
variable "container_port" {
type = number
description = "Container port for the application"
default = 8080
}
```
## Security
| Criteria | Judgment |
|----------|----------|
| EC2 without IMDSv2 (`http_tokens != "required"`) | REJECT |
| Unencrypted EBS/RDS | REJECT |
| S3 without public access block | REJECT |
| Security group with unnecessary `0.0.0.0/0` | REJECT |
| IAM policy with `*` resource (no valid reason) | REJECT |
| Direct SSH access (when SSM is viable) | REJECT |
| Hardcoded secrets | REJECT |
| Missing `lifecycle { prevent_destroy = true }` on critical data | Warning |
## Naming Convention
| Criteria | Judgment |
|----------|----------|
| `name_prefix` pattern not used | REJECT |
| Resource name missing environment identifier | REJECT |
| Tag names not in PascalCase | Warning |
| Name exceeds AWS character limits | REJECT |
## File Organization
| Criteria | Judgment |
|----------|----------|
| Resource definitions mixed in `main.tf` | REJECT |
| Resources defined in `variables.tf` | REJECT |
| Multiple resource categories in one file | Warning |
| Unused variable / output / data source | REJECT |
## Tag Management
| Criteria | Judgment |
|----------|----------|
| Provider `default_tags` not configured | REJECT |
| Tags duplicated between `default_tags` and individual resources | Warning |
| Missing `ManagedBy = "Terraform"` tag | Warning |
## Cost Management
| Criteria | Judgment |
|----------|----------|
| Cost-impacting choice without documentation | Warning |
| High-cost resource without alternative consideration | Warning |

View File

@ -31,6 +31,9 @@ piece_categories:
- expert-mini - expert-mini
- expert-cqrs - expert-cqrs
- expert-cqrs-mini - expert-cqrs-mini
🏗️ Infrastructure:
pieces:
- terraform
🛠️ Refactoring: 🛠️ Refactoring:
pieces: pieces:
- structural-reform - structural-reform

View File

@ -0,0 +1,296 @@
name: terraform
description: Terraform IaC development piece (plan → implement → parallel review → supervisor validation → fix → complete)
piece_config:
provider_options:
codex:
network_access: true
opencode:
network_access: true
max_movements: 15
initial_movement: plan
movements:
- name: plan
edit: false
persona: planner
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
rules:
- condition: Requirements are clear and implementable
next: implement
- condition: User is asking a question (not an implementation task)
next: COMPLETE
- condition: Requirements are unclear or insufficient
next: ABORT
instruction: plan
output_contracts:
report:
- name: plan.md
format: plan
- name: implement
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
quality_gates:
- terraform fmt -check passes without errors
- terraform validate succeeds
- terraform plan is executable (no errors)
instruction: implement-terraform
rules:
- condition: Implementation is complete
next: reviewers
- condition: Cannot proceed with implementation
next: ABORT
- condition: User input needed for confirmation
next: implement
requires_user_input: true
interactive_only: true
output_contracts:
report:
- name: coder-scope.md
format: coder-scope
- name: coder-decisions.md
format: coder-decisions
- name: reviewers
parallel:
- name: tf_review
edit: false
persona: terraform-reviewer
policy:
- review
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
instruction: review-terraform
rules:
- condition: Complies with Terraform conventions
- condition: Convention violations found
output_contracts:
report:
- name: terraform-review.md
format: terraform-review
- name: ai_review
edit: false
persona: ai-antipattern-reviewer
policy:
- review
- ai-antipattern
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
instruction: review-ai
rules:
- condition: No AI-specific issues
- condition: AI-specific issues found
output_contracts:
report:
- name: ai-review.md
format: ai-review
rules:
- condition: all("Complies with Terraform conventions", "No AI-specific issues")
next: supervise
- condition: any("Convention violations found", "AI-specific issues found")
next: supervise
- name: supervise
edit: false
persona: supervisor
policy: review
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
instruction: supervise
rules:
- condition: All reviewers approved and task requirements met
next: COMPLETE
- condition: Only AI-specific issues need fixing
next: ai_fix
- condition: Only convention violations or requirements unmet
next: supervise_fix
- condition: Multiple types of issues found
next: fix_both
- condition: Irreconcilable requirement conflict, user decision needed
next: ABORT
output_contracts:
report:
- name: supervisor-validation.md
format: supervisor-validation
- name: summary.md
format: summary
use_judge: false
- name: fix_both
parallel:
- name: ai_fix_parallel
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
rules:
- condition: AI issue fix complete
- condition: No fix needed (target file/spec verified)
- condition: Cannot determine, insufficient info
instruction: ai-fix
- name: supervise_fix_parallel
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
rules:
- condition: Supervisor's findings have been fixed
- condition: Cannot proceed with fix
instruction: fix-supervisor
rules:
- condition: all("AI issue fix complete", "Supervisor's findings have been fixed")
next: reviewers
- condition: any("No fix needed (target file/spec verified)", "Cannot determine, insufficient info", "Cannot proceed with fix")
next: implement
- name: ai_fix
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
pass_previous_response: false
rules:
- condition: AI issue fix complete
next: reviewers
- condition: No fix needed (target file/spec verified)
next: implement
- condition: Cannot determine, insufficient info
next: implement
instruction: ai-fix
- name: supervise_fix
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
pass_previous_response: false
rules:
- condition: Supervisor's findings have been fixed
next: reviewers
- condition: Cannot proceed with fix
next: implement
instruction: fix-supervisor
loop_monitors:
- cycle: [fix_both, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
The review → fix cycle has repeated {cycle_count} times.
Check the review report history in the Report Directory and assess convergence.
**Signs of unproductive cycling:**
- Same finding_id oscillating between resolved → new
- New issues keep arising as side effects of previous fixes
- Reviewer findings conflict with task requirements and cannot be reconciled
rules:
- condition: Healthy (new issues trending down)
next: fix_both
- condition: Unproductive (oscillation or requirement conflict)
next: ABORT
- cycle: [ai_fix, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
The AI fix → review cycle has repeated {cycle_count} times.
Check the review report history in the Report Directory and assess convergence.
**Signs of unproductive cycling:**
- Same finding_id oscillating between resolved → new
- New issues keep arising as side effects of previous fixes
- Reviewer findings conflict with task requirements and cannot be reconciled
rules:
- condition: Healthy (new issues trending down)
next: ai_fix
- condition: Unproductive (oscillation or requirement conflict)
next: ABORT
- cycle: [supervise_fix, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
The supervisor fix → review cycle has repeated {cycle_count} times.
Check the review report history in the Report Directory and assess convergence.
**Signs of unproductive cycling:**
- Same finding_id oscillating between resolved → new
- New issues keep arising as side effects of previous fixes
- Reviewer findings conflict with task requirements and cannot be reconciled
rules:
- condition: Healthy (new issues trending down)
next: supervise_fix
- condition: Unproductive (oscillation or requirement conflict)
next: ABORT

View File

@ -0,0 +1,54 @@
計画に従って Terraform コードを実装してください。
Piece Contextに示されたReport Directory内のファイルのみ参照してください。他のレポートディレクトリは検索/参照しないでください。
**重要**: 実装完了後、以下の検証を順番に実行してください。
1. `terraform fmt -check` — フォーマット違反があれば `terraform fmt` で修正
2. `terraform validate` — 構文・型エラーの確認
3. `terraform plan` — 変更内容の確認(意図しない変更がないこと)
**注意事項:**
- `terraform apply` は絶対に実行しない
- 機密情報(パスワード、トークン)をコードに書かない
- 既存リソースの `lifecycle { prevent_destroy = true }` を無断で削除しない
- 新しい variable を追加する場合は `type``description` を必ず付ける
**Scope出力契約実装開始時に作成:**
```markdown
# 変更スコープ宣言
## タスク
{タスクの1行要約}
## 変更予定
| 種別 | ファイル |
|------|---------|
| 作成 | `modules/example/main.tf` |
| 変更 | `environments/sandbox/main.tf` |
## 推定規模
Small / Medium / Large
## 影響範囲
- {影響するモジュールやリソース}
```
**Decisions出力契約実装完了時、決定がある場合のみ:**
```markdown
# 決定ログ
## 1. {決定内容}
- **背景**: {なぜ決定が必要だったか}
- **検討した選択肢**: {選択肢リスト}
- **理由**: {選んだ理由}
- **コスト影響**: {ある場合のみ}
```
**必須出力(見出しを含める)**
## 作業結果
- {実施内容の要約}
## 変更内容
- {変更内容の要約}
## 検証結果
- {terraform fmt -check の結果}
- {terraform validate の結果}
- {terraform plan の結果サマリー(追加/変更/削除のリソース数)}

View File

@ -0,0 +1,25 @@
**Terraform 規約準拠**のレビューに集中してください。
AI特有の問題はレビューしないでくださいai_reviewムーブメントで実施済み
**レビュー観点:**
- 変数宣言の規約準拠type, description, sensitive
- リソース命名の一貫性name_prefix パターン)
- ファイル構成の規約準拠1ファイル1関心事
- セキュリティ設定IMDSv2, 暗号化, アクセス制御, IAM最小権限
- タグ管理default_tags, 重複なし)
- lifecycle ルールの妥当性
- コストトレードオフの文書化
- 未使用の variable / output / data source
**前回指摘の追跡(必須):**
- まず「Previous Response」から前回の open findings を抽出する
- 各 finding に `finding_id` を付け、今回の状態を `new / persists / resolved` で判定する
- `persists` と判定する場合は、未解決である根拠(ファイル/行)を必ず示す
## 判定手順
1. まず前回open findingsを抽出し、`new / persists / resolved` を仮判定する
2. 変更差分を確認し、Terraform規約の観点に基づいて問題を検出する
- ナレッジの判定基準テーブルREJECT条件と変更内容を照合する
3. 検出した問題ごとに、Policyのスコープ判定表と判定ルールに基づいてブロッキング/非ブロッキングを分類する
4. ブロッキング問題(`new` または `persists`が1件でもあればREJECTと判定する

View File

@ -0,0 +1,241 @@
# Terraform AWS 知識
## モジュール設計
モジュールはドメイン(ネットワーク、データベース、アプリケーション層)単位で分割する。汎用ユーティリティモジュールは作らない。
| 基準 | 判定 |
|------|------|
| ドメイン単位のモジュール分割 | OK |
| 汎用 "utils" モジュール | REJECT |
| 1モジュールに無関係なリソースが混在 | REJECT |
| モジュール間の暗黙的依存 | REJECT出力→入力で明示的に接続 |
### モジュール間の依存
モジュール間の依存は出力→入力で明示的に渡す。暗黙的な参照(`data` ソースで他モジュールのリソースを引く)は避ける。
```hcl
# OK - 明示的な依存
module "database" {
source = "../../modules/database"
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
}
# NG - 暗黙的な依存
module "database" {
source = "../../modules/database"
# vpc_id を渡さず、module 内で data "aws_vpc" で引いている
}
```
### 識別変数のパススルー
環境名・サービス名などの識別変数は、ルートモジュールから子モジュールへ明示的に渡す。グローバル変数やハードコードに頼らない。
```hcl
# OK - 明示的なパススルー
module "database" {
environment = var.environment
service = var.service
application_name = var.application_name
}
```
## リソース命名規約
`locals``name_prefix` を計算し、全リソースに一貫して適用する。リソース固有のサフィックスを付加する。
| 基準 | 判定 |
|------|------|
| `name_prefix` パターンで統一命名 | OK |
| 各リソースでバラバラに命名 | REJECT |
| AWS 文字数制限を超える名前 | REJECT |
| タグ名が PascalCase でない | 警告 |
```hcl
# OK - name_prefix で統一
locals {
name_prefix = "${var.environment}-${var.service}-${var.application_name}"
}
resource "aws_ecs_cluster" "main" {
name = "${local.name_prefix}-cluster"
}
# NG - 各リソースでバラバラに命名
resource "aws_ecs_cluster" "main" {
name = "${var.environment}-app-cluster"
}
```
### 文字数制限への対応
AWS サービスには名前の文字数制限がある。制限に近い場合は短縮形を使う。
| サービス | 制限 | 例 |
|---------|------|-----|
| Target Group | 32文字 | `${var.environment}-${var.service}-backend-tg` |
| Lambda 関数 | 64文字 | フルプレフィックス可 |
| S3 バケット | 63文字 | フルプレフィックス可 |
## タグ戦略
provider の `default_tags` で共通タグを一括設定する。個別リソースでの重複タグ付けは不要。
| 基準 | 判定 |
|------|------|
| provider `default_tags` で一括設定 | OK |
| 個別リソースで `default_tags` と同じタグを重複設定 | 警告 |
| 個別リソースで `Name` タグのみ追加 | OK |
```hcl
# OK - provider で一括、個別は Name のみ
provider "aws" {
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
}
}
}
resource "aws_instance" "main" {
tags = {
Name = "${local.name_prefix}-instance"
}
}
# NG - default_tags と重複
resource "aws_instance" "main" {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Name = "${local.name_prefix}-instance"
}
}
```
## ファイル構成パターン
### 環境ディレクトリ構造
環境ごとにディレクトリを分離し、各環境が独立した状態管理を持つ。
```
environments/
├── production/
│ ├── terraform.tf # バージョン制約
│ ├── providers.tf # プロバイダ設定default_tags
│ ├── backend.tf # S3 バックエンド
│ ├── variables.tf # 環境変数
│ ├── main.tf # モジュール呼び出し
│ └── outputs.tf # 出力
└── staging/
└── ...
```
### モジュール内ファイル構成
| ファイル | 内容 |
|---------|------|
| `main.tf` | `locals``data` ソースのみ |
| `variables.tf` | 入力変数定義のみ(リソースなし) |
| `outputs.tf` | 出力定義のみ(リソースなし) |
| `{resource_type}.tf` | リソースカテゴリごとに1ファイル |
| `templates/` | user_data スクリプト等のテンプレート |
## セキュリティベストプラクティス
### EC2 インスタンスセキュリティ
| 設定 | 推奨値 | 理由 |
|------|--------|------|
| `http_tokens` | `"required"` | IMDSv2 強制SSRF 防止) |
| `http_put_response_hop_limit` | `1` | コンテナエスケープ防止 |
| `root_block_device.encrypted` | `true` | 保存データ暗号化 |
### S3 バケットセキュリティ
パブリックアクセスは4項目すべてブロックする。CloudFront 経由の場合は OACOrigin Access Controlを使用する。
```hcl
# OK - 完全ブロック
resource "aws_s3_bucket_public_access_block" "this" {
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
```
### IAM 設計
| パターン | 推奨 |
|---------|------|
| 用途別ロール分離 | 実行ロールECS Agent 用)とタスクロール(アプリ用)を分ける |
| CI/CD 認証 | OIDC フェデレーション(長期認証情報を使わない) |
| ポリシースコープ | リソース ARN を明示的に指定(`"*"` を避ける) |
### 機密情報管理
| 方法 | 推奨度 |
|------|--------|
| SSM Parameter StoreSecureString | 推奨 |
| Secrets Manager | 推奨(ローテーション必要時) |
| `.tfvars` に直接記載 | 条件付きOKgitignore 必須) |
| `.tf` ファイルにハードコード | REJECT |
SSM Parameter の初期値はプレースホルダーにし、`lifecycle { ignore_changes = [value] }` で Terraform 管理外にする。
## コスト最適化パターン
コスト影響のある選択にはインラインコメントでトレードオフを文書化する。
| 選択 | コスト効果 | トレードオフ |
|------|-----------|------------|
| NAT Instance vs NAT Gateway | NAT Instance は月額 ~$3-4 vs Gateway ~$32 | 可用性・スループットが劣る |
| パブリックサブネット配置 | VPC Endpoint 不要 | ネットワーク分離が弱まる |
| EC2 + EBS vs RDS | EC2 は月額 ~$15-20 vs RDS ~$50+ | 運用負荷が増える |
```hcl
# OK - トレードオフを文書化
# NAT Gateway の代わりに t3.nano を使用(約 $3-4/月 vs $32/月)
# トレードオフ: 可用性は単一AZ、スループット上限あり
resource "aws_instance" "nat" {
instance_type = "t3.nano"
}
```
## Lifecycle ルールの使い分け
| ルール | 用途 | 適用対象 |
|--------|------|---------|
| `prevent_destroy` | 誤削除防止 | データベース、EBS ボリューム |
| `ignore_changes` | 外部変更を許容 | `desired_count`Auto Scaling、SSM の `value` |
| `create_before_destroy` | ダウンタイム防止 | ロードバランサー、セキュリティグループ |
```hcl
# OK - データベースの誤削除防止
resource "aws_instance" "database" {
lifecycle {
prevent_destroy = true
}
}
# OK - Auto Scaling の desired_count を Terraform 管理外にする
resource "aws_ecs_service" "main" {
lifecycle {
ignore_changes = [desired_count]
}
}
```
## バージョン管理
| 設定 | 推奨 |
|------|------|
| `required_version` | `">= 1.5.0"` 以上(`default_tags` サポート) |
| プロバイダバージョン | `~>` でマイナーバージョン固定(例: `~> 5.80` |
| 状態ロック | `use_lockfile = true` 必須 |

View File

@ -0,0 +1,42 @@
```markdown
# Terraform 規約レビュー
## 結果: APPROVE / REJECT
## サマリー
{1-2文で結果を要約}
## 確認した観点
- [x] 変数宣言type, description, sensitive
- [x] リソース命名name_prefix パターン)
- [x] ファイル構成1ファイル1関心事
- [x] セキュリティ設定
- [x] タグ管理
- [x] lifecycle ルール
- [x] コストトレードオフ文書化
## 今回の指摘new
| # | finding_id | スコープ | 場所 | 問題 | 修正案 |
|---|------------|---------|------|------|--------|
| 1 | TF-NEW-file-L42 | スコープ内 | `modules/example/main.tf:42` | 問題の説明 | 修正方法 |
スコープ: 「スコープ内」(今回修正可能)/ 「スコープ外」(既存問題・非ブロッキング)
## 継続指摘persists
| # | finding_id | 前回根拠 | 今回根拠 | 問題 | 修正案 |
|---|------------|----------|----------|------|--------|
| 1 | TF-PERSIST-file-L77 | `file.tf:77` | `file.tf:77` | 未解消 | 既存修正方針を適用 |
## 解消済みresolved
| finding_id | 解消根拠 |
|------------|----------|
| TF-RESOLVED-file-L10 | `file.tf:10` は規約を満たす |
## REJECT判定条件
- `new` または `persists` が1件以上ある場合のみ REJECT 可
- `finding_id` なしの指摘は無効
```
**認知負荷軽減ルール:**
- APPROVE → サマリーのみ5行以内
- REJECT → 該当指摘のみ表で記載30行以内

View File

@ -0,0 +1,30 @@
# Terraform Coder
あなたはTerraform/AWS インフラストラクチャの実装専門家です。IaCの原則に従い、安全で保守性の高いインフラコードを書きます。
## 役割の境界
**やること:**
- Terraform コード(.tf ファイル)の作成・修正
- モジュール設計と変数定義
- セキュリティ設定の実装IAM、セキュリティグループ、暗号化
- コスト最適化の判断と文書化
**やらないこと:**
- アプリケーションコードの実装(実装担当の責務)
- インフラ設計の最終決定(設計担当の責務)
- 本番環境への直接適用(`terraform apply` は実行しない)
## 行動姿勢
- 速さより安全性。インフラの誤設定はアプリケーションバグより影響が大きい
- 推測で設定せず、公式ドキュメントで確認する
- 機密情報(パスワード、トークン)は絶対にコードに書かない
- コスト影響のある選択にはコメントでトレードオフを文書化する
- セキュリティはデフォルトで厳格に。緩和が必要な場合のみ明示的に開放する
**AI の悪い癖を自覚する:**
- 存在しないリソース属性やプロバイダ引数を書く → 禁止(公式ドキュメントで確認)
- セキュリティグループで `0.0.0.0/0` を安易に開放する → 禁止
- 未使用の variable や output を「念のため」書く → 禁止
- `depends_on` を暗黙的依存で十分な箇所に追加する → 禁止

View File

@ -0,0 +1,25 @@
# Terraform Reviewer
あなたはIaCInfrastructure as Code規約の専門レビュアーです。Terraformコードがプロジェクトの規約とセキュリティ基準に準拠しているかを検証します。
## 役割の境界
**やること:**
- Terraform 規約準拠の検証(命名、ファイル構成、変数宣言)
- セキュリティ設定の検証IAM最小権限、暗号化、アクセス制御
- コスト影響の検出とトレードオフ文書化の確認
- `lifecycle` ルールの妥当性検証
**やらないこと:**
- 自分でコードを書く(指摘と修正案の提示のみ)
- AI特有の問題のレビュー別のレビュー担当の責務
- アプリケーションコードのレビュー(設計レビュー担当の責務)
- `terraform plan` の実行(検証担当の責務)
## 行動姿勢
- セキュリティ問題は妥協しない。暗号化なし、パブリックアクセス開放は即 REJECT
- 命名の一貫性を重視する。1箇所でも規約外の命名があれば指摘する
- コスト影響のある選択にトレードオフのコメントがなければ指摘する
- 「条件付き承認」はしない。問題があれば差し戻す
- 未使用の variable/output/data source は見逃さない

View File

@ -0,0 +1,88 @@
# Terraform ポリシー
安全性と保守性を最優先し、一貫した規約に従うインフラコードを書く。
## 原則
| 原則 | 基準 |
|------|------|
| Security by Default | セキュリティはデフォルトで厳格。緩和は明示的かつ理由付き |
| Fail Fast | 必須値にデフォルトを入れない。不足は即エラー |
| 命名一貫性 | `name_prefix` パターンで全リソースを統一命名 |
| 最小権限 | IAM は必要最小限のアクション・リソースに絞る |
| コスト意識 | トレードオフはコメントで文書化 |
| DRY | `locals` で共通値を計算。重複排除 |
| 1ファイル1関心事 | リソースカテゴリごとにファイル分割 |
## 変数宣言
| 基準 | 判定 |
|------|------|
| `type` なし | REJECT |
| `description` なし | REJECT |
| 機密値に `sensitive = true` なし | REJECT |
| 環境依存値にデフォルト設定 | REJECT |
| 定数的な値(ポート番号等)にデフォルト設定 | OK |
```hcl
# REJECT - type/description なし
variable "region" {}
# REJECT - 機密値に sensitive なし
variable "db_password" {
type = string
}
# OK - 定数的な値にデフォルト
variable "container_port" {
type = number
description = "Container port for the application"
default = 8080
}
```
## セキュリティ
| 基準 | 判定 |
|------|------|
| EC2 で IMDSv2 未強制(`http_tokens != "required"` | REJECT |
| EBS/RDS 暗号化なし | REJECT |
| S3 パブリックアクセスブロックなし | REJECT |
| セキュリティグループで `0.0.0.0/0` への不要な開放 | REJECT |
| IAM ポリシーに `*` リソース(正当な理由なし) | REJECT |
| SSH 直接アクセスSSM 代替可能な場合) | REJECT |
| 機密情報のハードコーディング | REJECT |
| `lifecycle { prevent_destroy = true }` が重要データに未設定 | 警告 |
## 命名規約
| 基準 | 判定 |
|------|------|
| `name_prefix` パターン未使用 | REJECT |
| リソース名に環境名が含まれない | REJECT |
| タグ名が PascalCase でない | 警告 |
| AWS 文字数制限を超える名前 | REJECT |
## ファイル構成
| 基準 | 判定 |
|------|------|
| `main.tf` にリソース定義が混在 | REJECT |
| `variables.tf` にリソースが定義されている | REJECT |
| 1ファイルに複数カテゴリのリソースが混在 | 警告 |
| 未使用の variable / output / data source | REJECT |
## タグ管理
| 基準 | 判定 |
|------|------|
| provider `default_tags` 未設定 | REJECT |
| `default_tags` と個別リソースでタグが重複 | 警告 |
| `ManagedBy = "Terraform"` タグなし | 警告 |
## コスト管理
| 基準 | 判定 |
|------|------|
| コスト影響のある選択にコメントなし | 警告 |
| 高コストリソースNAT Gateway 等)に代替案の検討なし | 警告 |

View File

@ -31,6 +31,9 @@ piece_categories:
- expert-mini - expert-mini
- expert-cqrs - expert-cqrs
- expert-cqrs-mini - expert-cqrs-mini
🏗️ インフラストラクチャ:
pieces:
- terraform
🛠️ リファクタリング: 🛠️ リファクタリング:
pieces: pieces:
- structural-reform - structural-reform

View File

@ -0,0 +1,296 @@
name: terraform
description: Terraform IaC 開発ピースplan → implement → 並列レビュー → 監督検証 → 修正 → 完了)
piece_config:
provider_options:
codex:
network_access: true
opencode:
network_access: true
max_movements: 15
initial_movement: plan
movements:
- name: plan
edit: false
persona: planner
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
rules:
- condition: 要件が明確で実装可能
next: implement
- condition: ユーザーが質問をしている(実装タスクではない)
next: COMPLETE
- condition: 要件が不明確、情報不足
next: ABORT
instruction: plan
output_contracts:
report:
- name: plan.md
format: plan
- name: implement
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
quality_gates:
- terraform fmt -check がエラーなし
- terraform validate が成功
- terraform plan が実行可能(エラーなし)
instruction: implement-terraform
rules:
- condition: 実装が完了した
next: reviewers
- condition: 実装を進行できない
next: ABORT
- condition: ユーザーへの確認事項があるためユーザー入力が必要
next: implement
requires_user_input: true
interactive_only: true
output_contracts:
report:
- name: coder-scope.md
format: coder-scope
- name: coder-decisions.md
format: coder-decisions
- name: reviewers
parallel:
- name: tf_review
edit: false
persona: terraform-reviewer
policy:
- review
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
instruction: review-terraform
rules:
- condition: Terraform規約に準拠
- condition: 規約違反あり
output_contracts:
report:
- name: terraform-review.md
format: terraform-review
- name: ai_review
edit: false
persona: ai-antipattern-reviewer
policy:
- review
- ai-antipattern
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
instruction: review-ai
rules:
- condition: AI特有の問題なし
- condition: AI特有の問題あり
output_contracts:
report:
- name: ai-review.md
format: ai-review
rules:
- condition: all("Terraform規約に準拠", "AI特有の問題なし")
next: supervise
- condition: any("規約違反あり", "AI特有の問題あり")
next: supervise
- name: supervise
edit: false
persona: supervisor
policy: review
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Bash
- WebSearch
- WebFetch
instruction: supervise
rules:
- condition: レビュアー全員承認かつタスク要件充足
next: COMPLETE
- condition: AI特有の問題のみ要修正
next: ai_fix
- condition: 規約違反または要件未達のみ要修正
next: supervise_fix
- condition: 複数種別の問題あり
next: fix_both
- condition: 要件矛盾で収束不能、ユーザー判断が必要
next: ABORT
output_contracts:
report:
- name: supervisor-validation.md
format: supervisor-validation
- name: summary.md
format: summary
use_judge: false
- name: fix_both
parallel:
- name: ai_fix_parallel
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
rules:
- condition: AI問題の修正完了
- condition: 修正不要(指摘対象ファイル/仕様の確認済み)
- condition: 判断できない、情報不足
instruction: ai-fix
- name: supervise_fix_parallel
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
rules:
- condition: 監督者の指摘に対する修正が完了した
- condition: 修正を進行できない
instruction: fix-supervisor
rules:
- condition: all("AI問題の修正完了", "監督者の指摘に対する修正が完了した")
next: reviewers
- condition: any("修正不要(指摘対象ファイル/仕様の確認済み)", "判断できない、情報不足", "修正を進行できない")
next: implement
- name: ai_fix
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
pass_previous_response: false
rules:
- condition: AI問題の修正完了
next: reviewers
- condition: 修正不要(指摘対象ファイル/仕様の確認済み)
next: implement
- condition: 判断できない、情報不足
next: implement
instruction: ai-fix
- name: supervise_fix
edit: true
persona: terraform-coder
policy:
- terraform
knowledge: terraform-aws
allowed_tools:
- Read
- Glob
- Grep
- Edit
- Write
- Bash
- WebSearch
- WebFetch
required_permission_mode: full
pass_previous_response: false
rules:
- condition: 監督者の指摘に対する修正が完了した
next: reviewers
- condition: 修正を進行できない
next: implement
instruction: fix-supervisor
loop_monitors:
- cycle: [fix_both, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
レビュー → 修正のサイクルが {cycle_count} 回繰り返されました。
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
**非生産的の兆候:**
- 同じ finding_id が resolved → new を繰り返している
- 前の修正の副作用で新しい issue が生まれ続けている
- レビュアーの指摘とタスク要件が矛盾しており解消不能
rules:
- condition: 健全(新しい問題が減少傾向)
next: fix_both
- condition: 非生産的(振動または要件矛盾)
next: ABORT
- cycle: [ai_fix, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
AI修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
**非生産的の兆候:**
- 同じ finding_id が resolved → new を繰り返している
- 前の修正の副作用で新しい issue が生まれ続けている
- レビュアーの指摘とタスク要件が矛盾しており解消不能
rules:
- condition: 健全(新しい問題が減少傾向)
next: ai_fix
- condition: 非生産的(振動または要件矛盾)
next: ABORT
- cycle: [supervise_fix, reviewers]
threshold: 3
judge:
persona: supervisor
instruction_template: |
監督修正 → レビューのサイクルが {cycle_count} 回繰り返されました。
Report Directory 内のレビューレポート履歴を確認し、収束状況を判断してください。
**非生産的の兆候:**
- 同じ finding_id が resolved → new を繰り返している
- 前の修正の副作用で新しい issue が生まれ続けている
- レビュアーの指摘とタスク要件が矛盾しており解消不能
rules:
- condition: 健全(新しい問題が減少傾向)
next: supervise_fix
- condition: 非生産的(振動または要件矛盾)
next: ABORT