The Credentials plugin keeps secrets in credentials.xml, encrypted with a key in secrets/; folders, multibranch jobs included, can hold stores of their own that only their jobs see. Each credential also has a scope: Global credentials are for jobs, System ones only for the controller itself, such as the key that launches agent-ssh (SSH Agents). The scripted job sec-scope asks for one of each:
node('linux') {
withCredentials([usernamePassword(credentialsId: 'l2-registry',
usernameVariable: 'U', passwordVariable: 'P')]) { sh 'echo "GLOBAL l2-registry: $U $P"' }
withCredentials([sshUserPrivateKey(credentialsId: 'agent-ssh-key', keyFileVariable: 'K')]) {
sh 'echo "SYSTEM agent-ssh-key: $K"'
}
}Masking supported pattern matches of $U or $P + echo GLOBAL l2-registry: **** **** GLOBAL l2-registry: **** **** ERROR: Could not find credentials entry with ID 'agent-ssh-key'
To a job, a System credential does not exist. On disk, each secret in credentials.xml is a base64 blob such as {AQAAABAAAAAg+tjj...}, and the key sits beside it in secrets/: anyone who can read JENKINS_HOME or use the Script Console can decrypt everything, and a backup without secrets/ is useless (Backing Up JENKINS_HOME). Keep each team's credentials in its folder, prefer short-lived tokens (a GitHub 29 App rather than a personal token), and consider an external store through the HashiCorp Vault 4,548 or AWS Secrets Manager 24 plugins.