CI/CD 流水线是 DevOps 团队软件交付过程的基本组成部分。该流水线利用自动化和持续监控来实现软件的无缝交付。通过持续自动化,确保 CI/CD 流水线每一步的安全性非常重要。在流水线的各个阶段,通常需要访问凭据等敏感信息。保护这些信息对于保持强大的安全态势至关重要。本文将带你了解如何在 Jenkins CI/CD 流水线中保护密钥(Secrets)。
转自 SEAL安全
在 CI/CD 流水线中使用 Secrets
如前所述,CI/CD 流水线通常需要访问敏感信息,如密码和 API 密钥。以明文对它们进行硬编码会产生严重的安全风险,并且违反了大多数合规框架中的审计准则。使用这些凭证而不在非必要的情况下公开它们的机制,对于自动化软件交付很重要。
用于安全存储、管理和访问上述凭证的工具和技术的集合称为密钥管理(Secrets Management)。Secrets 广泛用于 IT、DevOps 和云环境。
Secrets 包括:
- 应用程序生成的密码
- 系统到系统的密码
- API 密钥
- 私有加密密钥
- 一次性密码
- 证书
- 特权账户凭证
CI/CD 流水线集成了多个配置管理平台,需要 secrets 来启用服务到服务的通信。这些平台还需要 secrets 来验证请求访问 SSH 服务器、数据库、HTTP 服务和其他资源的实体。
CI/CD 中 Secrets 的用途
Secrets 用于管理 CI/CD 流水线中的访问权限。一些用例包括源代码控制管理、基础设施连接、协作提供者和验证。让我们更详细地讨论这些用例中的每一个。
1. 源代码控制管理
版本控制系统,如 Git,便于多人团队之间的协作。这些系统通过管理和存储来自多个开发人员的代码贡献,来帮助维护应用程序的开发。由于源代码可能包含一些组织最有价值的资产,因此正确验证和管理 Git 存储库的访问权限至关重要。
密钥管理系统对保护用于将贡献者的主机连接到存储库的凭据非常重要。为了避免恶意攻击者利用 secrets 发起安全攻击,因此 secrets 并不存储在版本控制,而是存储在特殊的敏感文件中(当然这些敏感文件会被排除在存储库和日志之外)。
2. 基础设施连接
CI/CD 流水线通常由在多个主机上的不同服务组成,这些主机分布在不同的基础设施上。随着这些主机不断地相互通信,通过 API 调用与服务通信,从而实现所需的应用程序功能。API 密钥和系统到系统(system-to-system)密码等 secrets 能够支持在基础设施之间建立安全的连接,从而连接多租户和多云 CI/CD 流水线。
3. 跨团队协作
CI/CD 流水线包含跨多个开发、运营和质量保证环境的协作活动。这些团队依靠多种工具和框架来协作和共享信息。使用 secrets 进行协作有助于团队确保安全通信并在双方之间提供一层信任和安全保障。
4. 验证
身份验证是 CI/CD 和应用程序安全的关键要素。通过将应用程序连接到身份和访问管理 (IAM)解决方案,secrets 用于确保 CI/CD 流水线的安全性和隐私性。这些解决方案提供了用户角色和权限的外部数据库,让用户无需在 CI/CD 流水线中暴露其凭据即可登录应用程序。
CI/CD 中的 Secrets 使用示例
要为改进密钥管理奠定基础,了解一些简单的用例会很有帮助。
1. AWS 凭证
作为领先的云 SaaS 平台之一,AWS 是大多数基于云的基础设施的常见选择。与 AWS API 交互以预置和查询资源通常需要使用密钥/访问密钥凭证。保护这些凭证对于维护 AWS 账户的安全至关重要。
2. 基础架构即代码 (IaC)
现代应用程序架构通常依赖于基础架构即代码 (IaC) 来部署运行工作负载的底层系统。对这种配置进行编码能够更轻松地对可重复、可扩展和安全的基础架构进行维护。在配置此基础架构的过程中,通常需要将敏感信息(例如 SSH 密钥和 API 凭证)部署到节点。通过 IaC 和 CI/CD 自动配置基础设施是一种常见模式,管理机密是该工作流程的重要组成部分。
3. 环境变量
环境变量在大多数 CI/CD 流水线中都有一致的用法。在处理 CI/CD 工作流时,需要动态设置值并保留这些数据,以供其他进程和脚本使用。在许多情况下,敏感值需要通过环境变量传递,这也再次强调了有效机密管理的必要性。
在Jenkins内保护secrets
Jenkins 需要访问大量凭据才能与构成完整 CI/CD 流水线的所有平台和应用程序交互。Jenkins 附带了一个默认的凭证插件,其提供一个内置的密钥存储。还带有凭据绑定插件,可以将凭据绑定到环境变量。
将密钥存储在 Jenkins controller 中使流水线中的应用程序,即使这些机密仅被创建一次仍然能够被多次引用。虽然 Jenkins 凭据插件提供了一种存储和管理机密的简单方法,但任何 Jenkins 管理员和流水线作者都可以访问它们。因此,DevOps 团队应确保正确配置访问权限,以确保 CI/CD 流水线的安全。
Jenkins 支持的 secret 类型
Jenkins 机密插件支持的凭证包括:Secret text、用户名/密码对、secrets file、SSH 用户名和证书。对于数量有限的密钥,可以单独存储,而大量密钥通常最好使用凭证文件进行管理。
在 Jenkins 中管理 secret
接下来我们将讨论在 Jenkins 中保护 secret 的一些可用选项。一起来看看将 secrets 安全地注入 Jenkins 流水线的一些最佳实践。
1. 一次性密码 (OTP)
一次性密码通过确保用户名/密码组合不能多次使用来帮助防止用户帐户被盗用。虽然该帐户始终保留用户名,但用户每次登录时都会收到一个 OTP。这可以保证 Jenkins 管理员和用户帐户的安全,防止密钥信息泄露。
2. 避免硬编码密钥
删除已硬编码到 CI/CD 配置和 Jenkinsfiles 中的密钥。这样能够让敏感凭证信息不出现在流水线中,避免恶意行为者访问和利用。
3. 将密钥存储在多个 Jenkins 文件
将密钥存储在多个文件中有助于实施凭据最少暴露原则。这样可以让凭据用于尽可能少的应用程序和用户。
4. 使用授权控制来管理密钥权限
开发团队应配置安全检查,以确保请求资源访问的应用程序具有有效应用程序的属性。这些应用程序需要根据 RBAC (Role-based Access Control)策略中分配的权限访问各种资源。
5. 遵循最小权限原则
仅将权限授予需要访问流水线内密钥的应用程序。团队应始终如一地审核权限,确保在流水线的整个生命周期中最小权限原则得以实施和维护。
管理和存储密钥
这一节我们将会介绍3个实际使用密钥的Jenkins和Akeyless密钥管理平台的基本例子:
- 第一个例子是完全不安全的示例:使用纯文本环境变量来存储敏感凭据
- 第二个例子则是使用原生的Jenkins功能和插件来进行密钥管理
- 第三例子将会展示使用第三方工具来进行密钥管理的好处
纯文本示例
首先,我们将会在Jenkins中创建一个“freestyle”项目,并将其连接到GitHub Repo:
无论我们选择如何管理代码中的密钥,使用Jenkins内置的凭证机制来访问GitHub仓库是有用的。
我们的实际代码将是一个非常基本的Python应用程序,它进行API调用。该API需要一个简单的API密钥,以文本字符串的形式进行认证:
#!/usr/bin/env python
import os
import requests
api_key = os.environ[‘API_KEY’]response = requests.get(“https://thedogapi.com/v1/breeds?api_key={}”.format(api_key))
print(response)
Jenkins提供了配置环境变量的功能,然而,如果没有额外的插件,它们只能对Jenkins的环境或实例进行全局设置。
代码将从刚才配置的环境变量中读取API密钥。下面是构建步骤的配置:
构建步骤运行一些简单的提示,然后实际执行代码。下面是一个成功构建的日志的一部分:
API密钥显然已经在一个构建步骤中的一个简单指令中以明文日志的形式暴露出来。一个小小的错误配置就有可能导致泄露或危险。
Jenkins Secret Text
现在我们可以尝试通过使用内置的证书处理程序来提高我们构建环境的安全性:
在本例中,我们将使用简单的“Secret Text”凭据绑定来存储API密钥:
接下来,我们配置我们的构建job来使用新的凭证变量:
现在,在运行另一个构建job后,我们再次检查构建日志:
尽管我们已经将构建步骤配置为将变量内容打印到日志中,但Jenkins凭证处理程序知道该值是敏感的,并在任何日志或输出中混淆了实际值。
这固然极大地提高了构建的安全性,但并不是十全十美的。这对一个用户量较少的Jenkins部署已经足够用,但在一个大型的、分布式的Jenkins架构中,需要管理多个用户和团队的访问权限,这十分复杂,难以有效管理。此外,存储在凭证变量中的密钥值仍然可以被集群中的每个Jenkins实例以及具有适当权限的任何用户访问。
如果任意节点被破坏,跨越多个部署和上下文的密钥可能处于危险之中。用户仍然需要手动保护和配置Jenkins的基础设施,在本例中指密钥存储。如果有一种方法可以使用敏感的凭证,而不需要将他们存储在Jenkins内部,会怎么样呢?
密钥管理工具
让我们试试使用Akeyless来管理密钥。既然我们已经和Jenkins部署集成,我们可以按照文档来进行操作。Akeyless与公开可用的Hashicorp Vault插件集成,因此Jenkins的设置很简单。
接下来,我们将创建一个免费的Akeyless并配置密钥:
下一步是创建一个访问角色,并且该角色有权限访问刚刚创建的密钥:
现在我们需要给我们的访问角色以正确的权限来查看密钥:
在Akeyless侧我们需要创建的最后一个东西是一种认证方式。这就是我们如何让外部实体,如我们的Jenkins部署,能够对Akeyless进行API调用并检索密钥。
认证方式创建完毕后,请确保通过下载CSV文件来保存访问ID和密钥,否则这些值将不会再次显示。最后,我们需要将我们新创建的角色与这个访问方式联系起来。
下一步是根据Akeyless文档配置Jenkins构建环境:
现在,我们将运行另一个构建,这次配置的是利用此前配置过的Akeyless vault
在日志中,现在有一个步骤展示了Jenkins从Akeyless Vault中检索密钥。但构建日志中的凭证值也依旧是模糊的。现在,我们有了一个与Jenkins实例集成的第三方密钥管理平台。
这看起来有些画蛇添足,但是一个完全专注于密钥管理的外部工具是一个强大的抽象。Jenkins首先是一个CI/CD工具,密钥管理是一个附加功能。在这种情况下,它永远无法提供一流的功能、管理能力和安全保障,而专门的密钥管理平台则可以提供:
- 具有SLA保证的管理基础设施
- 零知识加密
- 直观的、可访问的密钥管理和组织
- 与标准的DevOps工具和平台集成
像Akeyless这样的工具还可以避免管理复杂的、自我托管的基础设施。我们只需点击几下,就能拥有一个运行中的密钥终端。
结 论
由于安全性是 CI/CD 流水线的首要考虑因素,因此在 Jenkins 中使用密钥时遵循最佳实践非常重要。Jenkins 流水线依赖密钥进行身份验证、协作和基础设施管理。CI/CD 密钥管理对大多数团队来说都是一个挑战,因为在细节上实施访问控制非常困难和复杂。
而通过密钥管理工具,Jenkins 用户可以获得更加集中且安全的资源来管理运行 CI/CD 流水线所需的包含敏感信息的凭据,加速 DevOps 工作流程。同时,安全团队也能够全面了解密钥的位置和使用方式。借助自动化流程和集中访问策略,密钥管理平台还可以帮助安全团队应对安全相关的法律和合规问题。