Chapter 02Lesson 05~210 minutes

Checkpoint Lab — Accounts, Two-Factor Authentication, SSH Keys, Access Tokens, Service Accounts, and Credentials

Integrate web, SSH/HTTPS Git, glab/API, token-scope diagnostics, CI job identity, service-identity design, and complete credential cleanup in one free-compatible checkpoint.

Checkpoint labLeast privilegeSSHPAT scopesCI_JOB_TOKENCleanup

Learning objectives

  • Build and predict a complete authentication matrix before creating temporary credentials.
  • Prove SSH account and repository access with a dedicated key while verifying GitLab's host identity.
  • Demonstrate an intentionally under-privileged API request, diagnose it, and correct only the required scope.
  • Explain HTTPS credential-helper, CI job-token, and service-identity boundaries without requiring paid features or runner compute.
  • Revoke/remove all temporary credentials and independently prove cleanup without recording secret values.

1. Checkpoint mission and safety contract

Build an authentication matrix for one disposable GitLab.com project and prove each channel independently. The checkpoint is complete only when temporary credentials are removed and you can state what each observation proves.

Required: GitLab.com Free, a disposable project, Git, OpenSSH, glab, one dedicated SSH lab key, and two short-lived PATs used sequentially for the scope drill. No Premium/Ultimate, Dedicated, Self-Managed administrator access, cloud, Kubernetes, custom runner, or paid compute is required.
Secret handling: never paste token values, private keys, recovery codes, cookies, or OAuth secrets into the project, command arguments, screenshots, lab notes, or evidence files. Evidence records metadata/status only.

2. Predict the authentication matrix before touching credentials

Channel Principal Credential Target Predicted authority
Web Your human GitLab user Current sign-in method + 2FA/passkey/SSO as configured Disposable project Your project role only
Git SSH Your human GitLab user Dedicated lab SSH key Repository Git operations permitted by project/ref policy
Git HTTPS Your human GitLab user Credential helper + token/OAuth-capable workflow Repository Token permission + user role
glab Your human GitLab user OAuth on GitLab.com CLI/API resources OAuth permissions + user authorization
REST scope drill Your human GitLab user Temporary PAT A then PAT B /user A denied as under-scoped; B succeeds with only user-read permission
CI identity Future running job CI_JOB_TOKEN Supported GitLab resources Job-lifetime credential; not created manually here

Prediction 1: registering the public SSH key changes GitLab account metadata but creates no Git commit. Prediction 2: revoking a PAT changes credential validity but does not alter repository history. Verify both.

3. Capture non-secret preflight evidence

git remote -v
git branch --show-current
git rev-parse HEAD
glab auth status --hostname gitlab.com

Record project path, visibility, default branch, your role if visible, current Git remote host/protocol, whether the dedicated lab key exists yet, and token names currently present. Do not export token values. If reusing the Chapter 01 project, confirm it contains only synthetic learning content.

4. Create, register, verify, and exercise the SSH lab key

ssh-keygen -t ed25519 -C "gitlab-ch02-checkpoint" \
  -f ~/.ssh/id_ed25519_gitlab_ch02
ssh-keygen -lf ~/.ssh/id_ed25519_gitlab_ch02.pub
  1. Register only the .pub key with a clearly disposable title.
  2. Compare the first-connect server fingerprint with GitLab's current published GitLab.com host fingerprints.
  3. Run ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_gitlab_ch02 -T git@gitlab.com.
  4. Use GIT_SSH_COMMAND plus git ls-remote against the disposable project.
  5. Confirm the default-branch SHA matches the hosted project.

Evidence: key fingerprint, GitLab key title/metadata, authenticated username, repository ref SHA. No private key contents.

5. Verify glab identity and context

If glab is not authenticated, use the current GitLab.com OAuth flow:

glab auth login --hostname gitlab.com --web --git-protocol ssh
glab auth status --hostname gitlab.com
glab repo view -R YOUR_NAMESPACE/credential-hygiene-lab -F json

For a headless environment, use the documented device flow instead. Record hostname, account, and repository metadata; never use token-display output as evidence.

6. Required under-privilege drill: fail, diagnose, minimally correct

Create PAT A named ch02-under-scoped with the shortest practical expiry and only read_repository. Securely load it without echoing. Request the authenticated-user endpoint:

