Safeguard
Security Guides•

How should ephemeral CI jobs authenticate to a private registry?

Give each job a short-lived, read-only registry credential at start, never a login saved on the runner. Here is how to pull and push without shared secrets.

Safeguard Security Team
3 min read

Give each job its own short-lived registry credential at start, read only for pulls and write only for the one repository it publishes to. Do not save a registry login on the runner host or in the image, because every job that runs there can then use it.

Why saved logins are the problem

GitLab's runner security guidance is explicit: Docker credentials kept in the runner host's own configuration files are available to every job the runner executes. On shared runners it says not to run docker login as the runner user, and not to keep Docker configuration files in the runner user's home directory.

That advice matters more when a platform starts many runners from one image. A login baked into the image or mounted into every pod is a credential shared by every job and every contributor who can trigger one.

Two separate needs

  1. Pulling the job image. The platform pulls the container image before the job starts. GitHub's job container syntax lets you set credentials for the image's registry, with a username and password map, the same values you would give docker login.
  2. Pulling and pushing inside the job. Steps that fetch base images or publish new ones need their own credentials.

Options compared

ApproachStrengthWeakness
Login saved on runner hostEasyShared by all jobs, long lived
Credential baked into imageEasyAnyone with the image has it
Long lived stored secret passed to jobSimpleOne leak exposes the registry
Short lived token via OIDC or platform tokenExpires, scoped per jobNeeds registry support and setup
Pull-through mirror inside your networkNo external credential in jobYou maintain the mirror

GitHub documents OIDC as a way to exchange short lived tokens with a cloud provider instead of duplicating long lived credentials as secrets. If your registry supports it, that is a good fit.

Steps

  1. Remove any registry login from runner hosts and images.
  2. Configure pulls of public base images through an internal mirror, so jobs need no credential for them.
  3. Issue a token per job, read only by default.
  4. Allow push rights only to the single repository and only from protected branches.
  5. Set a short expiry, ideally the length of the job.
  6. Log token issuance in the registry or identity system, so the trail survives the runner.
  7. Rotate any credential that ever sat on a shared runner image.

What to avoid in logs

A failed login can print the command with its arguments. Pass the password on standard input, not on the command line, and keep shell tracing off.

Quick check

Is a read only registry token safe to share across jobs?

It is lower risk than a write token, but it still lets anyone who steals it pull your images. Prefer per job tokens.

Do public base images need credentials?

Not for pulling. They can hit rate limits, so a mirror helps. See pull-through cache security trade-offs.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.