「漂移检测与收敛」

讲解 Terraform 漂移检测与收敛:drift 的产生成因、plan 差异审计流程、driftctl 扫描工具、自动化收敛与再漂移防护,以及合规审计与定期漂移扫描体系的设计。

1. drift 的产生成因

一句话总结: drift 是「云端现状偏离期望状态」;主要成因是手工改动、控制台操作、其他工具覆盖与资源被删除,检测的价值在于「发现偏离,而非消除所有偏离」。

Infrastructure drift(漂移)指:Terraform 声明的期望状态,与实际运行环境不一致。Terraform 的 refresh 阶段每次都会对比 state 与真实云资源,凡是「配置里没有、云上却有」或「配置写了、云上被改」的差异,都算漂移。

期望状态(代码+state)      实际状态(云端)          drift
instance_type = t3.micro    instance_type = t3.large  ✗ 属性被改
configmap 定义了 3 个 key    只剩 1 个 key            ✗ 被删
安全组放行 80/443           多放行了 22               ✗ 被加
整个 EC2 不存在              存在(手工建的)          ✗ 游离资源

1.1 六大成因

成因典型场景
控制台手工操作运维直接在 AWS 控制台改安全组
应急热修线上紧急 scale、改端口后没走 IaC
其他工具覆盖Ansible/脚本/其他 IaC 改同一资源
资源被删手工删除实例、桶、数据库
系统异步变化自动扩缩容、自动清理任务
上游变更依赖的资源被他人重建导致引用失效

1.2 漂移的两面性

漂移是「现状与声明的差」。它不全是坏事——紧急修复可能是合理的;但未被记录的漂移意味着「你以为的配置不是实际配置」,这正是事故与审计风险的温床。

2. plan 差异审计

一句话总结: terraform plan 是漂移的第一道探测器,refresh 对比后把差异输出为计划;审计 plan 是每个 CI 流水线与周期扫描的标配动作。

2.1 plan 是天然的差异报告

# 默认就刷新并对比,输出差异
terraform plan

# 只看刷新与差异,不进入计划生成细节
terraform plan -refresh-only

# 差异审计退出码:0=无差异 1=有差异 2=错误
terraform plan -detailed-exitcode
echo $?

2.2 用退出码做门禁

在 CI 里用 -detailed-exitcode 判断是否有漂移,把结果变成「可自动判定的信号」。

#!/bin/bash
set -e
terraform init -backend-config=$ENV.backend.tfvars

# 只做差异审计,不 apply
terraform plan -detailed-exitcode -out=plan.bin
exitcode=$?

if [ $exitcode -eq 1 ]; then
  echo "::warning::检测到配置差异(可能为漂移),请人工确认"
  exit 0   # 审计阶段不阻断,仅告警
fi

2.3 plan 差异的分类

差异类型是否漂移处理
配置修改引起否(期望变更)正常 apply
state 与实际不符是refresh 后判断
云上多出资源是决定纳入 or 删除
云上资源缺失是决定重建 or 接受

一句话:plan 输出的是「代码意图 vs 现状」,审计的人要能区分「这是我的改动」和「这是别人/系统造成的漂移」。

3. driftctl 扫描工具

一句话总结: driftctl 是独立于 Terraform 的漂移扫描器,直接对云端资源与 IaC 代码做覆盖比对,能发现「state 之外的游离资源」。

driftctl(现已并入 CloudSkiff/Scanner)不依赖 state 文件,它扫描云端真实资源,与 Terraform 代码声明做覆盖比对,找出未被代码管理的资源。

3.1 基本用法

# 扫描当前配置声明的资源是否与云端一致
driftctl scan

# 指定云平台 profile 与区域
driftctl scan --from aws+tf --region ap-northeast-1

# 只输出 JSON 报告
driftctl scan --output json://- > drift.json

3.2 典型输出解读

Found 3 resource(s)
 - 2 managed by IaC (Terraform)
 - 1 not managed by Terraform
   1 resource(s) drifted

Unmanaged resources:
  - aws_security_group sg-xxxx (created out of band)

Unmanaged(游离)资源就是 driftctl 的独有价值:它们连 state 里都没有,是纯手工或旁路创建的。

3.3 driftctl 与 plan 的互补

工具视角发现
terraform planstate↔云端state 内资源的属性漂移
driftctl代码↔云端未纳管的游离资源
两者结合全量属性漂移 + 游离资源全覆盖

4. 自动化收敛

一句话总结: 收敛是「把漂移拉回期望状态」,推荐「计划驱动 + 审批」的自动修复,避免直接 apply 造成不可预期变更。

4.1 收敛的三种策略

策略做法适用
手动修复人工改回/重跑 apply低频、高风险资源
自动收敛CI 定时 plan→apply可重建、低风险资源
纳入管理把游离资源 import 进 state合理资源,转为受管

4.2 自动化收敛流水线

# 伪代码:定时漂移检测与收敛
schedule: "0 3 * * *"        # 每天凌晨
steps:
  - terraform plan -detailed-exitcode
  - if drift: 生成差异报告并通知
  - approve(人工/自动门禁)
  - terraform apply
  - 复核 plan 无新漂移