read -rsp "PAT A: " GITLAB_TOKEN; echo
STATUS=$(curl --silent --show-error \
  --output pat-a-response.json --write-out '%{http_code}' \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/user")
unset GITLAB_TOKEN
printf 'HTTP status: %s\n' "$STATUS"
python -m json.tool pat-a-response.json
rm -f pat-a-response.json

Diagnose the result from current GitLab documentation: the credential is valid for repository-read use, but the /user API call needs user/API read permission. Do not “fix” it by adding full api.

Revoke PAT A. Create PAT B named ch02-read-user with only read_user, repeat the same request, and verify a successful authenticated profile response. Then revoke PAT B immediately.

Version-aware expected result: GitLab can evolve status/body details. The invariant is that PAT A must not authorize the endpoint and PAT B with the documented minimum read permission must. If your target version behaves differently, capture the sanitized status/body and reconcile it with that version's official access-token-scope documentation.

7. HTTPS transport design without putting a token in the URL

Inspect the project's HTTPS clone URL and explain how a Git credential helper would supply a token as the password when HTTPS is used. Do not replace your working remote unless you need to test it. Never use a URL such as https://token-value@gitlab.com/... in the lab because URLs leak into history, process lists, logs, and configuration.

On Windows, Git Credential Manager is a common way to keep Git HTTPS credentials out of plain-text remote URLs. On other systems, use the supported credential helper/keychain for the environment. The exact helper is local-tooling policy, not a GitLab server feature.

8. Model CI identity without consuming runner compute

No pipeline is required. Use this synthetic job description to predict identity:

inspect_gitlab:
  script:
    - 'echo "job identity exists only while this job runs"'
    # Do not echo $CI_JOB_TOKEN.

When GitLab actually runs a job, it provides CI_JOB_TOKEN; the token is valid only during the job and can authenticate only to supported GitLab resources/endpoints. Cross-project access can require target allowlisting and sufficient permissions from the user who triggered the job. This is a workload identity, not a PAT you manually create or keep after the job.

9. Service identity design exercise

Your deployment service must survive employee turnover and needs only read access to a package/registry. Compare three candidates: a human PAT, service-account PAT, and deploy token. Choose one and state resource reach, protocol, owner, storage, rotation, revocation, and why a broader alternative is unnecessary. No service account or deploy token creation is required.

Then consider a GitLab CI job performing a supported GitLab API/resource operation. Explain why CI_JOB_TOKEN may be preferable to all three long-lived choices.

10. Cleanup and independent verification

  1. Confirm PAT A and PAT B are revoked/inactive in GitLab. No token value should remain in files or shell variables.
  2. Remove the lab SSH public key from GitLab.
  3. Retry the dedicated-key SSH test; it should no longer authenticate that identity.
  4. Delete only ~/.ssh/id_ed25519_gitlab_ch02 and its .pub file after confirming the exact paths.
  5. Remove any temporary response files. Search the disposable project and lab notes for accidental strings such as access-token prefixes or private-key headers.
  6. Keep or archive the disposable project for Chapter 03; deletion is optional and must target only the full verified lab path.
unset GITLAB_TOKEN
rm -f pat-a-response.json pat-b-response.json
# Before deleting the key files, print exact paths and verify they are the lab key.
printf '%s\n' ~/.ssh/id_ed25519_gitlab_ch02 ~/.ssh/id_ed25519_gitlab_ch02.pub
If a real credential leaked: stop the normal cleanup flow. Revoke/rotate first, preserve sanitized evidence, assess exposure, then remove the secret from history/logs/other surfaces. Deleting the lab project alone is not containment.

11. Verification checklist

  • Web sign-in/2FA state is documented without recovery codes or session material.
  • The dedicated SSH key fingerprint and target account were verified before removal.
  • Repository authorization was independently checked with git ls-remote or equivalent.
  • glab host/account context was verified without displaying a token.
  • PAT A failed the user endpoint because it was intentionally under-scoped; PAT B used only the documented user-read permission and succeeded.
  • Both temporary PATs are revoked; the dedicated SSH key is removed; temporary local files/variables are cleared.
  • The CI identity explanation correctly states that CI_JOB_TOKEN is generated for the running job and revoked afterward.
  • Paid/admin/SSO/service-account features were not required for completion.

12. What Chapter 02 adds to the production operating model

Chapter 01 taught you to name GitLab resources and scopes. Chapter 02 adds the principal and credential dimension: every action now has an authenticated identity, credential type, lifetime, storage boundary, and authorization intersection. This becomes the basis for safe merge governance, CI/CD variables, runner trust, registry authentication, environment deployment, API automation, security policy, and incident response later in the course.

Chapter 03 moves from identity to project configuration: visibility, repository settings, forks, protected resources, and project templates.

Checkpoint questions

PAT A has read_repository and receives an authorization/scope failure from /user. Why is api not the best first fix?

After deleting the local SSH private key, the public key remains registered in GitLab. Is cleanup complete?

A CI job token worked during the job but fails after completion. Is that evidence of a GitLab outage?

A project access token and a personal PAT both have read_api. Why can their reachable projects differ?

What evidence is safe to attach to a credential review?

Chapter 02 summary

You built and verified a multi-channel GitLab authentication model, used a disposable SSH key, protected host identity, authenticated glab without exposing credentials, executed an intentionally under-privileged API request, corrected only the required scope, modeled CI and service identities, and proved cleanup. The production invariant is simple: credential choice follows principal + resource + protocol + minimum permission + lifetime, and revocation is always verified at the issuer.

Chapter 03

Projects, repository settings, visibility, forks, protected resources, and templates

With identity and credential boundaries established, the next chapter applies them to the GitLab project as a governed resource.

Official references

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.