跳转至

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 指定绝对路径。