
最近折腾了一下 Terraform 安全审查,踩了几个坑,这篇把问题说清楚:AI(人工智能)到底能不能帮我们读扫描报告、改基础设施代码,以及怎么验证这些改动真的有效。
把安全扫描器接进流水线并不难,难的是拿到结果之后:这些告警到底意味着什么,哪些配置必须改,以及 AI 给出的修复方案能不能用。
作为 DevOps(开发运维)工程师,我想验证的是:能不能把真实基础设施扫描结果交给 GitHub Copilot,让它协助完成修复分析,同时保留原有的检查和人工审查流程。
我用一份故意写得不安全的 Azure Storage Account(存储账户)Terraform(基础设施即代码工具)配置做了实验。Azure Pipelines 负责执行扫描,Microsoft Defender for Cloud 集中展示仓库级告警,Visual Studio Code(VS Code)里的 GitHub Copilot 则负责解释结果、提出代码修改建议。
第一轮修复只带来了部分改善:流水线记录的警告数从 7 个降到了 3 个,但错误数仍然是 3 个。截图里还有一个容易忽略的细节:即使存在这些错误,构建仍然显示成功。
这次实验里最有价值的结论之一正是这个区别:扫描跑完了、流水线显示成功,并不能证明安全要求已经满足。
整个实验的重点,是部署前审查基础设施代码。基础设施即代码(Infrastructure as Code,IaC)是指把资源及其配置写进文件,由 Terraform 这类工具统一管理。本次演示覆盖的是扫描和修改代码,并没有验证一个完成加固的存储账户能否成功部署。
| 组件 | 在实验中的作用 |
|---|---|
| Azure Repos | 保存 Terraform 配置以及修改建议。 |
| Azure Pipelines 和 Microsoft Security DevOps | 执行安全分析,包括 Checkov 检查,并发布扫描结果。 |
| SARIF 报告 | 把扫描结果带入审查流程。 |
| Microsoft Defender for Cloud | 展示仓库建议,并提供指向源代码位置的链接。 |
| VS Code 中的 GitHub Copilot | 帮助解释报告并提出 Terraform 修改建议。 |
| 拉取请求和再次扫描 | 记录代码变更,并提供验证结果的方式。 |

图 1:Copilot 协助工程师审查扫描输出,Defender for Cloud 则提供集中视图。这不表示 Copilot 会自动读取或关闭 Defender for Cloud 中的建议。
这里的 AI 能力属于交互式开发流程。我会在 VS Code 中打开报告,再借助 Copilot 逐项处理扫描结果。它不是能够自行批准修复方案或执行部署的自主智能体。
我准备了一份故意采用薄弱配置的存储账户代码,让扫描器有明确的问题可以识别。示例足够小,就能更方便地从报告中的告警一路追到对应的 Terraform 配置。这类实验应放在受控的学习环境中,不要直接拿来操作生产环境。
流水线使用了 Microsoft Security DevOps 任务,演示中的扫描配置如下:
- task: MicrosoftSecurityDevOps@1 displayName: Microsoft Security DevOps Scan inputs: publish: true
这段配置只展示了结果发布,没有显式设置“发现安全问题就失败”。Microsoft Security DevOps 的扩展及分析器说明,可以参考 Microsoft Security DevOps 配置指南。
Checkov 在 Terraform 配置中识别出了一些问题,随后流水线发布了一份 SARIF(Static Analysis Results Interchange Format,静态分析结果交换格式)文件。SARIF 是一种结构化报告格式,可以记录规则标识、告警信息、严重级别和源代码位置。
有了真实扫描结果,我就可以让 Copilot 分析具体告警,而不是让它凭空猜测配置可能哪里有问题。
我把 Azure DevOps 环境连接到 Microsoft Defender for Cloud,然后在 DevOps 安全视图里检查仓库建议。
这里最有价值的是完整的问题定位链路:从一条建议跳转到对应的代码位置,能够看到仓库、分支、Terraform 文件、行号和证据链接。开发者可以据此找到告警背后的代码并展开调查。
不过,集中式仪表板和流水线摘要代表的是不同视图,两者显示的数量不能直接当成同一口径。连接配置中还会暴露无代理扫描选项,因此,把某条仪表板建议归因到某一次流水线执行之前,必须先核对扫描来源和时间戳。
观察期间,仓库级建议数记录为 11 条,没有观察到数量下降。但不能因此直接认定修改完全没有效果,也不能想当然地认为仪表板只是延迟更新。正确做法是逐条检查具体告警及其最新评估状态。
我在 VS Code 中本地查看 SARIF 报告,并使用 GitHub Copilot 总结扫描结果、建议 Terraform 修改,同时解释哪些问题仍未处理。
这里使用的是编辑器里的 GitHub Copilot,不是 Microsoft Security Copilot,这个实验也不能证明两个产品的能力完全等价。
给出的修改建议涉及公开 Blob 访问、最低 TLS(传输层安全)版本、共享密钥访问、复制和恢复设置等多个方面。但这些建议仍然需要工程师审查,因为一项安全调整可能影响应用兼容性、故障恢复能力或使用成本。
例如,在接受身份验证方式变更前,我会先确认它是否会影响现有应用;还要核对每个 Terraform 参数是否受当前 Provider(基础设施服务提供程序)版本支持,并检查基础设施变更计划。一段听起来合理的解释,既不能证明配置有效,也不能证明告警已经解决。
如果要把这个练习做成可重复执行的流程,我会使用下面这段提示词。它只是建议使用的提示词,不是原始会话记录:
Review this SARIF report alongside the Terraform configuration.
For each finding, identify the rule, resource and affected setting.
Explain the risk and propose the smallest useful fix.
Check the provider version before suggesting arguments.
Flag effects on access, networking, recovery and cost.
List anything you cannot resolve with the files provided.
Do not disable checks or label a finding fixed without validation.
要把报告和源文件交给 AI 工具,就应把它们当作待分析材料,而不是能够覆盖审查要求的指令。共享之前,必须移除密钥和无关敏感信息,并遵守对应的数据处理规范。
我在主分支上配置了必需的构建验证。捕获到的拉取请求显示,必需检查通过并成功合并。
这只能证明验证构建必须成功,并不能说明每一条不可接受的安全告警都会导致构建失败。
流水线运行摘要一边显示绿色成功状态,一边又记录了错误条目。YAML(Yet Another Markup Language,另一种标记语言)截图只开启了报告发布,没有显示显式的 break 输入项。当前任务定义将这个输入项默认设为 false,并将它定义为在出现错误级结果时让任务步骤失败的选项。
这与实验中观察到的“报告”和“阻断”差异一致。不过,仅凭截图仍无法确定每次历史运行实际使用的全部配置。
如果继续落地,我会把预期行为明确写进流水线:
# Proposed follow-up, not the recorded demo settings.
- task: MicrosoftSecurityDevOps@1 displayName: Scan infrastructure and fail on error results inputs: publish: true break: true
接下来要构造一个故意失败的用例来验证控制措施:扫描器必须产生预期告警,任务和构建必须报告失败,必需的拉取请求策略必须阻止合并。同时还要明确处理扫描器崩溃和报告缺失的情况,避免把它们误认为“扫描结果干净”。
Azure Repos 的构建验证策略会根据构建结果进行判断,但这一机制是否有效,取决于流水线能否产出正确结果,以及是否设置了合理的绕过权限限制。仅凭一次成功合并的拉取请求,不能证明失败路径有效。
捕获到的运行记录对比如下:
| 流水线摘要项 | 修改前 | 修改后 |
|---|---|---|
| 警告 | 7 | 3 |
| 错误 | 3 | 3 |

