凭据管理 #
凭据(Credentials)管理是Jenkins安全体系的核心,用于安全存储和使用敏感信息,如密码、SSH密钥、API令牌等。
凭据类型 #
类型概览 #
| 类型 | 说明 | 适用场景 |
|---|---|---|
| Username with password | 用户名和密码 | 基本认证 |
| SSH Username with private key | SSH私钥 | SSH连接 |
| Secret file | 机密文件 | 证书、配置文件 |
| Secret text | 机密文本 | API令牌 |
| Certificate | 证书 | 双向SSL认证 |
| Docker Host Certificate Credentials | Docker证书 | Docker TLS |
管理凭据 #
访问凭据管理 #
- 进入 Manage Jenkins
- 点击 Credentials
- 选择 System → Global credentials
创建凭据 #
用户名密码 #
- 点击 Add Credentials
- 选择 Username with password
- 填写信息:
- Scope: Global
- Username: 用户名
- Password: 密码
- ID: 唯一标识符
- Description: 描述
SSH私钥 #
- 选择 SSH Username with private key
- 配置:
- ID: ssh-key
- Username: 用户名
- Private Key: 选择输入方式
- Enter directly: 直接输入
- From a file on Jenkins master: 从文件读取
- From the Jenkins master ~/.ssh: 从~/.ssh读取
Secret Text #
- 选择 Secret text
- 输入机密文本内容
Secret File #
- 选择 Secret file
- 上传文件
在Pipeline中使用凭据 #
environment方式 #
groovy
pipeline {
agent any
environment {
DB_PASSWORD = credentials('db-password')
API_KEY = credentials('api-key')
}
stages {
stage('Deploy') {
steps {
sh "deploy.sh --password ${DB_PASSWORD}"
}
}
}
}
withCredentials步骤 #
用户名密码 #
groovy
steps {
withCredentials([usernamePassword(
credentialsId: 'docker-registry',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASS}"
}
}
SSH私钥 #
groovy
steps {
withCredentials([sshUserPrivateKey(
credentialsId: 'ssh-key',
keyFileVariable: 'SSH_KEY',
usernameVariable: 'SSH_USER'
)]) {
sh "ssh -i ${SSH_KEY} ${SSH_USER}@server 'deploy.sh'"
}
}
文件凭据 #
groovy
steps {
withCredentials([file(
credentialsId: 'kube-config',
variable: 'KUBECONFIG'
)]) {
sh 'kubectl get pods'
}
}
Secret Text #
groovy
steps {
withCredentials([string(
credentialsId: 'api-token',
variable: 'API_TOKEN'
)]) {
sh "curl -H 'Authorization: Bearer ${API_TOKEN}' https://api.example.com"
}
}
证书 #
groovy
steps {
withCredentials([certificate(
credentialsId: 'client-cert',
keystoreVariable: 'KEYSTORE',
passwordVariable: 'PASSWORD'
)]) {
sh "curl --cert ${KEYSTORE} --pass ${PASSWORD} https://api.example.com"
}
}
多个凭据 #
groovy
steps {
withCredentials([
usernamePassword(
credentialsId: 'db-creds',
usernameVariable: 'DB_USER',
passwordVariable: 'DB_PASS'
),
string(
credentialsId: 'api-key',
variable: 'API_KEY'
),
file(
credentialsId: 'config-file',
variable: 'CONFIG_FILE'
)
]) {
sh """
export DB_USER=${DB_USER}
export DB_PASS=${DB_PASS}
export API_KEY=${API_KEY}
./deploy.sh --config ${CONFIG_FILE}
"""
}
}
凭据绑定 #
UsernamePasswordMultiBinding #
groovy
steps {
withCredentials([usernamePassword(
credentialsId: 'creds',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD'
)]) {
echo "User: ${USERNAME}"
sh 'echo $PASSWORD'
}
}
UsernameColonPasswordBinding #
groovy
steps {
withCredentials([usernameColonPassword(
credentialsId: 'creds',
variable: 'USERPASS'
)]) {
sh "curl -u ${USERPASS} https://api.example.com"
}
}
GitLabGitCredentialBinding #
groovy
steps {
withCredentials([gitLab(
credentialsId: 'gitlab-token',
tokenVariable: 'GITLAB_TOKEN'
)]) {
sh "git push https://oauth2:${GITLAB_TOKEN}@gitlab.com/user/repo.git"
}
}
凭据作用域 #
System #
- 只在Jenkins系统内部使用
- 不能在Pipeline中直接访问
- 用于Jenkins配置
Global #
- 全局可用
- 所有Pipeline都可以访问
- 最常用的作用域
项目作用域 #
groovy
withCredentials(bindings: [
usernamePassword(
credentialsId: 'project-creds',
usernameVariable: 'USER',
passwordVariable: 'PASS'
)
]) {
}
凭据安全最佳实践 #
1. 不记录敏感信息 #
groovy
// 不推荐
steps {
withCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) {
echo "API Key: ${API_KEY}" // 会暴露
sh "echo ${API_KEY}" // 会记录到日志
}
}
// 推荐
steps {
withCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) {
sh 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com'
}
}
2. 使用掩码 #
groovy
options {
maskPassword()
}
steps {
withCredentials([string(credentialsId: 'secret', variable: 'SECRET')]) {
echo "Processing..." // SECRET会被掩码
}
}
3. 限制凭据访问 #
groovy
// 在文件夹级别配置凭据
folder('project') {
properties {
folderCredentialsProperty {
domainCredentials {
domainCredentials {
domain {
name("")
description("")
}
credentials {
usernamePassword {
id("project-creds")
username("user")
password("pass")
}
}
}
}
}
}
}
4. 定期轮换凭据 #
groovy
// 使用脚本更新凭据
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
def updateCredential(String id, String newUsername, String newPassword) {
def domain = Domain.global()
def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
def credentials = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
id,
"Updated credential",
newUsername,
newPassword
)
store.updateCredentials(domain, credentials, credentials)
}
凭据提供者 #
Jenkins内置 #
默认凭据存储在Jenkins主目录。
Kubernetes Secrets #
yaml
apiVersion: v1
kind: Secret
metadata:
name: jenkins-credentials
type: Opaque
data:
username: dXNlcg==
password: cGFzc3dvcmQ=
groovy
withCredentials([usernamePassword(
credentialsId: 'k8s-secret',
usernameVariable: 'USER',
passwordVariable: 'PASS'
)]) {
}
HashiCorp Vault #
groovy
withVault(configuration: [
engineVersion: 2,
path: 'secret/jenkins'
], vaultSecrets: [
[
path: 'database',
secretValues: [
[vaultKey: 'username', envVar: 'DB_USER'],
[vaultKey: 'password', envVar: 'DB_PASS']
]
]
]) {
sh 'deploy.sh'
}
AWS Secrets Manager #
groovy
withAWS(credentials: 'aws-creds', region: 'us-east-1') {
withSecretsManager(secretId: 'myapp/database', credentialsId: 'aws-creds') {
sh 'deploy.sh'
}
}
凭据管理API #
列出凭据 #
groovy
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
def creds = CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials,
Jenkins.instance,
null,
null
)
creds.each { c ->
println "ID: ${c.id}"
println "Description: ${c.description}"
println "Username: ${c.username}"
}
创建凭据 #
groovy
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
def domain = Domain.global()
def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
def credentials = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
"new-credential",
"Description",
"username",
"password"
)
store.addCredentials(domain, credentials)
删除凭据 #
groovy
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
def id = "credential-to-delete"
def domain = Domain.global()
def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
def credentials = CredentialsProvider.lookupCredentials(
Credentials.class,
Jenkins.instance,
null,
null
).find { it.id == id }
if (credentials) {
store.removeCredentials(domain, credentials)
}
完整示例 #
groovy
pipeline {
agent any
environment {
APP_NAME = 'myapp'
VERSION = "${BUILD_NUMBER}"
DOCKER_REGISTRY = 'registry.example.com'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Docker Build') {
steps {
withCredentials([usernamePassword(
credentialsId: 'docker-registry',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh """
docker login -u ${DOCKER_USER} -p ${DOCKER_PASS} ${DOCKER_REGISTRY}
docker build -t ${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} .
docker push ${DOCKER_REGISTRY}/${APP_NAME}:${VERSION}
"""
}
}
}
stage('Deploy to K8s') {
steps {
withCredentials([file(
credentialsId: 'kube-config',
variable: 'KUBECONFIG'
)]) {
sh """
kubectl set image deployment/${APP_NAME} \
${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${VERSION} \
-n production
"""
}
}
}
stage('Database Migration') {
steps {
withCredentials([
usernamePassword(
credentialsId: 'db-credentials',
usernameVariable: 'DB_USER',
passwordVariable: 'DB_PASS'
),
string(
credentialsId: 'db-host',
variable: 'DB_HOST'
)
]) {
sh """
flyway -url=jdbc:mysql://${DB_HOST}:3306/mydb \
-user=${DB_USER} \
-password=${DB_PASS} \
migrate
"""
}
}
}
stage('Notify') {
steps {
withCredentials([string(
credentialsId: 'slack-webhook',
variable: 'SLACK_WEBHOOK'
)]) {
sh """
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Deployed ${APP_NAME}:${VERSION}"}' \
${SLACK_WEBHOOK}
"""
}
}
}
}
post {
always {
cleanWs()
}
}
}
下一步学习 #
小结 #
- 凭据管理是安全的核心
- 支持多种凭据类型
- 使用withCredentials安全访问
- 不要在日志中暴露敏感信息
- 定期轮换凭据
- 考虑使用外部密钥管理
最后更新:2026-03-28