安全管理Jenkins凭据的最佳实践
使用凭据插件、文件夹作用域、withCredentials、RBAC、轮换和外部保管库安全存储Jenkins密钥。
安全管理Jenkins凭据的最佳实践
Jenkins任务通常需要接近生产环境的密钥:云令牌、注册表密码、部署密钥、签名证书和API凭据。如果这些密钥最终出现在Jenkinsfile、控制台日志或任务参数中,您的CI/CD系统将成为直接导致安全漏洞的途径。
使用凭据插件,将凭据范围限制在狭窄范围内,并仅将其注入到需要它们的步骤中。
基础:Jenkins凭据插件
凭据插件是Jenkins用于存储敏感数据的标准机制。它提供了一个集中式、加密的凭据存储库,确保密钥永远不会暴露在构建日志、源代码控制或配置文件中。
当Jenkins存储凭据时,它会使用Jenkins控制器上的密钥材料(包括JENKINS_HOME/secrets下的文件)对其进行加密。任何对控制器文件系统和Jenkins配置具有广泛访问权限的人都可能恢复密钥,因此必须严格控制文件系统和管理员访问权限。
关键凭据类型
了解可用的凭据类型是安全实现的第一步。选择与要存储的密钥最匹配的类型:
- 秘密文本: 用于通用的短文本值,例如API令牌、访问密钥、OAuth令牌或Webhook密钥。
- 用户名和密码: 用于对Maven仓库、私有注册表(Docker Hub、Artifactory)或内部应用程序等服务进行身份验证的标准配对。
- 带私钥的SSH用户名: 对于访问远程代理、克隆私有Git仓库或在远程基础设施上执行命令至关重要。私钥可以直接输入、作为路径提供或由Jenkins控制器管理。
- 秘密文件: 用于上传包含敏感信息的整个文件,例如密钥库、证书(
.pem、.crt)或包含密钥的配置文件。
提示: 始终使用尽可能细粒度的凭据类型。例如,如果您只需要一个API密钥,请使用秘密文本,而不是尝试将其放入用户名和密码字段中。
最小权限原则:凭据作用域
凭据作用域决定了它们在Jenkins环境中的可访问位置。应用最小权限原则——仅授予任务所需的访问权限——至关重要。
1. 系统作用域
系统作用域的凭据(存储在管理Jenkins > 管理凭据 > Jenkins下)对Jenkins实例上的所有任务、文件夹和管道全局可用。
- 用途: 仅将系统作用域用于整个Jenkins操作所需的密钥,例如全局配置插件使用的凭据或所有代理连接所需的密钥。
- 警告: 尽量减少系统作用域的使用。任何被入侵的任务都可能访问所有全局可用的密钥。
2. 文件夹作用域
文件夹作用域的凭据在特定文件夹内定义(使用文件夹插件或通过组织文件夹创建)。这些密钥仅对该文件夹及其子文件夹内的任务可见和可用。
- 建议: 始终优先使用文件夹作用域。 这可以隔离访问,并在一个项目被入侵时限制爆炸半径。
安全注入声明式管道
不要将凭据硬编码在管道脚本中。仅当Jenkins为狭窄的代码块注入环境变量并屏蔽日志中已知的密钥值时,环境变量才是可接受的。
在声明式管道中访问凭据的安全方法是使用内置的withCredentials步骤。此步骤将指定的凭据加载到作用域环境变量中,该变量仅在代码块执行期间可用。
示例1:注入秘密文本(API令牌)
此示例安全地检索秘密文本凭据(MY_API_TOKEN)并将其值分配给内部变量SECRET_TOKEN。一旦withCredentials块完成,SECRET_TOKEN将自动从环境中清除。
pipeline {
agent any
stages {
stage('通过API部署') {
steps {
script {
withCredentials([string(credentialsId: 'MY_API_TOKEN', variable: 'SECRET_TOKEN')]) {
sh "echo '调用外部API...'"
sh '''
curl -X POST \
-H "Authorization: Bearer $SECRET_TOKEN" \
https://api.mycorp.com/deploy
'''
}
}
}
}
}
}
示例2:注入用户名和密码
使用用户名和密码凭据时,withCredentials步骤将密钥拆分为两个变量:一个用于用户名,一个用于密码,通常后缀为_USR和_PSW(或自定义名称)。
pipeline {
agent any
stages {
stage('登录注册表') {
steps {
withCredentials([usernamePassword(credentialsId: 'DOCKER_REGISTRY_CRED', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
sh '''
printf '%s' "$DOCKER_PASS" | docker login \
--username "$DOCKER_USER" \
--password-stdin my.registry.com
'''
}
}
}
}
}
安全警告:日志抑制
Jenkins尝试在构建日志中屏蔽已知的凭据值,但屏蔽不能替代谨慎的脚本。不要在密钥使用附近打印密钥、在命令行上传递密码或运行shell跟踪(
set -x)。
高级安全集成
对于高安全环境,仅依赖本地Jenkins主密钥通常是不够的。与外部密钥管理系统集成提供了关注点分离、集中审计和增强的加密能力。
外部凭据存储
流行的集成包括:
- HashiCorp Vault: 使用Vault插件,Jenkins可以在运行时动态从Vault请求密钥。这意味着密钥从不永久存储在Jenkins控制器上,仅在执行阶段临时存储在内存中。
- AWS Secrets Manager/Azure Key Vault: 云原生插件允许管道使用IAM角色或服务主体直接从这些服务检索密钥,从而最大限度地减少静态凭据暴露。
使用外部存储符合安全最佳实践,原因如下:
- 分离存储: 密钥基础设施与CI/CD服务器解耦。
- 动态访问: 密钥可以频繁轮换,无需手动更新Jenkins配置。
- 增强审计: 所有密钥访问尝试都在外部保管库系统中记录。
基于角色的访问控制(RBAC)
实施RBAC插件(如基于角色的授权策略)允许管理员控制谁可以运行任务,还可以控制谁可以配置和查看特定凭据。
- 限制任务配置权限,以便只有受信任的用户才能在管道中绑定凭据。
- 限制修改或创建系统级凭据的能力,仅限一小群安全或平台管理员。
凭据管理最佳实践
| 实践 | 描述 | 安全优势 |
|---|---|---|
| 使用文件夹作用域 | 将凭据访问限制在需要它们的特定任务/文件夹。 | 限制暴露和爆炸半径。 |
| 避免硬编码 | 切勿将密钥放在Jenkinsfile、构建脚本或源代码控制中。 |
消除源代码漏洞。 |
使用withCredentials |
使用官方Jenkins API安全地将密钥注入管道步骤。 | 确保自动日志编辑和环境清理。 |
| 集成外部保管库 | 对于企业部署,使用Vault、AWS Secrets Manager或Azure Key Vault。 | 解耦存储并启用动态轮换。 |
| 应用RBAC | 使用授权插件限制谁可以配置、查看和使用凭据。 | 在用户之间强制执行最小权限原则。 |
| 定期轮换 | 定期轮换API密钥和密码(最好通过外部保管库自动化)。 | 最小化被泄露密钥被利用的时间窗口。 |
| 保护控制器 | 确保Jenkins控制器上的严格文件系统权限以保护master.key。 |
保护核心加密机制。 |
将Jenkins凭据视为生产密钥。严格限制其范围,短暂绑定,定期轮换,并将控制器访问权限限制在允许恢复这些密钥的人员。