tf-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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

tf-best-practices — 生成式IaC态势规则 + 只读策略检查门

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)
这是一个共享编写指南与判定结果生成工具,而非工作流。它为生成AWS Terraform的阶段解答两个问题:
  1. 写入前 — “生成的
    terraform/
    必须遵循何种安全态势?” (态势规则 +
    baseline.tf
    账户加固规范)
  2. 写入后 — “生成的
    terraform/
    是否符合策略要求?”(确定性的 只读判定结果 + 机器可读报告)

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 contextLoadWhy
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.
该Skill在调用方的生成流程中的两个节点被触发,中间穿插调用方自身的Terraform编写工作。调用方加载该Skill时需声明当前所处的节点,并读取对应内容:
调用方上下文加载内容原因
即将编写
terraform/
(写入前)
第一部分 →
references/security-posture-rules.md
“应生成内容”的AWS编写规则(检查门强制执行 + 仅编写阶段适用 + 合规条件触发)。
terraform/
已编写完成,待验证
(写入后)
第二部分 →
references/terraform-validation.md
+ 运行检查门脚本
fmt → init → validate → policy
协议及只读判定结果。
该Skill的所有内容均与源云厂商无关(仅针对AWS Terraform)。任何GCP/Heroku的检测或工件读取工作均由调用方负责;当规则需要调用方已知的信息(如声明的合规框架)时,调用方需将其作为调用方上下文信号传入——详见
references/security-posture-rules.md
中的_调用方上下文信号_章节。

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.
本单元仅作为判定结果生成工具,绝不修改任何内容。其唯一的输出是被要求生成的JSON判定结果。具体而言,它绝不能
  • 编辑、格式化或重写任何
    .tf
    文件(修复工作由调用方负责),
  • 读取或写入
    .phase-status.json
    或任何运行状态文件(由解释器负责),
  • 决定阶段是否可完成,或向用户发起提示(由调用方策略决定)。
调用方(迁移Skill的生成阶段)负责:编辑生成的
.tf
文件的修复重试循环、自动应用
terraform fmt
、重试/跳过/终止提示、阶段完成检查门,以及所有
.phase-status.json
的写入操作。请查看消费Skill的生成阶段,了解判定结果如何为这些决策提供依据。
消费者(v1版本):
gcp-to-aws
。该契约与源厂商无关,设计目的是后续供
heroku-to-aws
使用,但目前暂时不涉及相关对接工作。

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

第一部分 — 编写态势(写入
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).
生成符合
references/security-posture-rules.md
中态势要求的Terraform。
这些是“优质AWS Terraform应具备的特征”规则。遵循这些规则可确保第二部分的检查门直接通过。本单元不会读取调用方的工件——仅使用调用方传入的上下文信号。
范围说明。
security-posture-rules.md
分为三个层级:
  • 检查门强制执行(第二部分静态验证):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 — Policy gate (run after writing
terraform/
)

第二部分 — 策略检查门(写入
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:
bash
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.
针对生成的目录运行只读检查工具。脚本路径需相对于插件根目录解析(
$PLUGIN_ROOT/skills/tf-best-practices/scripts/...
),与插件其他脚本的约定一致:
bash
python3 "$PLUGIN_ROOT/skills/tf-best-practices/scripts/validate-terraform-policy.py" "$TERRAFORM_DIR" --json "$VERDICT_PATH"
  • $TERRAFORM_DIR
    必填,由调用方提供:生成的
    terraform/
    目录 (例如
    $MIGRATION_DIR/terraform
    )。该Skill绝不会默认或自动发现路径——调用方必须传入其写入Terraform的路径。
  • --json $VERDICT_PATH
    — 可选;将机器可读的判定结果写入指定路径,供调用方合并至自身的
    validation-report.json
策略检查是更大范围验证流程(
fmt → init → validate → policy
)中的一个阶段。完整协议——包括离线 fallback 行为以及策略判定结果如何映射至
validation-report.json
——详见
references/terraform-validation.md
。该协议为描述性协议:调用方负责执行fmt/init/validate、修复重试循环以及报告写入;本单元仅提供只读策略阶段+判定结果格式。

Exit codes → caller action

退出码 → 调用方操作

ExitstdoutMeaningCaller does
0
POLICY_OK
posture satisfiedproceed
1
POLICY_FAIL
violations presentread
violations[]
, edit the named
.tf
sites, re-run (caller's retry budget)
2
(usage error)bad path / IOsurface to user; do not treat as pass
退出码标准输出含义调用方操作
0
POLICY_OK
符合态势要求继续执行
1
POLICY_FAIL
存在违规项读取
violations[]
,编辑指定的
.tf
文件位置,重新运行(调用方自行控制重试次数)
2
(使用错误)路径错误/IO异常向用户展示错误信息;不视为验证通过

Verdict shape (
--json
)

判定结果格式(
--json
参数)

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.
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 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.
所有规则均采用模糊情况放行原则——仅在存在明确的块内字面证据时触发,因此有效的栈绝不会被误拦截(
POLICY_FAIL
是调用方的硬性完成检查门,误报会阻碍真实迁移工作)。
面向公网的ALB TLS态势(当
internal
字段缺失、为
false
或由变量驱动时,ALB被视为面向公网——采用安全容错原则):
  • alb_https_listener
    — 必须在
    443
    端口配置HTTPS监听器,且包含
    certificate_arn
    forward
    动作。
  • alb_http_redirect
    — HTTP
    :80
    端口的监听器必须重定向至HTTPS,绝不能
    forward
    至目标。内部ALBs(
    internal = true
    )可豁免此规则。
托管数据库暴露与加密
aws_db_instance
aws_rds_cluster
):
  • rds_not_public
    — 不得设置
    publicly_accessible = true
    (字段缺失/由变量驱动则放行)。
  • rds_encryption_at_rest
    — 必须设置
    storage_encrypted = true
    ;字段缺失或字面为
    false
    则触发规则(RDS默认未加密),由变量驱动则放行。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
    — 覆盖
    5432
    /
    3306
    端口的内联
    aws_security_group
    入站规则,不得允许
    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
    。Web端口(
    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 (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.
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.yaml
中的
skip-path
排除在仓库范围的
checkov
扫描之外;请勿“加固”这些数据——否则会破坏断言失败路径的测试。

Verification

验证方法

bash
undefined
bash
undefined

from skills/tf-best-practices/

进入skills/tf-best-practices/目录

uv run --python 3.12 --with pytest python -m pytest scripts/test_validate_terraform_policy.py -q
undefined
uv run --python 3.12 --with pytest python -m pytest scripts/test_validate_terraform_policy.py -q
undefined