用 AWS Signer 实现代码签名 - Lambda 函数与容器镜像的可信性保证
对 Lambda 函数和容器镜像应用代码签名,在 CI/CD 流水线中强制签名验证。还介绍通过签名撤销应对入侵。
代码签名的必要性
代码签名是以密码学方式保证部署的代码来自可信发行者且未被篡改的机制。即使供应链攻击侵入了构建流水线,通过签名验证也可防止不正当代码的部署。以 2020 年 SolarWinds 事件为代表,构建环境的入侵日趋高级化,代码签名是零信任部署的基础技术。AWS Signer 为 Lambda 函数部署包和容器镜像提供托管式签名和验证服务,无需自建签名基础设施。
Lambda 的代码签名
Lambda 的代码签名配置 (Code Signing Configuration) 中定义信任的签名配置文件 ARN (最多 20 个) 和签名验证失败时的操作 (Warn 或 Enforce)。Enforce 模式下,未签名的函数或用不受信任的签名配置文件签名的函数的部署会被阻止。Warn 模式记录验证失败但允许部署,适用于分阶段导入。CI/CD 流水线中,在 CodeBuild 构建的 ZIP 包通过 Signer 的 StartSigningJob API 签名,将签名后包的 S3 URL 传给 Lambda 的 UpdateFunctionCode。签名作业异步执行,完成后可向 EventBridge 发送通知。
容器镜像签名与 CI/CD 集成
AWS Signer 支持对 ECR 容器镜像的 Notation 格式签名。CI/CD 流水线的构建阶段构建镜像,用 Signer 签名后推送到 ECR。EKS 的准入控制器强制签名验证,拒绝未签名镜像的部署。签名配置文件定义签名使用的加密算法 (ECDSA P-256 或 RSA) 和有效期,配置文件过期后无法生成新签名但已有签名仍然有效。签名的撤销 (Revocation) 可使被侵入的签名配置文件签名的代码失效。撤销后进行签名验证会失败,相关代码的部署会被阻止。 要深入了解 Signer 的实践知识,可参考相关专业书籍 (Amazon)。
签名配置文件的运维设计
签名配置文件的设计应匹配组织的部署体制。为每个团队创建单独的配置文件,可在某个配置文件被侵入时将影响范围限制在该团队的制品内。配置文件有效期过短会增加轮换运维负担,过长则在侵入时延长风险窗口,应根据组织的风险承受度设置。通过 IAM 策略将 signer:StartSigningJob 的执行限制在特定角色 (CI/CD 流水线的构建角色),防止开发者个人签名,确保只有经过批准的构建流程的代码才会被签名。在 CloudTrail 中记录所有签名操作,维护谁在何时签了什么的审计跟踪。
与其他签名方式的比较
除 AWS Signer 外,代码签名还有其他选择。Cosign (Sigstore 项目) 是开源容器签名工具,支持无密钥签名 (短期证书),但需要自行管理签名基础设施和密钥。AWS Signer 提供托管的密钥生成、存储和轮换,通过 KMS 集成确保密钥由硬件安全模块 (HSM) 保护。GPG 签名广泛用于 git commit 签名,但难以与 Lambda 或 ECR 的部署验证集成。AWS Signer 的优势在于与 Lambda Code Signing Configuration 和 EKS 准入控制器的原生集成,无需额外基础设施即可实现部署时的验证强制。另一方面,在需要统一签名策略的多云环境中,Notation 或 Cosign 的通用性更具优势。
Signer 的费用
AWS Signer 的费用按签名操作次数计费。签名验证免费。CI/CD 流水线频繁构建和签名时,容器镜像的签名成本会累积,因此开发环境省略签名,仅在测试/生产环境强制签名来管理成本。签名配置文件的管理不产生额外费用。Lambda 代码签名的单次成本较低,即使部署频率高,成本影响也很小。
总结
AWS Signer 是为 Lambda 函数和容器镜像提供代码签名的托管服务,以密码学方式保证部署代码的可信性。在 CI/CD 流水线的构建阶段签名,通过 Lambda 的代码签名配置或 EKS 的准入控制器强制签名验证,为供应链攻击添加了防御层。通过团队隔离的签名配置文件和 IAM 限制签名权限的设计,可在侵入时最小化影响范围。