Credentials binding done right
withCredentials, masking, and scope.
Pipelines need secrets — a registry password, a deploy token, an SSH key — and how you handle them is the security heart of this course. The rule is absolute: secrets never appear in the Jenkinsfile, in the repo, or in environment{}. They live in Jenkins’ credentials store (encrypted in JENKINS_HOME), scoped to who may use them, and are injected into a build only for the moment they are needed.
stage('Push') {steps {withCredentials([usernamePassword(credentialsId: 'registry-creds', // an id, never the valueusernameVariable: 'REG_USER',passwordVariable: 'REG_PASS')]) {sh 'echo "$REG_PASS" | docker login -u "$REG_USER" --password-stdin registry.acme.internal'}}}
withCredentials scopes the exposure
withCredentials binds a stored credential to environment variables only inside its block, so the secret exists for those few steps and nowhere else in the pipeline. Jenkins also masks the value in the build log — if the secret string appears in output, it is replaced with ****. Reference the credential by its id, pass it to commands via the variable, and let the block’s scope limit how far it can leak.
For declarative pipelines there is also the credentials() helper in an environment block, which is convenient for a single credential across a stage. Either way the principle holds: the Jenkinsfile names an id; the value is resolved from the encrypted store at run time.
environment {// resolves the stored secret text into GH_TOKEN for this scope onlyGH_TOKEN = credentials('github-token')}