凭证管理
Jenkins 里最大的安全漏洞往往是"把密码硬编码进流水线"或"把私钥提交进 Git"。Credentials 机制把敏感信息与流水线代码解耦,让凭证只存一处、引用时动态注入。
本篇目标:能创建和管理各类凭证,用 credentials() 在流水线安全引用,并了解与 Vault / 云密钥系统的集成。
1. Credentials 类型
Manage Jenkins → Credentials → System → Global credentials(或文件夹级凭证):
| 类型 | 用途 |
|---|---|
| Username with password | 仓库账号、镜像仓库账号、HTTP 基本认证 |
| SSH Username with private key | Git SSH 拉取、SSH 执行命令 |
| Secret text | API Token、密钥、Webhook Token |
| Secret file | 证书文件、kubeconfig、密钥文件 |
| Certificate | 客户端证书 / CA 证书 |
| Docker Host Certificate | Docker 守护进程 TLS 凭据 |
| Vault 动态凭证 | 从 HashiCorp Vault 动态获取(见下文) |
凭证存储位置
凭证默认加密存储在 $JENKINS_HOME/secrets/。备份 $JENKINS_HOME 即备份凭证,务必用与业务同等的方式保护备份文件(见第 14、15 篇)。
2. 在流水线中引用凭证
2.1 凭据绑定(Credentials Binding)
pipeline {
agent any
stages {
stage('登录镜像仓库') {
steps {
withCredentials([usernamePassword(
credentialsId: 'harbor-registry-auth',
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh '''
docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASS" registry.company.com
'''
}
}
}
}
}
关键点:
- 用
credentialsId引用,不写明文; usernameVariable/passwordVariable指定变量名,环境变量只在withCredentials块内有效;- Secret text 用
string(variable: 'TOKEN', credentialsId: 'xxx'); - 注意不要
echo这些变量,日志里会泄露。
2.2 Git 仓库凭据
Pipeline 从 Git 拉取代码时在 Job 配置(或流水线 git 步骤)中引用凭证:
stage('检出代码') {
steps {
git branch: 'main',
url: 'https://gitlab.company.com/team/app.git',
credentialsId: 'gitlab-token'
}
}
2.3 Secret file
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh 'kubectl --kubeconfig "$KUBECONFIG" get pods'
}
3. 凭证的最佳实践
| 实践 | 说明 |
|---|---|
| 专用账号 | 为 CI 创建最小权限的机器人账号,不与个人账号混用 |
| 短期令牌 | 优先用会过期的 Token,设置轮换提醒 |
| 最小范围 | 凭证按全局 / 文件夹分级,谁用给谁看 |
| 不在日志出现 | 启用 Credentials Binding 的"日志打码";不要 echo 变量 |
| 定期轮换 | 定期更换密码/Token,用 Jenkins API 或外部密钥系统驱动 |
| 审计 | 记录凭证读取和使用日志(Audit Trail 插件) |
# 审计:谁在什么时候读了什么凭证
# 开启 Manage Jenkins → Security → Audit Trail 的 Credentials 审计
4. 与外部密钥系统集成
4.1 HashiCorp Vault
安装 Vault Credentials Provider 插件,让 Jenkins 从 Vault 动态取凭据:
# 流水线中
withVault(configuration: [
vaultUrl: 'https://vault.company.com',
vaultNamespace: 'team/order',
authMethod: 'TOKEN',
token: 'xxx' # 或从 Jenkins 凭证引用
]) {
withVaultSecret(engineVersion: 2, path: 'secret/data/order/api', key: 'DB_PASSWORD', vaultVar: 'DB_PASSWORD') {
sh 'echo $DB_PASSWORD' # 仅在块内可用
}
}
好处:密码不在 $JENKINS_HOME 里,与 Vault 的轮换策略联动。
4.2 云密钥服务
| 云 | 对接方式 |
|---|---|
| AWS | Secrets Manager / Parameter Store 的 CLI + STS 临时凭证 |
| 阿里云 | KMS / 参数仓库 + RAM 角色 |
| 腾讯云 | SSM 参数 + 临时密钥(STS) |
流水线通过云的 SDK 在构建时取密钥,不用把长期密钥放进 Jenkins。
4.3 从外部 Secret 的取舍
| 方案 | 优点 | 缺点 |
|---|---|---|
| Jenkins Credentials | 简单、内置 | 凭证在 Jenkins 存储,需同步轮换 |
| Vault | 动态、可轮换、集中 | 多一套组件要运维 |
| 云密钥服务 | 与云原生一致 | 绑定云厂商 |
中小团队从 Jenkins Credentials 起步即可;多人协作、合规要求高时再上 Vault。
5. 练习与验收
练习 A
- 创建
harbor-registry-auth(Username with password)和gitlab-token(Secret text)两类凭证 - 用
withCredentials在流水线中引用并登录镜像仓库(可用模拟命令验证变量注入) - 确认日志中没有打印出密码明文
练习 B
- 创建一个 Secret file 凭证(如 kubeconfig),用
file()绑定加载 - 尝试让
developer账号只能读取文件夹级凭证、不能读取全局凭证 - (可选)部署 Vault 或用云密钥服务做一次动态取密钥
验收清单
- 能创建各类凭证,理解全局与文件夹级凭证的差异
- 会用
withCredentials和credentialsId安全引用,不用明文 - 知道 Secret text、Secret file、Username/password、SSH key 各自适用场景
- 知道凭证存储位置与备份安全
- 了解 Vault 或云密钥系统的集成价值
下一篇:Groovy 基础。