• Projects
  • Service
  • About
  • branding.bz
  • Podcast
  • Tips
  • FAQ
  • Recruit
  • Download
  • Contact
  • branding.bz(ブランド構築SaaS)
  • DESIGN NOW(デザインメディア)
  • X
  • LinkedIn
  • Spotify
  • Facebook

213-0011 神奈川県川崎市高津区久本3-6-7-303

© 2026 ID INC. All rights reserved

claude-skills/スキル
SKILLOfficialdevelopment

tf-best-practices

プラグイン
aws-startup-advisor
ソース
GitHub で見る ↗
説明

(no description)

本文(日本語訳)

tf-best-practices — 生成Terraform向けのセキュリティ基準 + ポリシーチェック機能

共有ガイドと検証結果の出力ツールです。ワークフロー全体ではなく、AWS Terraformを生成する段階における2つの質問に答えます。

  1. 執筆前 — 「生成されたterraform/はどんなセキュリティ基準を満たすべきか?」 (セキュリティ基準ルール + baseline.tfによるアカウント強化仕様)
  2. 執筆後 — 「生成されたterraform/はポリシーをクリアするか?」 (確定的で読み取り専用の検証結果 + 機械が読める形式のレポート)

ルーティング — 現在の状況に合わせて使い分ける

このスキルは、呼び出し側がTerraform執筆を行う前後の2つの地点で利用できます。利用時に現在地を指定することで、対応する部分を読み込みます:

呼び出し側の状況 読み込む内容 理由
terraform/を執筆する直前 Part 1 → references/security-posture-rules.md 「何を出力すべきか」のAWSルール(ポリシー適用、執筆時のみ、コンプライアンス条件付き)
terraform/が完成し検証準備完了 Part 2 → references/terraform-validation.md + ゲートスクリプト実行 フォーマット → 初期化 → 検証 → ポリシーチェックの手順と読み取り専用の検証結果

このスキルが述べることはすべてクラウド種別に依存しないもの(純粋なAWS Terraform)です。GCP/Herokuの判定やファイル読み込みは呼び出し側の責任です。ルールが呼び出し側で把握できる情報(宣言されたコンプライアンスフレームワークなど)を必要とする場合、呼び出し側がシグナルとして渡します — 詳しくはreferences/security-posture-rules.mdの「呼び出し側が提供するシグナル」を参照してください。

責任範囲(最初に読んでください)

このユニットは検証結果を出力するだけで、決して書き込み処理をしません。出力は依頼された検証結果のJSONだけです。具体的に以下をしてはいけません:

  • .tfファイルの編集・フォーマット・上書き(修正は呼び出し側の責任)
  • .phase-status.jsonやその他の実行状態ファイルの読み書き(これはスキル実行エンジンの管理)
  • 段階の完了可否を決定したり、ユーザーに入力を促す(これは呼び出し側のポリシー)

呼び出し側(マイグレーションスキルの生成段階)が管理すること:生成されたTerraformを修正して再試行するループ、terraform fmtの自動適用、再試行/スキップ/中止のプロンプト、段階完了ゲート、.phase-status.jsonのすべての書き込み。検証結果がこれらの判断にどう活用されるかは、このスキルを利用する側のドキュメントを参照してください。

利用スキル(v1): 現在はgcp-to-awsのみ。設計上は元のクラウド種別に依存しないため、将来的にheroku-to-awsでも採用できますが、その実装は今のところ対象外です。

Part 1 — 執筆前のセキュリティ基準(terraform/を執筆する直前に確認)

references/security-posture-rules.mdに記載されたセキュリティ基準を満たすTerraformを生成してください。

これが「良好なAWS Terraformとは何か」というルール集です。これに従えば、Part 2のポリシーチェックは自動的にクリアします。このスキルは呼び出し側のファイルを読みません。呼び出し側が渡すシグナル情報のみを使用します。

