防患于未然 – 软件供应链安全
前言:为何从“供应链”开始?
我们花费了大量精力来加固 Kubernetes 集群的配置、设置网络策略。但如果我们在这个固若金汤的堡垒里,运行的是一个包含了“Log4Shell”这种高危漏洞的、或是被植入了恶意代码的容器镜像,那么之前的一切努力都可能付之东流。
现代网络攻击,越来越多地从直接攻击生产服务器,转向攻击更上游、防御更薄弱的软件供应链——即从开发者编写代码,到最终制品被部署到生产环境的全过程。
“安全左移”的核心思想,就是不再等到生产环境出问题后才被动响应,而是尽可能早地、在开发生命周期的上游(即“左侧”)就发现并修复安全问题。我们的 CI/CD 流水线,就是实践“安全左移”的最佳阵地。
今天,我们将为我们的软件供应链设立三道关键的自动化“安检门”。
第一关:依赖安全 – “检查你的配料” 🥫
我们的应用很少从零开始编写,而是构建在成百上千个开源依赖(库、框架)之上。这些依赖就是我们软件的“配料”。任何一个“配料”出了问题,都会影响我们最终的“菜品”。
问题: 手动追踪和更新所有依赖的漏洞信息,是一项不可能完成的任务。
解决方案: 自动化依赖扫描工具。
工具:
GitHub Dependabot: GitHub 原生集成的工具,可以自动扫描你仓库中的 package.json (Node.js), go.mod (Go), pom.xml (Maven) 等依赖文件,发现已知漏洞后会发出告警,甚至能自动为你创建一个 Pull Request 来升级到安全的版本。
Snyk, Renovate Bot 等也是业界非常流行的同类工具。
实践: 对于一个 GitHub 仓库,你只需在 Settings > Code security and analysis 中,启用 Dependabot alerts 和 Dependabot security updates 即可。这是一个零成本、高回报的安全实践。
第二关:镜像安全 – “扫描你的成品” 📦
一个容器镜像,除了我们的应用代码和依赖,还包含了基础操作系统(如 Alpine, Ubuntu)、系统库(如 apenSSL, glibc)等。这些都可能存在漏洞。
问题: 如何确保我们最终构建出的容器镜像,没有已知的严重漏洞 (CVEs)?
解决方案: 在 CI 流水线中集成自动化镜像扫描。
工具: 我们将使用 Trivy,这是一款由 Aqua Security 出品的开源工具。它以其速度快、易于集成、漏洞库更新及时而广受欢迎。
实践: 让我们在 GitHub Actions 工作流中加入 Trivy 扫描步骤。
# .github/workflows/ci.yaml
# ... (其他步骤,例如 checkout, setup-go, login-to-dockerhub) ...
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: your-username/myapp:${
{
github.sha }}
- name: Scan image for vulnerabilities with Trivy
uses: aquasecurity/trivy-action@master
with:
# 引用上一步构建的镜像
image-ref: 'your-username/myapp:${
{ github.sha }}'
# 输出格式
format: 'table'
# 如果发现漏洞,则让流水线失败(退出码为1)
exit-code: '1'
# 忽略那些尚无补丁的漏洞,避免流水线被不必要地阻塞
ignore-unfixed: true
# 只对高危和严重级别的漏洞失败,以平衡安全和开发速度
severity: 'HIGH,CRITICAL'
通过 exit-code: '1' 和 severity 配置,我们就在 CI 流水线中建立了一个自动化的安全门禁。任何带有高危漏洞的镜像,都将被阻止进入我们的制品库,更不用说生产环境了。
第三关:制品签名 – “贴上防伪封条” seals
我们扫描过的镜像是“干净”的。但我们如何确保,最终在生产环境中运行的,就是我们亲手构建和扫描过的那个镜像,而不是一个被中间人篡改过的、植入了后门的版本?
问题: 如何保证软件制品的完整性 (Integrity) 和来源可追溯性 (Authenticity)?
解决方案: 对制品进行数字签名。
工具: 我们将使用 Sigstore,这是一个由 Linux 基金会支持的、旨在简化软件签名流程的开源项目。它的核心组件是 Cosign。
工作原理:
签名: 在 CI 流水线中,当镜像成功构建并推送到仓库后,我们调用 cosign sign 命令。Cosign 会利用 CI 环境的身份(例如,GitHub Actions 的 OIDC Token)向 Sigstore 的免费证书颁发机构 Fulcio 申请一个短期的签名证书。然后用这个证书对镜像的摘要 (digest) 进行签名。
记录: 签名信息会被记录到一个公开的、不可篡改的透明日志 Rekor 中。
存储: 签名本身会作为一个独立的层,被附加到容器镜像旁,一同存储在容器仓库里。
强制验证: 签名的真正威力在于强制验证。我们可以在 Kubernetes 集群中部署一个准入控制器 (Admission Controller),如 Kyverno 或 Gatekeeper,并配置一条策略:“禁止运行任何没有经过我们 CI/CD 流程有效签名的容器镜像”。
这样,我们就构建了一个从“出生”到“运行”的全链路信任链。
SRE 视角的思考
自动化即正义: 安全措施如果依赖于人的自觉和手动检查,那它注定会失败。SRE 的核心职责之一,就是将这些安全检查无缝地、强制地集成到自动化的平台和流程中,让“安全的方式”成为“最轻松的方式”。
风险与速度的平衡: 注意我们在 Trivy 扫描中配置了 ignore-unfixed: true 和 severity: 'HIGH,CRITICAL'。这体现了 SRE 的务实精神。我们的目标是管理风险,而不是不惜一切代价地追求“零漏洞”,从而因为一些无法修复或低风险的漏洞而完全阻塞开发流程。
平台责任: 为开发者提供一个“默认安全”的“铺好的路 (Paved Road)”,是平台工程团队的核心价值。上述所有工具的集成、配置和维护,都应该是平台团队的责任,从而让业务开发者可以专注于业务逻辑本身。
总结与展望
今天,我们成功地为我们的软件交付流程,构建了第一道、也是最重要的防线——软件供应链安全。我们学习了如何在 CI/CD 流程中,通过自动化依赖扫描、镜像扫描和制品签名这三道关卡,来“左移”安全问题,防患于未然。
我们现在能够确保,进入我们制品库的每一个软件,都是经过严格“安检”的“合格品”。
那么,当这些合格品被部署到我们的“堡垒”——Kubernetes 集群中之后,我们又该如何保护这个堡垒本身,以及在其中运行的应用呢?
在下一篇中,我们将深入堡垒内部,探讨**“Kubernetes 集群安全强化”**。我们将学习如何配置 RBAC、Pod 安全标准等,来加固我们的运行时环境。敬请期待!























暂无评论内容