图 2:数字来自运行摘要的转录,它们是流水线条目,并不是经过独立验证的漏洞数量。
3 条错误记录中,包括 2 个有明确名称的 Checkov 扫描结果,以及 1 条扫描器汇总异常。把它们直接称为 3 个独立的阻断性漏洞,会夸大截图所能证明的内容。更关键的是,这些错误存在时,记录中的流水线运行仍然显示成功。
警告数下降是一个积极信号,但不能据此证明修复了 4 个不同的漏洞。要做可靠对比,应当按规则、资源和位置匹配扫描结果,并确认两次运行使用的代码修订、扫描器版本和配置。两次捕获的运行触发上下文并不相同,这也是结论应该保持克制的原因之一。
最终结果只能算部分修复。AI 协助推动了审查和修改,但第一轮并没有得到干净的安全基线。我没有测量节省了多少时间,所以也不会给这个结果贴上一个“提升生产力百分比”的标签。
证明合并控制确实有效。 验证一个已知不可接受的告警能够导致必需构建失败,并阻止合并。除了检测到的问题,还要测试报告缺失和工具运行失败。
验证基础设施变更。 固定 Provider 版本,校验 Terraform 配置,检查变更计划;当访问或恢复设置发生变化时,还要测试应用行为。
逐条跟踪剩余告警。 后续范围包括客户托管加密密钥、私有连接,以及存储日志和恢复设置。每个问题都需要明确是否适用、指定负责人,并留存解决证据或获批例外。暂缓处理告警,并不代表配置已经可以进入生产环境。
让每条结果对应准确的代码修订。 记录代码修订号、扫描器版本、策略版本、报告、修改建议和验证结果。审查并验证新的修订,不要依赖上一次扫描结果。
保证 AI 参与的改动可以审查。 记录为什么接受某些修改、为什么暂缓某些告警。GitHub 关于审查 AI 生成代码的指南同样强调,必须进行测试、结合上下文审查,并保留人的判断。
在这次实验中,AI 最有价值的角色,是帮助我从扫描报告走到一份可以检查和测试的修改方案。
实验还暴露了一个必须验证的控制缺口:流水线可以执行安全扫描、发布告警,最后仍然成功。在把它称为安全门禁之前,我需要证明那些明确要阻断的问题,确实能够阻止变更继续推进。
如果你也准备尝试类似方案,我建议先从一个小例子开始,保存原始扫描证据,审查 AI 的建议,然后对准确的那份代码修改重新扫描。只要剩余工作足够明确,部分改进也值得认真复盘。
你觉得 AI 最适合用在哪个环节:理解扫描结果、提出修复方案,还是审查变更影响?欢迎分享你会怎样加强验证和审查流程。
本文描述的是 2026 年 4 月进行的一次实验。产品文档于 2026 年 11 月核对,界面、任务行为和 Provider 支持情况可能已经发生变化。