対象範囲。 security-posture-rules.mdは3つのレベルでカバーしています:

  • ポリシー適用(Part 2で静的検証): ALB TLS、データベースの非公開化、RDS + ElastiCache保存時暗号化、データベースポートの非公開化、管理者/データストアポートの非公開化、IAMワイルドカード禁止
  • 執筆時ガイドライン(ポリシーチェックでは検証不可だが必須): deletion_protection、Secrets Managerによるマスターパスワード管理、S3強化、Fargate/EKS/ECR設定、プライベートサブネット配置、バックアップ、ベースラインモニタリング
  • コンプライアンス条件付き(呼び出し側がsoc2/pci/hipaa/fedrampを宣言したときに出力): VPCフローログ、S3アクセスログ、シークレットローテーション、カスタマー管理KMS

引き続き呼び出し側の生成時の考慮事項(将来ここに移す候補):アカウント強化層であるbaseline.tf(CloudTrail、GuardDuty、Config、Security Hub)

Part 2 — ポリシーチェック(terraform/の執筆後に実行)

読み取り専用のチェッカーを生成ディレクトリに対して実行します。スクリプトパスはプラグインルートからの相対パスで指定します(プラグインの他のスクリプトと同じ規約):

python3 "$PLUGIN_ROOT/skills/tf-best-practices/scripts/validate-terraform-policy.py" "$TERRAFORM_DIR" --json "$VERDICT_PATH"
  • $TERRAFORM_DIR — 必須(呼び出し側が指定): 生成されたterraform/ディレクトリ (例:$MIGRATION_DIR/terraform)。このスキルは自動判定や探索をしません。呼び出し側が常にパスを渡します。
  • --json $VERDICT_PATH — オプション。機械が読める形式の検証結果を出力し、呼び出し側が自分のvalidation-report.jsonにマージできます。

ポリシーチェックは大きな検証フロー(フォーマット → 初期化 → 検証 → ポリシー)の1段階です。完全な手順(オフライン時の代替動作、ポリシー検証結果をvalidation-report.jsonにどう反映するかなど)はreferences/terraform-validation.mdに記載されています。この手順は説明的なもので、呼び出し側がフォーマット/初期化/検証の実行、修正と再試行のループ、レポート出力を管理します。このスキルが提供するのは読み取り専用ポリシーチェック段階と検証結果の形式だけです。

終了コード → 呼び出し側のアクション

コード 標準出力 意味 呼び出し側の対応
0 POLICY_OK 基準を満たしている 続行
1 POLICY_FAIL 違反がある violations[]を確認し、該当ファイルを修正して再実行(呼び出し側の再試行予算内)
2 (使用方法エラー) パスの誤りやIO問題 ユーザーに通知。成功として扱わない

検証結果の形式(--json出力)

{
  "check": "policy",
  "policy_status": "POLICY_OK | POLICY_FAIL",
  "violations": [
    {
      "check": "policy",
      "rule": "alb_https_listener | alb_http_redirect | no_tf_files",
      "file": "compute.tf",
      "line": 7,
      "severity": "error",
      "summary": "人間が読める形式の違反内容",
      "fix_hint": "呼び出し側が適用できる具体的な修正方法"
    }
  ]
}

各violations[]エントリは実行可能な情報です。file + line + fix_hintで、呼び出し側は正確に何を修正するかが分かります。修正は呼び出し側が行い、このスキルは報告するだけです。

現在適用されているポリシールール

すべてのルールは曖昧さに対して見過ごす設定です。明確でブロック内の直かな証拠にのみ反応するため、有効なスタックが誤検知で止まることはありません(POLICY_FAILは呼び出し側にとって完了を阻むゲートなので、誤検知は実際のマイグレーションを止めてしまいます)。

