Phase 5a:静态检查(tflint / checkov)¶
目标¶
在 apply 之前,用工具自动发现代码的问题。
| 工具 | 检查什么 |
|---|---|
| tflint | Terraform 的写法:版本约束、没用到的变量、缺 description 等 |
| checkov | 安全设置:加密、metadata 服务、网络开放范围等 |
安装¶
winget install --id TerraformLinters.tflint -e # 新开的 shell 里 PATH 才生效
python -m pip install --user checkov # exe 不在 PATH 里 → 用 python -m checkov.main 执行
OCI 没有官方的 tflint ruleset → 只用 Terraform 语言本身的规则(plugin "terraform",内置)。
执行¶
tflint --recursive --config "$PWD\.tflint.hcl"
$env:PYTHONUTF8 = '1' # ← 必须,见下面的坑
python -m checkov.main -d . --framework terraform --compact
指出的问题和处理(对 Phase 4 的代码)¶
| 工具 | 指出 | 处理 |
|---|---|---|
| tflint | module 没有 required_version / provider 版本约束 |
module 里只写下限(>= 9.0),具体版本由调用方(~> 9.0)决定 |
| tflint | output 没有 description | 补上 |
| checkov CKV_OCI_5 | 旧版 metadata 服务(IMDS v1)没关 | instance_options { are_legacy_imds_endpoints_disabled = true } |
| checkov CKV_OCI_4 | boot volume 的传输中加密没开 | launch_options { is_pv_encryption_in_transit_enabled = true } |
| checkov CKV_OCI_21 | NSG 的 ingress 规则不是 stateless | 不改,用 skip 注释写明理由 |
- IMDS v1 不需要 token,SSRF 攻击时容易被利用(和 AWS 的 IMDSv2 是同一个问题)
- 修改后:tflint 0 条,checkov 通过 18 / 失败 0 / skip 3
有意不改的就写 skip 注释¶
resource "oci_core_network_security_group_security_rule" "lb_http_from_my_ip" {
#checkov:skip=CKV_OCI_21:Low traffic lab; stateful rules are simpler and sufficient
...
}
stateless 规则要另外写返回流量的规则(数量翻倍、容易配错),好处只在大流量时才明显。 skip 注释 = 把"知道风险、有意不改"的决定和理由留在代码里,review 时能看到,checkov 的结果里也会显示理由。
学到的¶
静态检查通过 ≠ 安全
checkov 没有指出:Bastion 的 0.0.0.0/0、ADB 的 public endpoint、LB 只有 HTTP。
OCI 的规则比 AWS 少很多,设计层面的问题还是要靠人 review。
checkov 只认一种写法
is_pv_encryption_in_transit_enabled 在 oci_core_instance 的顶层和 launch_options 里都能写。
写在顶层 provider 能正常工作,但 checkov 还是判定失败 → 看 checkov 源码,发现只检查 launch_options 里的。
apply 时发生的事¶
- plan:
0 to add, 2 to change(in-place,私有 IP 不变) - 但 VM 被重启了 → 刚 apply 完访问 LB 是 502 Bad Gateway(两台同时重启,健康检查都没通过),几十秒后恢复
- 正式环境要一台一台改:
-target分两次 apply,或者先从 LB 的 backend 里摘掉
in-place ≠ 不停机
~(in-place)只表示 OCID 不变,不代表不重启。改什么属性会触发重启,要看 provider 文档或先在测试环境试。
坑¶
checkov:UnicodeDecodeError: 'cp932' codec can't decode
checkov 默认用 Windows 的系统编码(日文 Windows 是 cp932)读文件,中文注释就会报错。
→ $env:PYTHONUTF8 = '1'(Python 的 UTF-8 模式)。
tflint --recursive 找不到配置
子目录里没有 .tflint.hcl → 用 --config 指定绝对路径。