4.3 收敛后再漂移的防护

  • 锁定控制台权限:高危资源禁止控制台直改,走 IaC。
  • 变更即记录:所有变更入口收敛到 PR + CI。
  • 约束工具链:其他工具只准读,不准写受管资源。
  • 标签策略:受管资源打 managed-by: terraform 标签,供扫描器识别。

5. 合规与审计

一句话总结: 漂移直接破坏合规审计——审计要的是「声明即实际」,漂移让「配置=实际」的承诺失效;因此把漂移检测接入合规门禁是治理刚需。

5.1 漂移对合规的冲击

合规要求漂移的影响
配置即真相实际与配置不一致,审计无法信任何一方
安全基线安全组被改、加密被关,基线失效
变更可追溯手工热修没有变更记录
数据保留备份策略被改,留存违规

5.2 把漂移接入合规报告

#!/bin/bash
# 合规扫描:任何漂移都生成违规记录
terraform plan -detailed-exitcode >/tmp/plan.txt
if [ $? -eq 1 ]; then
  echo "DRIFT detected at $(date)" >> compliance-drift.log
  cat /tmp/plan.txt
  exit 1   # 有漂移即不合规
fi

5.3 策略即代码

配合 OPA/Conftest,把「禁止未纳管资源」「安全组不得放行 0.0.0.0/0」等规则写进策略,扫描结果自动判合规。

# policy/drift.rego
package main

deny[msg] {
  unmanaged := input.unmanaged[_]
  msg := sprintf("未纳管资源: %v", [unmanaged.id])
}

6. 定期漂移扫描体系设计

一句话总结: 一套漂移体系 = 定期扫描 + 差异分级 + 通知分流 + 收敛与豁免,扫描频率按资源风险分级,不搞一刀切。

6.1 分级扫描频率

资源风险扫描频率收敛方式
安全敏感(IAM/SG/加密)每次 PR + 每日阻断式合规
业务核心(数据库/计算)每日告警 + 人工审批
低风险(标签/普通资源)每周定期批量收敛

6.2 扫描到收敛的闭环

定时扫描 → 差异报告 → 分级告警 → 人/自动决策 → 收敛 apply → 复扫确认

6.3 定时任务示例

扫描与收敛用 cron 或 CI 定时器驱动,频率与收敛策略按环境配置:

# crontab:每天 03:00 全量扫描,每周一 04:00 收敛低风险环境
0 3 * * *  /usr/local/bin/terraform-drift-scan --env prod
0 4 * * 1  /usr/local/bin/terraform-converge-lowrisk --env dev

6.4 豁免与噪音管理

  • 已知的合理漂移(自动扩缩容)用豁免列表排除。
  • 告警按影响面分级,避免「狼来了」导致告警疲劳。
  • 每次收敛后记录原因,形成漂移趋势报表。

7. 常见坑

一句话总结: 漂移治理的坑集中在误删真实资源、自动收敛扩大事故、扫描噪音与豁免滥用,核心是「收敛要有护栏,扫描要有区分」。

坑现象正确做法
apply 自动收敛误删手动热修的资源被删收敛前 diff 评审 + 备份
plan 噪音每次都有无关差异配置 -refresh-only 单独看漂移
豁免滥用漂移被大面积豁免豁免必须带理由与时限
driftctl 权限过大只读扫描给了写权限扫描用只读 credential
收敛竞态扫描与人工修改撞车加锁 + 非高峰窗口

7.1 安全收敛模板

#!/bin/bash
set -e
# 只对允许自动收敛的目录执行
cd "$ENV_DIR"

terraform plan -detailed-exitcode -out=plan.bin || exitcode=$?

# 有差异且非豁免 → 先记录再走审批
if [ "${exitcode:-0}" -eq 1 ]; then
  echo "drift: $(date) $ENV_DIR" >> /var/log/drift.log
  if grep -q "$ENV_DIR" /etc/terraform/auto-approve.list; then
    terraform apply -auto-approve plan.bin
  else
    echo "需人工审批,跳过收敛"
    exit 1
  fi
fi

8. 总结

漂移检测与收敛,把「声明式 IaC」的信任闭环补完:

环节要点
成因手工、热修、其他工具、删除、异步变化
检测plan 差异 + 退出码门禁
游离资源driftctl 扫描「未纳管」资源
收敛计划驱动 + 审批,避免裸 apply
合规漂移即不合规,策略即代码
体系分级扫描 + 通知 + 豁免
坑收敛护栏、只读扫描、豁免治理

一句话收尾:漂移治理的目标不是「零漂移」,而是「每个漂移都被看见、被决策、被记录」。把检测、收敛、合规与豁免串成闭环,IaC 的「声明即实际」承诺才能真正兑现。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「terraform」更多文章

  1. 「资源重构与迁移」
  2. 「数据源与远程数据读取」
  3. 「Kubernetes Provider 编排」