Chapter 15Lesson 05~165 minutes

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.

Checkpoint labFake credentialsTrusted agentLeak-risk drillEvidence packetCleanup

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
Preflight guard: verify that 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

  1. Prediction A — context: cred-lab/checkpoint will resolve all four folder credentials; credential-outsider will not resolve lab-secret-text.
  2. 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.
  3. 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.
  4. 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
      }
    }
  }
}
Interpretation: if the transformed fake canary appears in the console, the lab has demonstrated the expected limitation. Do not try to create additional encodings. The repair is to avoid transforming/printing secrets, not to chase every possible representation with masking rules.

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

  1. Archive/download only the safe evidence packet.
  2. Delete credential-outsider and cred-lab only after confirming they are the exact disposable lab resources.
  3. Delete local fake key/config input directories.
  4. Remove only the disposable trusted lab agent/controller resources you created.
  5. 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.

Next chapter

Chapter 16 — Secret Masking Limits, Credentials Scope, External Secret Providers, Vault Integration, and Rotation Patterns

Move from correct Jenkins credential binding to provider-backed secret lifecycles, short-lived identity, masking caveats, and operational rotation.

Knowledge check

What are the two predictions you must make before this checkpoint?

Why is the controlled leak-risk value explicitly fake canary data?

What proves the secret-file binding was cleaned up?

If a transformed fake token appears in the log, what is the correct redesign?

What does this chapter add before Chapter 16?

Official references and version notes

Assumption timestamp: 2026-09-17. Recheck core/plugin security advisories and minimum-core requirements before reproducing this lab later.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.