tf-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesetf-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:
- Before writing — "what security posture must the generated follow?" (the posture rules + the
terraform/account-hardening spec)baseline.tf - After writing — "does the generated pass policy?" (a deterministic, read-only verdict + a machine-readable report)
terraform/
这是一个共享编写指南与判定结果生成工具,而非工作流。它为生成AWS Terraform的阶段解答两个问题:
- 写入前 — “生成的必须遵循何种安全态势?” (态势规则 +
terraform/账户加固规范)baseline.tf - 写入后 — “生成的是否符合策略要求?”(确定性的 只读判定结果 + 机器可读报告)
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 context | Load | Why |
|---|---|---|
About to author | Part 1 → | The "what to emit" AWS authoring rules (gate-enforced + authoring-only + compliance-conditional). |
| Part 2 → | The |
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
§ Caller-context signals.
references/security-posture-rules.md该Skill在调用方的生成流程中的两个节点被触发,中间穿插调用方自身的Terraform编写工作。调用方加载该Skill时需声明当前所处的节点,并读取对应内容:
| 调用方上下文 | 加载内容 | 原因 |
|---|---|---|
即将编写 | 第一部分 → | “应生成内容”的AWS编写规则(检查门强制执行 + 仅编写阶段适用 + 合规条件触发)。 |
| 第二部分 → | |
该Skill的所有内容均与源云厂商无关(仅针对AWS Terraform)。任何GCP/Heroku的检测或工件读取工作均由调用方负责;当规则需要调用方已知的信息(如声明的合规框架)时,调用方需将其作为调用方上下文信号传入——详见中的_调用方上下文信号_章节。
references/security-posture-rules.mdBoundary (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 file (the caller owns remediation),
.tf - read or write or any run-state file (interpreter-owned),
.phase-status.json - 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 it generated, auto-apply, the retry/skip/abort prompt, the
Phase Completion gate, and every write. See the consuming skill's
generate phase for how the verdict feeds those decisions.
.tfterraform fmt.phase-status.jsonConsumers (v1):only. The contract is source-agnostic and designed to be adopted bygcp-to-awslater, but that wiring is intentionally out of scope for now.heroku-to-aws
本单元仅作为判定结果生成工具,绝不修改任何内容。其唯一的输出是被要求生成的JSON判定结果。具体而言,它绝不能:
- 编辑、格式化或重写任何文件(修复工作由调用方负责),
.tf - 读取或写入或任何运行状态文件(由解释器负责),
.phase-status.json - 决定阶段是否可完成,或向用户发起提示(由调用方策略决定)。
调用方(迁移Skill的生成阶段)负责:编辑生成的文件的修复重试循环、自动应用、重试/跳过/终止提示、阶段完成检查门,以及所有的写入操作。请查看消费Skill的生成阶段,了解判定结果如何为这些决策提供依据。
.tfterraform fmt.phase-status.json消费者(v1版本): 仅。该契约与源厂商无关,设计目的是后续供gcp-to-aws使用,但目前暂时不涉及相关对接工作。heroku-to-aws
Part 1 — Authoring posture (load before writing terraform/
)
terraform/第一部分 — 编写态势(写入terraform/
前加载)
terraform/Emit generated Terraform that satisfies the posture in
.
references/security-posture-rules.mdThese 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.covers, in three tiers:security-posture-rules.md
- 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):
, master-password-via-Secrets-Manager, S3 hardening, Fargate/EKS/ECR settings, private-subnet placement, backups, baseline monitoring.deletion_protection- Compliance-conditional (emitted when the caller declares
/soc2/pci/hipaa): VPC flow logs, S3 access logging, secret rotation, customer-managed KMS.fedrampStill the caller's own generation concern (candidates to migrate here later): the account-hardeninglayer (CloudTrail, GuardDuty, Config, Security Hub).baseline.tf
生成符合中态势要求的Terraform。
references/security-posture-rules.md这些是“优质AWS Terraform应具备的特征”规则。遵循这些规则可确保第二部分的检查门直接通过。本单元不会读取调用方的工件——仅使用调用方传入的上下文信号。
范围说明。分为三个层级:security-posture-rules.md
- 检查门强制执行(第二部分静态验证):ALB TLS配置、禁止数据库公网访问、RDS + ElastiCache静态加密、禁止数据库端口公网入站、禁止管理/数据存储端口公网入站、禁止通配符IAM权限。
- 仅编写阶段适用(无法通过检查门验证,但仍需遵守):
配置、 通过Secrets Manager管理主密码、S3加固、Fargate/EKS/ECR设置、私有子网部署、备份配置、基线监控。deletion_protection- 合规条件触发(当调用方声明
/soc2/pci/hipaa合规时生效): VPC流日志、S3访问日志、密钥轮换、客户管理的KMS。fedramp仍属于调用方自身生成工作的内容(后续可能迁移至此):账户加固的层(CloudTrail、GuardDuty、Config、Security Hub)。baseline.tf
Part 2 — Policy gate (run after writing terraform/
)
terraform/第二部分 — 策略检查门(写入terraform/
后运行)
terraform/Run the read-only checker against the generated directory. Resolve the script path relative to
the plugin root (), the same convention the
plugin uses for its other scripts:
$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"- — required, caller-supplied: the generated
$TERRAFORM_DIRdirectory (e.g.terraform/). This skill never defaults or discovers it — the caller always passes the path it wrote Terraform to.$MIGRATION_DIR/terraform - — optional; writes a machine-readable verdict the caller can merge into its own
--json $VERDICT_PATH.validation-report.json
The policy check is one stage of a larger validation flow ().
The full protocol — including offline-fallback behavior and how the policy verdict maps into a
— is documented in
. 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.
fmt → init → validate → policyvalidation-report.jsonreferences/terraform-validation.md针对生成的目录运行只读检查工具。脚本路径需相对于插件根目录解析(),与插件其他脚本的约定一致:
$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/)。该Skill绝不会默认或自动发现路径——调用方必须传入其写入Terraform的路径。$MIGRATION_DIR/terraform - — 可选;将机器可读的判定结果写入指定路径,供调用方合并至自身的
--json $VERDICT_PATH。validation-report.json
策略检查是更大范围验证流程()中的一个阶段。完整协议——包括离线 fallback 行为以及策略判定结果如何映射至——详见。该协议为描述性协议:调用方负责执行fmt/init/validate、修复重试循环以及报告写入;本单元仅提供只读策略阶段+判定结果格式。
fmt → init → validate → policyvalidation-report.jsonreferences/terraform-validation.mdExit codes → caller action
退出码 → 调用方操作
| Exit | stdout | Meaning | Caller does |
|---|---|---|---|
| | posture satisfied | proceed |
| | violations present | read |
| (usage error) | bad path / IO | surface to user; do not treat as pass |
| 退出码 | 标准输出 | 含义 | 调用方操作 |
|---|---|---|---|
| | 符合态势要求 | 继续执行 |
| | 存在违规项 | 读取 |
| (使用错误) | 路径错误/IO异常 | 向用户展示错误信息;不视为验证通过 |
Verdict shape (--json
)
--json判定结果格式(--json
参数)
--jsonjson
{
"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 entry is actionable evidence — + + tell the
caller exactly what to edit. The caller applies the edit; this unit only reports.
violations[]filelinefix_hintjson
{
"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[]filelinefix_hintPolicy 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 is a hard completion gate
for the caller, so a false positive would block a real migration).
POLICY_FAILInternet-facing ALB TLS posture (an ALB is internet-facing when is absent,
, or variable-driven — fail-safe):
internalfalse- — must have an HTTPS listener on
alb_https_listenerwith443and acertificate_arnaction.forward - — an HTTP
alb_http_redirectlistener must:80to HTTPS, neverredirectto targets. Internal ALBs (forward) are exempt.internal = true
Managed database exposure & encryption (, ):
aws_db_instanceaws_rds_cluster- — must not set
rds_not_public(absent/variable → fail-open).publicly_accessible = true - — must set
rds_encryption_at_rest; missing or literalstorage_encrypted = truefires (RDS defaults to unencrypted), variable-driven fails open. S3 is not checked (default SSE-S3 since Jan 2023).false
ElastiCache encryption ():
aws_elasticache_replication_group- — must set
elasticache_encryption_at_rest; missing or literalat_rest_encryption_enabled = truefires, variable-driven fails open.false(Memcached) not checked.aws_elasticache_cluster
Security group ingress:
- — an inline
db_sg_no_public_ingressingress coveringaws_security_group/5432must not allow3306or0.0.0.0/0.::/0 - — an inline ingress must not open a curated never-public admin/datastore port (
sg_no_public_admin_ingress,22,3389,6379,11211,27017/9200,9300) to5601or0.0.0.0/0. Web (::/0/80) and app/game ports are not flagged; DB ports are handled by the rule above. Both check443andcidr_blocksindependently, so a benign IPv4 list does not mask an open IPv6 one. Both: separateipv6_cidr_blocks/aws_security_group_ruleresources fail open (not correlated).aws_vpc_security_group_ingress_rule
IAM least-privilege (, , ,
):
aws_iam_policyaws_iam_role_policyaws_iam_group_policyaws_iam_user_policy- — an
no_wildcard_iamstatement must not useAllow/ActionResource."*"data sources and assume-role trust policies fail open.aws_iam_policy_document
The checker is a zero-dependency static HCL reader (no, 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 nestedterraform initblock is not a false failure.forward { ... }
所有规则均采用模糊情况放行原则——仅在存在明确的块内字面证据时触发,因此有效的栈绝不会被误拦截(是调用方的硬性完成检查门,误报会阻碍真实迁移工作)。
POLICY_FAIL面向公网的ALB TLS态势(当字段缺失、为或由变量驱动时,ALB被视为面向公网——采用安全容错原则):
internalfalse- — 必须在
alb_https_listener端口配置HTTPS监听器,且包含443和certificate_arn动作。forward - — HTTP
alb_http_redirect端口的监听器必须重定向至HTTPS,绝不能:80至目标。内部ALBs(forward)可豁免此规则。internal = true
托管数据库暴露与加密(、):
aws_db_instanceaws_rds_cluster- — 不得设置
rds_not_public(字段缺失/由变量驱动则放行)。publicly_accessible = true - — 必须设置
rds_encryption_at_rest;字段缺失或字面为storage_encrypted = true则触发规则(RDS默认未加密),由变量驱动则放行。S3不做检查(自2023年1月起默认启用SSE-S3)。false
ElastiCache加密():
aws_elasticache_replication_group- — 必须设置
elasticache_encryption_at_rest;字段缺失或字面为at_rest_encryption_enabled = true则触发规则,由变量驱动则放行。false(Memcached)不做检查。aws_elasticache_cluster
安全组入站规则:
- — 覆盖
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。Web端口(::/0/80)及应用/游戏端口不会被标记;数据库端口由上述规则处理。两个规则分别检查443和cidr_blocks,因此良性的IPv4列表不会掩盖开放的IPv6规则。另外:独立的ipv6_cidr_blocks/aws_security_group_rule资源会被放行(不做关联检查)。aws_vpc_security_group_ingress_rule
IAM最小权限原则(、、、):
aws_iam_policyaws_iam_role_policyaws_iam_group_policyaws_iam_user_policy- —
no_wildcard_iam语句不得使用Allow/Action为Resource的通配符权限。"*"数据源及角色信任策略会被放行。aws_iam_policy_document
检查工具是一个无依赖的静态HCL读取器(无需,无需下载提供商)——即使注册表不可访问也能运行。它使用括号深度匹配嵌套块,因此使用嵌套terraform init块编写的有效HTTPS监听器不会被误判为失败。forward { ... }
Fixtures (also the checker's regression suite)
测试用例(同时作为检查工具的回归测试套件)
fixtures/terraform-policy/scripts/test_validate_terraform_policy.py- — internet-facing ALB that forwards plaintext HTTP → MUST
bad-http-forward/.POLICY_FAIL - — internal ALB on HTTP → MUST
internal-alb-only/(HTTP allowed internally).POLICY_OK - — the correct pattern →
good-https-redirect/.POLICY_OK
These are deliberately non-compliant test data (never deployed). They are excluded from the
repo-wide scan via ; do not "harden" them — doing so
breaks the tests that assert the failure paths.
checkov.checkov.yamlskip-pathfixtures/terraform-policy/scripts/test_validate_terraform_policy.py- — 面向公网的ALB转发明文HTTP → 必须返回
bad-http-forward/。POLICY_FAIL - — 仅使用内部ALB的HTTP配置 → 必须返回
internal-alb-only/(内部允许HTTP)。POLICY_OK - — 正确的配置模式 → 返回
good-https-redirect/。POLICY_OK
这些是故意构造的不合规测试数据(绝不会部署)。它们通过中的排除在仓库范围的扫描之外;请勿“加固”这些数据——否则会破坏断言失败路径的测试。
.checkov.yamlskip-pathcheckovVerification
验证方法
bash
undefinedbash
undefinedfrom 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
undefineduv run --python 3.12 --with pytest python -m pytest scripts/test_validate_terraform_policy.py -q
undefined