Checkpoint Lab — Credentials Store, Secret Text, Files, SSH Keys, Username/Password, Binding, and Secret Hygiene
Build and verify a three-layer credential-safety model with multiple fake credential types, folder scoping, bounded bindings, cleanup, and one controlled leak-risk demonstration using non-sensitive canary data.
Learning objectives
- Build a disposable credential model with four fake credential kinds under one least-privilege folder.
- Predict and verify credential-resolution and temporary binding state before executing secret-bearing steps.
- Demonstrate one masking/leak-risk limitation using explicitly non-sensitive canary data, then redesign the flow safely.
- Prove temporary file cleanup and verify no credential material entered artifacts, stashes, reports, or persistent workspace output.
- Produce an evidence packet containing IDs/types/scopes/build/node/cleanup metadata without secret values.
1. Checkpoint scenario
You operate a disposable Jenkins controller. A folder
cred-lab has a trusted Pipeline job that needs four
fake credentials. An unrelated root job must not resolve those
folder credentials. The trusted job must prove safe binding, record
only non-secret metadata, and perform one controlled fake-canary
transformation to show why masking is not data-loss prevention.
No real external system is required. All “authentication” is simulated locally; the goal is to validate Jenkins credential lifecycle and exposure boundaries.
2. Assumptions and preflight
| Component | Lab assumption |
|---|---|
| Jenkins | 2.568.3 LTS |
| Java | 21 for controller/agent; 2.568.3 also supports 25 |
| Credentials | 1511.v2e3cb_0008ef0 |
| Credentials Binding | 728.v902a_273b_8947 |
| SSH Credentials | 372.va_250881b_08cd |
| Folders | 6.1106.v3a_d9a_6d2465e |
| Agent |
Disposable trusted Linux agent labeled
trusted-cred-lab
|
| SCM | Synthetic/disposable repository or Pipeline script; no proprietary source |
cred-lab,
credential-outsider, and the four
lab-* credential IDs are disposable and do not collide
with existing resources.
3. Predict state changes before running
-
Prediction A — context:
cred-lab/checkpointwill resolve all four folder credentials;credential-outsiderwill not resolvelab-secret-text. - Prediction B — lifetime: environment variables and secret/key files will exist only inside the binding block; after it ends, the temporary file paths will be absent.
- Prediction C — masking: a literal fake canary may be masked, but a transformed representation can escape masking; this is why real secrets must never be used in this drill.
- Prediction D — retention: the final evidence artifact will contain metadata only and no token/password/key/file contents.
4. Create the disposable folder, fake inputs, and credentials
Use the four IDs from Lesson 2. Generate the secret file and SSH key
in a local temporary directory with restrictive permissions, upload
them to the cred-lab folder credential store, then
remove the local input directory after Jenkins has stored the fake
values.
mkdir -p ./checkpoint-cred-input && chmod 700 ./checkpoint-cred-input
printf '%s\n' 'profile=lab-only' > ./checkpoint-cred-input/client.conf
chmod 600 ./checkpoint-cred-input/client.conf
ssh-keygen -t ed25519 -f ./checkpoint-cred-input/id_ed25519 -N '' -C 'jenkins-checkpoint-lab'
ssh-keygen -lf ./checkpoint-cred-input/id_ed25519.pub
5. Jenkinsfile: bind, verify metadata, demonstrate fake leak risk, then clean
The controlled transformation stage uses only the known fake value
behind lab-secret-text. It must never be reused with
real credentials.
pipeline {
agent { label 'trusted-cred-lab' }
options { skipDefaultCheckout(true); timestamps(); disableConcurrentBuilds() }
stages {
stage('Preflight') {
steps {
sh '''
set -eu
umask 077
rm -rf evidence && mkdir evidence
printf 'job=%s\\nbuild=%s\\nnode=%s\\nworkspace=%s\\n' \
"$JOB_NAME" "$BUILD_NUMBER" "$NODE_NAME" "$WORKSPACE" > evidence/build.txt
'''
}
}
stage('Safe bindings') {
steps {
withCredentials([
string(credentialsId: 'lab-secret-text', variable: 'LAB_TOKEN'),
usernamePassword(credentialsId: 'lab-basic-auth',
usernameVariable: 'LAB_USER', passwordVariable: 'LAB_PASS'),
file(credentialsId: 'lab-secret-file', variable: 'LAB_FILE'),
sshUserPrivateKey(credentialsId: 'lab-ssh-key',
keyFileVariable: 'LAB_KEY', usernameVariable: 'LAB_SSH_USER')
]) {
sh '''
set -eu; set +x
test -n "$LAB_TOKEN" && test -n "$LAB_USER" && test -n "$LAB_PASS"
test -f "$LAB_FILE" && test -f "$LAB_KEY"
printf 'binding-ok=true\\n' >> evidence/binding.txt
printf 'secret-file-parent=%s\\n' "$(dirname "$LAB_FILE")" >> evidence/binding.txt
printf 'ssh-key-parent=%s\\n' "$(dirname "$LAB_KEY")" >> evidence/binding.txt
ssh-keygen -lf "$LAB_KEY" >> evidence/ssh-public-fingerprint.txt
printf '%s' "$LAB_FILE" > evidence/secret-file-path.txt
printf '%s' "$LAB_KEY" > evidence/ssh-key-path.txt
'''
}
}
}
stage('Prove cleanup') {
steps {
sh '''
set -eu
FILE_PATH=$(cat evidence/secret-file-path.txt)
KEY_PATH=$(cat evidence/ssh-key-path.txt)
test ! -e "$FILE_PATH"
test ! -e "$KEY_PATH"
printf 'temporary-files-cleaned=true\\n' > evidence/cleanup.txt
'''
}
}
stage('Controlled fake masking-limit drill') {
steps {
withCredentials([string(credentialsId: 'lab-secret-text', variable: 'LAB_TOKEN')]) {
sh '''
set -eu; set +x
printf 'This stage uses FAKE training data only.\\n'
ENCODED=$(printf '%s' "$LAB_TOKEN" | base64 | tr -d '\\n')
printf 'transformed-fake-canary=%s\\n' "$ENCODED"
unset ENCODED
'''
}
}
}
stage('Retain safe evidence') {
steps {
sh '''
set -eu
rm -f evidence/secret-file-path.txt evidence/ssh-key-path.txt
grep -R -n -E 'LAB_ONLY_TOKEN_2026|LAB_ONLY_PASSWORD_42' evidence && exit 1 || true
'''
archiveArtifacts artifacts: 'evidence/*', fingerprint: true
}
}
}
}
6. Prove the unauthorized context is denied
Create credential-outsider outside
cred-lab and use the expected-denial Pipeline from
Lesson 2. Record the build URL and resolution error. Do not broaden
the credential scope.
7. Redesign the leak-risk stage safely
Replace the transformation stage with a local simulated consumer that never prints the token:
stage('Safe simulated consumer') {
steps {
withCredentials([string(credentialsId: 'lab-secret-text', variable: 'LAB_TOKEN')]) {
sh '''
set -eu; set +x
test -n "$LAB_TOKEN"
# A real tool would consume the value directly here.
printf 'consumer-called=true\\n' >> evidence/consumer.txt
'''
}
}
}
This is the desired production pattern: credential use is bounded, the value is not transformed or logged, and retained evidence records only that the intended action occurred.
8. Required evidence packet
-
baseline.txt: Jenkins core, Java, relevant plugin versions. -
credential-metadata.md: the four IDs, kinds, folder store, domain/scope metadata, rotation owner—no values. -
authorized-build.md: job full name, build number/URL, node/label/workspace, source/Jenkinsfile revision if SCM-backed. -
binding.txt: binding success and temporary parent directories. -
ssh-public-fingerprint.txt: public fingerprint of the disposable SSH key, not the key. -
cleanup.txt: proof that bound temporary files disappeared. -
outsider-denial.md: expected credential-resolution denial from outside the folder. -
masking-limit.md: note that transformed fake canary output can evade masking and that no real secret was used. -
assumptions-limitations.md: local-only simulation, trusted-agent assumption, no external secret provider.
9. Verification checklist
- Exactly four lab credentials exist only in the disposable folder during the exercise.
- Authorized job resolves them; outsider job does not.
- No token/password/private-key/secret-file content is present in archived evidence.
- Temporary bound file paths no longer exist after the binding ends.
- The fake transformation demonstrates a masking limitation and is removed from the final safe Pipeline.
- No routine build runs on the Jenkins controller built-in node.
- No TLS/CSRF/authorization/Script Security/SSH host-key protections were disabled.
10. Cleanup and rollback
- Archive/download only the safe evidence packet.
-
Delete
credential-outsiderandcred-labonly after confirming they are the exact disposable lab resources. - Delete local fake key/config input directories.
- Remove only the disposable trusted lab agent/controller resources you created.
- If this were a real incident rather than fake data, rotate/revoke first; deleting a build cannot make an exposed secret safe again.
11. What Chapter 15 adds to the production operating model
You can now reason about credential storage, selection, authorization context, type, binding lifetime, agent trust, workspace exposure, masking, cleanup, and rotation as separate states. A green Pipeline is not enough: you must know which credential ID was available to which item, on which trusted agent, for how long, and what evidence proves it was not retained as ordinary build data.
Chapter 16 extends this foundation into secret-masking limits, external secret providers, Vault-style integrations, short-lived credentials, and rotation patterns.
Knowledge check
What are the two predictions you must make before this checkpoint?
At minimum predict which job contexts can resolve each folder credential and what temporary environment/file state will exist only during the binding. Then verify both independently.
Why is the controlled leak-risk value explicitly fake canary data?
The exercise demonstrates that masking can be bypassed by transformations without disclosing any real credential. Real secrets must never be used for such a demonstration.
What proves the secret-file binding was cleaned up?
Capture only its temporary path metadata during the binding, then after the binding verify that path no longer exists. Also ensure no copy was archived, stashed, or left in the workspace.
If a transformed fake token appears in the log, what is the correct redesign?
Do not transform or print the secret. Pass it directly to the target tool through the narrowest supported mechanism, keep tracing disabled, and bind only around the exact command that needs it.
What does this chapter add before Chapter 16?
A precise model of Jenkins credential storage, scoping and binding. Chapter 16 can then examine masking limits, external providers and rotation without confusing those concerns with basic credential lifecycle.
Official references and version notes
- Jenkins Handbook — Using credentials — credential kinds, system/global scope, IDs and controller-side encrypted storage.
- Jenkins Handbook — Credentials security — limit access, protect secrets, and treat credential use as a trust-boundary decision.
- Using a Jenkinsfile — Handling credentials — Pipeline credential helpers and safe binding patterns.
-
Credentials Binding step reference
— current
withCredentialsbindings and file-placement cautions. -
Credentials plugin
— version
1511.v2e3cb_0008ef0in this lab baseline. -
Credentials Binding plugin
— version
728.v902a_273b_8947. -
SSH Credentials plugin
— version
372.va_250881b_08cd. -
Folders plugin
— version
6.1106.v3a_d9a_6d2465e; provides per-folder credential stores when used with Credentials. -
Jenkins LTS changelog
and
Java support policy
— lab baseline
Jenkins 2.568.3 LTS, Java 21; 2.568.3 is tested with Java 21 and 25.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.