インターネット公開ALBのTLS基準(ALBがインターネット公開の場合はinternalがない、false、または変数駆動 — 安全側に判定):

  • alb_https_listener — ポート443にHTTPSリスナーがあり、certificate_arnとforwardアクションを備えていることが必須
  • alb_http_redirect — HTTP:80リスナーはredirectでHTTPSに向け、ターゲットへのforwardは禁止。内部ALB(internal = true)は対象外

マネージドデータベースの公開防止と暗号化(aws_db_instance、aws_rds_cluster):

  • rds_not_public — publicly_accessible = trueを設定してはいけない(未設定/変数 → 見過ごす)
  • rds_encryption_at_rest — storage_encrypted = trueが必須。未設定または直かなfalse → 違反。変数駆動 → 見過ごす。S3はチェック対象外(2023年1月以降のデフォルトはSSE-S3)

ElastiCache暗号化(aws_elasticache_replication_group):

  • elasticache_encryption_at_rest — at_rest_encryption_enabled = trueが必須。未設定または直かなfalse → 違反、変数駆動 → 見過ごす。aws_elasticache_cluster(Memcached)はチェック対象外

セキュリティグループの受信ルール:

  • db_sg_no_public_ingress — インラインaws_security_groupの受信ルールが5432/3306をカバーする場合、0.0.0.0/0や::/0を許可してはいけない
  • sg_no_public_admin_ingress — インライン受信ルールが、決して公開してはいけない管理者/データストアポート(22、3389、6379、11211、27017、9200/9300、5601)を0.0.0.0/0や::/0に開放してはいけない。ウェブポート(80/443)とアプリ/ゲームポートは対象外。データベースポートは上記ルールで扱う。両者ともcidr_blocksとipv6_cidr_blocksを独立してチェックするため、IPv4が安全でもIPv6が開いていれば検知。両者とも:別リソースのaws_security_group_rule/aws_vpc_security_group_ingress_ruleは見過ごします(相関チェック不可)

IAM最小権限(aws_iam_policy、aws_iam_role_policy、aws_iam_group_policy、aws_iam_user_policy):

  • no_wildcard_iam — AllowステートメントのAction/Resourceに"*"を使ってはいけない。aws_iam_policy_documentデータソースと信頼ポリシーは見過ごします

チェッカーは依存がないシンプルなHCLリーダー(terraform initなし、プロバイダーダウンロードなし)です。レジストリが到達不可でも動作。ブレース深度マッチングを使用するため、ネストしたforward { ... }ブロックで書かれたHTTPSリスナーは誤検知になりません。

テストデータ(チェッカーの回帰テストスイート)

fixtures/terraform-policy/に意図的に作られたTerraformが入っており、scripts/test_validate_terraform_policy.pyで使われます:

  • bad-http-forward/ — インターネット公開ALBがHTTPをフォーワード → POLICY_FAIL必須
  • internal-alb-only/ — 内部ALBがHTTP → POLICY_OK必須(内部利用はHTTP許可)
  • good-https-redirect/ — 正しいパターン → POLICY_OK

これらは意図的に非準拠のテストデータ(デプロイしません)。リポジトリ全体のcheckovスキャンは.checkov.yamlのskip-pathで除外しています。「強化」してはいけません — そうするとテストを破

原文(English)を表示

tf-best-practices — Generated-IaC posture rules + read-only policy gate

A shared authoring guide and verdict producer, not a workflow. It answers two questions for a phase that generates AWS Terraform:

  1. Before writing — "what security posture must the generated terraform/ follow?" (the posture rules + the baseline.tf account-hardening spec)
  2. After writing — "does the generated terraform/ pass policy?" (a deterministic, read-only verdict + a machine-readable report)

Routing — load the part that matches your context

This skill is entered at two touchpoints in the caller's Generate flow, with the caller's own terraform-authoring work in between. The caller states which touchpoint it is at when it loads this skill, and reads the corresponding part:

Caller context Load Why
About to author terraform/ (before writing) Part 1 → references/security-posture-rules.md The "what to emit" AWS authoring rules (gate-enforced + authoring-only + compliance-conditional).
terraform/ written, ready to validate (after writing) Part 2 → references/terraform-validation.md + run the gate script The fmt → init → validate → policy protocol and the read-only verdict.

Everything this skill states is source-cloud-agnostic (pure AWS Terraform). Any GCP/Heroku detection or artifact reading is the caller's job; where a rule needs a caller-known fact (e.g. declared compliance frameworks), the caller passes it as a caller-context signal — see references/security-posture-rules.md § Caller-context signals.

Boundary (read this first)

This unit is a verdict producer, never a mutator. Its entire write surface is the JSON verdict it is asked to emit. Specifically it MUST NOT:

  • edit, format, or rewrite any .tf file (the caller owns remediation),
  • read or write .phase-status.json or any run-state file (interpreter-owned),
  • decide whether a phase may complete, or prompt the user (caller policy).

The caller (a migration skill's Generate phase) owns: the fix-and-retry loop that edits the .tf it generated, terraform fmt auto-apply, the retry/skip/abort prompt, the Phase Completion gate, and every .phase-status.json write. See the consuming skill's generate phase for how the verdict feeds those decisions.

Consumers (v1): gcp-to-aws only. The contract is source-agnostic and designed to be adopted by heroku-to-aws later, but that wiring is intentionally out of scope for now.

Part 1 — Authoring posture (load before writing terraform/)

Emit generated Terraform that satisfies the posture in references/security-posture-rules.md.

These are the "what good AWS Terraform looks like" rules. Following them makes the Part 2 gate pass by construction. This unit does not read the caller's artifacts — it consumes only caller-context signals the caller passes in.

Scope. security-posture-rules.md covers, in three tiers:

  • Gate-enforced (Part 2 verifies statically): ALB TLS, no-public-database, RDS + ElastiCache encryption-at-rest, no-public-DB-port ingress, no-public admin/datastore-port ingress, no-wildcard-IAM.
  • Authoring-only (not gate-checkable, still required): deletion_protection, master-password-via-Secrets-Manager, S3 hardening, Fargate/EKS/ECR settings, private-subnet placement, backups, baseline monitoring.
  • Compliance-conditional (emitted when the caller declares soc2/pci/hipaa/fedramp): VPC flow logs, S3 access logging, secret rotation, customer-managed KMS.

Still the caller's own generation concern (candidates to migrate here later): the account-hardening baseline.tf layer (CloudTrail, GuardDuty, Config, Security Hub).

Part 2 — Policy gate (run after writing terraform/)

Run the read-only checker against the generated directory. Resolve the script path relative to the plugin root ($PLUGIN_ROOT/skills/tf-best-practices/scripts/...), the same convention the plugin uses for its other scripts:

python3 "$PLUGIN_ROOT/skills/tf-best-practices/scripts/validate-terraform-policy.py" "$TERRAFORM_DIR" --json "$VERDICT_PATH"
  • $TERRAFORM_DIR — required, caller-supplied: the generated terraform/ directory (e.g. $MIGRATION_DIR/terraform). This skill never defaults or discovers it — the caller always passes the path it wrote Terraform to.
  • --json $VERDICT_PATH — optional; writes a machine-readable verdict the caller can merge into its own validation-report.json.

The policy check is one stage of a larger validation flow (fmt → init → validate → policy). The full protocol — including offline-fallback behavior and how the policy verdict maps into a validation-report.json — is documented in references/terraform-validation.md. That protocol is descriptive: the caller owns the fmt/init/validate execution, the fix-and-retry loop, and the report write; this unit contributes only the read-only policy stage + verdict shape.

Exit codes → caller action

Exit stdout Meaning Caller does
0 POLICY_OK posture satisfied proceed
1 POLICY_FAIL violations present read violations[], edit the named .tf sites, re-run (caller's retry budget)
2 (usage error) bad path / IO surface to user; do not treat as pass

Verdict shape (--json)

{
  "check": "policy",
  "policy_status": "POLICY_OK | POLICY_FAIL",
  "violations": [
    {
      "check": "policy",
      "rule": "alb_https_listener | alb_http_redirect | no_tf_files",
      "file": "compute.tf",
      "line": 7,
      "severity": "error",
      "summary": "human-readable violation",
      "fix_hint": "concrete remediation the caller can apply"
    }
  ]
}

Each violations[] entry is actionable evidence — file + line + fix_hint tell the caller exactly what to edit. The caller applies the edit; this unit only reports.

Policy rules enforced today

Every rule is fail-open on ambiguity — it fires only on unambiguous, in-block literal evidence, so a valid stack is never falsely blocked (a POLICY_FAIL is a hard completion gate for the caller, so a false positive would block a real migration).

Internet-facing ALB TLS posture (an ALB is internet-facing when internal is absent, false, or variable-driven — fail-safe):

  • alb_https_listener — must have an HTTPS listener on 443 with certificate_arn and a forward action.
  • alb_http_redirect — an HTTP :80 listener must redirect to HTTPS, never forward to targets. Internal ALBs (internal = true) are exempt.

Managed database exposure & encryption (aws_db_instance, aws_rds_cluster):

  • rds_not_public — must not set publicly_accessible = true (absent/variable → fail-open).
  • rds_encryption_at_rest — must set storage_encrypted = true; missing or literal false fires (RDS defaults to unencrypted), variable-driven fails open. S3 is not checked (default SSE-S3 since Jan 2023).

ElastiCache encryption (aws_elasticache_replication_group):

  • elasticache_encryption_at_rest — must set at_rest_encryption_enabled = true; missing or literal false fires, variable-driven fails open. aws_elasticache_cluster (Memcached) not checked.

Security group ingress:

  • db_sg_no_public_ingress — an inline aws_security_group ingress covering 5432/3306 must not allow 0.0.0.0/0 or ::/0.
  • sg_no_public_admin_ingress — an inline ingress must not open a curated never-public admin/datastore port (22, 3389, 6379, 11211, 27017, 9200/9300, 5601) to 0.0.0.0/0 or ::/0. Web (80/443) and app/game ports are not flagged; DB ports are handled by the rule above. Both check cidr_blocks and ipv6_cidr_blocks independently, so a benign IPv4 list does not mask an open IPv6 one. Both: separate aws_security_group_rule / aws_vpc_security_group_ingress_rule resources fail open (not correlated).

IAM least-privilege (aws_iam_policy, aws_iam_role_policy, aws_iam_group_policy, aws_iam_user_policy):

  • no_wildcard_iam — an Allow statement must not use Action/Resource "*". aws_iam_policy_document data sources and assume-role trust policies fail open.

The checker is a zero-dependency static HCL reader (no terraform init, no provider download) — it runs even when the registry is unreachable. It uses brace-depth matching for nested blocks, so a valid HTTPS listener written with a nested forward { ... } block is not a false failure.

Fixtures (also the checker's regression suite)

fixtures/terraform-policy/ holds intentionally-shaped Terraform used by scripts/test_validate_terraform_policy.py:

  • bad-http-forward/ — internet-facing ALB that forwards plaintext HTTP → MUST POLICY_FAIL.
  • internal-alb-only/ — internal ALB on HTTP → MUST POLICY_OK (HTTP allowed internally).
  • good-https-redirect/ — the correct pattern → POLICY_OK.

These are deliberately non-compliant test data (never deployed). They are excluded from the repo-wide checkov scan via .checkov.yaml skip-path; do not "harden" them — doing so breaks the tests that assert the failure paths.

Verification

# from skills/tf-best-practices/
uv run --python 3.12 --with pytest python -m pytest scripts/test_validate_terraform_policy.py -q

原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。