凭据管理 #

凭据(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

管理凭据 #

访问凭据管理 #

  1. 进入 Manage Jenkins
  2. 点击 Credentials
  3. 选择 SystemGlobal credentials

创建凭据 #

用户名密码 #

  1. 点击 Add Credentials
  2. 选择 Username with password
  3. 填写信息:
    • Scope: Global
    • Username: 用户名
    • Password: 密码
    • ID: 唯一标识符
    • Description: 描述

SSH私钥 #

  1. 选择 SSH Username with private key
  2. 配置:
    • ID: ssh-key
    • Username: 用户名
    • Private Key: 选择输入方式
      • Enter directly: 直接输入
      • From a file on Jenkins master: 从文件读取
      • From the Jenkins master ~/.ssh: 从~/.ssh读取

Secret Text #

  1. 选择 Secret text
  2. 输入机密文本内容

Secret File #

  1. 选择 Secret file
  2. 上传文件

在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