CloudFormation 漂移检测的检测范围 - 追踪手动变更的机制与局限

详细介绍 CloudFormation 漂移检测内部如何比较资源当前状态与模板期望状态、可检测变更与不可检测变更的边界以及漂移修复策略。

什么是漂移 - 模板与现实的偏差

CloudFormation 的漂移是指堆栈模板中定义的期望状态与资源实际状态不一致的情况。例如,模板中将 EC2 实例的实例类型定义为 t3.medium,但有人通过控制台将其更改为 t3.large,此时就发生了漂移。漂移是 Infrastructure as Code(IaC)的根本性挑战。即使通过模板管理基础设施,如果通过控制台或 CLI 进行了手动变更,模板与现实就会产生偏差。下次更新堆栈时,手动变更可能被覆盖导致意外行为,或者模板变更与手动变更冲突导致错误。漂移检测是 2018 年引入的功能,用于检测并可视化这种偏差。

漂移检测的内部工作原理

执行漂移检测时,CloudFormation 会对堆栈中的每个资源执行以下处理。第一,从模板读取期望状态。模板中定义的属性值即为期望状态。第二,通过 AWS API 获取各资源的实际状态。EC2 实例使用 DescribeInstances,S3 存储桶使用 GetBucketPolicy 和 GetBucketEncryption 等,根据资源类型调用相应的 API。第三,按属性逐一比较期望状态和实际状态。存在差异的属性报告为 MODIFIED。模板中未定义但已添加的属性报告为 ADD,模板中已定义但被删除的属性报告为 REMOVE。漂移检测是异步处理。对于大规模堆栈(数百个资源),获取所有资源状态可能需要数分钟。由于各资源的 API 调用存在限流约束,会在控制并行度的同时顺序处理。

可检测的变更与不可检测的变更

漂移检测存在重要限制。第一,并非所有资源类型都支持漂移检测。截至 2024 年,约 500 种资源类型中,支持漂移检测的约有 300 种。不支持的资源类型不在漂移检测范围内,报告为 NOT_CHECKED。第二,仅模板中明确定义的属性才是比较对象。模板中省略而使用默认值的属性,即使被手动更改也不会被检测为漂移。例如,模板中省略了 EC2 实例的 Monitoring 属性(默认值:false),即使从控制台启用了详细监控也不会被检测为漂移。第三,可以检测资源的删除,但无法检测在堆栈外创建的资源。即使有人手动启动了与堆栈无关的 EC2 实例,CloudFormation 也不会知道。检测堆栈外的资源需要使用 AWS Config

漂移修复策略

检测到漂移后,有 3 种修复方法。第一,撤销手动变更。如果模板定义正确且手动变更是错误的,更新堆栈(不更改模板和参数)即可让 CloudFormation 将资源恢复到模板状态。但需注意,某些属性的更改会导致资源替换(Replace)。第二,使模板与现实一致。如果手动变更是合理的(如紧急响应中更改的设置),则更新模板以反映实际状态。使用 CloudFormation 的导入功能,还可以将手动创建的资源纳入堆栈。第三,容忍漂移。某些属性(如 Auto Scaling Group 的 DesiredCapacity)在运行中会动态变更。这些属性的漂移是正常行为,无需修复。

防止漂移的机制

与其检测漂移,不如构建从根本上防止漂移发生的机制更为有效。CloudFormation 的堆栈策略可以禁止特定资源的更新。但堆栈策略仅在堆栈更新时生效,无法防止通过控制台或 CLI 的直接变更。通过 IAM 策略禁止 CloudFormation 以外的资源变更是最可靠的方法。例如,设置策略仅允许 CloudFormation 的服务角色调用 EC2 实例的 ModifyInstanceAttribute 操作,拒绝用户的直接调用。使用 AWS Config 规则持续监控漂移也很有效。cloudformation-stack-drift-detection-check 规则会定期执行漂移检测,将检测到漂移的堆栈报告为不合规。结合 Config 的修复操作(Remediation Action),还可以实现漂移的自动修复。如果想系统学习 IaC 运维,可以参考专业书籍(Amazon)