Credentials are stored (encrypted) in Jenkins; pipelines only reference them by ID.
| Type | Used for |
|---|---|
| Secret text | API tokens, GitHub PATs |
| Username and password | Registries, Git over HTTPS |
| Secret file | kubeconfig, .env files |
| SSH Username with private key | SSH to servers, Git over SSH |
| Certificate | PKCS#12 with an optional password |
| Docker Host Certificate Authentication | Connecting to a Docker daemon over TLS |
Scope: global (all of Jenkins), one folder/item, or one user.
pipeline {
agent any
environment {
REGISTRY = credentials('registry-creds') // creates REGISTRY, REGISTRY_USR, REGISTRY_PSW
}
stages {
stage('Push') {
steps {
sh 'echo "$REGISTRY_PSW" | docker login -u "$REGISTRY_USR" --password-stdin registry.example.com'
withCredentials([sshUserPrivateKey(credentialsId: 'deploy-key', keyFileVariable: 'KEY')]) {
sh 'ssh -i "$KEY" deploy@192.0.2.10 uptime'
}
}
}
}
}
flowchart LR
S[("Credentials store<br/>encrypted")] -- "credentials('id')" --> P["Pipeline step"]
P --> L["Console log: ****"]
- A username and password through
credentials()yieldsVAR(user:pass),VAR_USRandVAR_PSW. - Jenkins masks secret values in the log.
- Use single quotes for
sh '...$VAR...'so the shell reads the variable; double quotes"${VAR}"make Groovy interpolate the secret into the command string (Jenkins warns about it).
The Jenkins CLI needs authentication too: read user:apitoken from a file with -auth @FILE instead of typing the token on the command line (it leaks into shell history and ps).
Traps: hard-coding tokens in the Jenkinsfile; echo-ing secrets; using a password instead of an API token for the CLI.
| Command | Meaning |
|---|---|
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth @/home/fresher/.jenkins-cli-auth who-am-i |
Check the CLI is authenticated |
Binding credentials inside a stage
withCredentials limits a secret to a block of steps instead of the whole pipeline:
withCredentials([usernamePassword(credentialsId: 'registry-cred',
usernameVariable: 'REG_USER',
passwordVariable: 'REG_PASS')]) {
sh 'echo "$REG_PASS" | docker login registry.example.com -u "$REG_USER" --password-stdin'
}
Other bindings include string(...) for secret text, file(...) for secret files such as a kubeconfig, and sshUserPrivateKey(...). The SSH Agent plugin's sshagent(['deploy-key']) { sh 'ssh deploy@192.0.2.20 ...' } loads a key for one block of SSH commands.
Where Jenkins keeps secrets
Credentials are encrypted on disk under JENKINS_HOME with keys in secrets/. Anyone who can copy JENKINS_HOME (including backups) and the secrets folder can decrypt them, so protect backups as carefully as the server. Restrict who can view or update credentials with folder-scoped credentials and role-based permissions.
Better than static secrets
| Approach | Benefit |
|---|---|
| Short-lived tokens via OIDC (cloud workload identity) | No long-lived cloud keys in Jenkins at all |
| External secret stores (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault plugins) | Central rotation and audit |
| Separate credentials per environment | A leaked dev token cannot deploy to production |
Avoiding leaks
Masking only hides the exact secret string; a transformed value (base64, part of a URL, printed with set -x) can still appear in logs. Never echo secrets, avoid sh "..." with Groovy interpolation, and disable shell tracing around sensitive commands. If a secret does leak into a log, rotate it immediately: deleting the build log is not enough.
Configuration as code
The Configuration as Code (JCasC) plugin defines Jenkins settings, including credential definitions that read values from environment variables or a secret store, in a YAML file. This lets you rebuild a Jenkins controller reproducibly instead of clicking through the UI.