Registry authentication
Configure credentials once to pull private job images, build images, or mirror
container images and OCI Helm charts. Include the common component and grant
each credential only the registry permissions required by its jobs.
Choose where to supply credentials
| Variable | Used by | Value |
|---|---|---|
DOCKER_AUTH_CONFIG | GitLab Runner before startup, then commands inside the job | Docker-compatible authentication JSON; use a text variable for Runner image pulls. |
CI_REGISTRY_AUTH_FILE | Commands inside the job | A GitLab file variable or literal Docker-compatible JSON for additional registries. |
CI_REGISTRY | Commands inside the job | Destination hostname without https://, such as harbor.example.com. |
CI_REGISTRY_PROJECT_PATH | Container build and publish jobs | Repository namespace below the destination hostname; the component appends its image name. |
CI_REGISTRY_USER, CI_REGISTRY_PASSWORD | Commands inside the job | Credentials for CI_REGISTRY; normally predefined by GitLab CI. |
CI_JOB_TOKEN | Commands inside the job | Fallback password when the GitLab registry password is unavailable. |
Runner pulls image and services images before before_script starts. A
runtime login or CI_REGISTRY_AUTH_FILE alone cannot authorize those pulls.
See GitLab's private image authentication
for Runner configuration and access requirements.
Store credentials under Settings > CI/CD > Variables at project or group level, or under Admin > Settings > CI/CD > Variables for an instance-wide credential. Use compact, single-line JSON without spaces when masking a text variable, and disable variable-reference expansion for literal credentials. See GitLab's masking requirements. Mark credentials protected only when all consuming jobs run on protected branches or tags; protected variables are unavailable on other refs.
Configure an additional registry
Generate an auth value locally, without committing the secret:
printf '%s' '<registry-user>:<registry-password>' | base64 | tr -d '\n'
Put the result in a masked DOCKER_AUTH_CONFIG text variable, or in
CI_REGISTRY_AUTH_FILE when only commands inside the job need it:
{
"auths": {
"registry.example.com:5000": {
"auth": "<base64-username-colon-password>"
}
}
}
Registry keys must exactly match the hostname and optional port in the image
reference. Base64 is an encoding, not encryption. Prefer static auths entries
unless both Runner and each component image provide the required credential helper.
Include the components and use the matching registry name:
include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/common@stable
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/oci-mirror@stable
inputs:
source: registry.example.com:5000/team/application:1.0.0
target: $CI_REGISTRY_IMAGE/mirrors
On a tag pipeline, the job publishes mirrors/application:1.0.0 below
$CI_REGISTRY_IMAGE. An authentication error fails the registry operation;
credentials are not inferred from unrelated API tokens.
Authenticate to a protected group registry
For projects sharing private job images, create a group deploy token with
read_registry and, for publishing jobs, write_registry. Set these group
variables:
| Variable | Value |
|---|---|
CI_REGISTRY_USER | Deploy-token username. |
CI_REGISTRY_PASSWORD | Masked deploy-token secret. |
DOCKER_AUTH_CONFIG | Masked authentication JSON using the registry hostname and deploy-token credentials. |
Use the JSON format above, with the hostname from the private image reference. If the variables are protected, run both the build and every job pulling its image on protected refs. Limit the token to the group owning those images.
Add credentials in a before script
Use ci_registry_auth_add REGISTRY USER PASSWORD when a job obtains credentials
at runtime. Create masked MIRROR_USER and MIRROR_PASSWORD variables first.
Load the library before calling the helper:
include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/common@stable
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/oci-mirror@stable
inputs:
source: registry.example.com/team/application:1.0.0
target: $CI_REGISTRY_IMAGE/mirrors
mirror:oci:
before_script:
- source <(echo "${CI_BOOTLOADER}" | base64 -d) stable
- ci_registry_auth_add registry.example.com "${MIRROR_USER}" "${MIRROR_PASSWORD}"
Keep the library reference (stable here) aligned with the included component
version. The helper adds or replaces only that registry's credentials; other
registry entries remain available. It does not enable private Runner image
pulls retroactively.
Credential precedence and client support
CI Tools merges DOCKER_AUTH_CONFIG, then CI_REGISTRY_AUTH_FILE, then runtime
logins into a private job-scoped configuration. Later entries override the same
registry from earlier sources. Automatic GitLab and legacy Red Hat logins run
when their login helper is called, which can be after before_script.
Podman, Buildah, skopeo, Helm, ORAS, and Cosign share the merged configuration
through DOCKER_CONFIG, REGISTRY_AUTH_FILE, and HELM_REGISTRY_CONFIG.
After initialization, CI_REGISTRY_AUTH_FILE points to the merged output file.
Do not edit a source variable expecting a second initialization to reload it;
use ci_registry_auth_add for later changes.
Registry-specific credentials
For GitHub Container Registry, add ghcr.io with a GitHub username and a token
authorized for the required packages. GITHUB_TOKEN, GITHUB_USER, and
GITHUB_USERNAME no longer trigger automatic image or Helm registry login.
GITHUB_TOKEN remains available to unrelated GitHub API, Composer, and Renovate
operations. A job using a legacy GitHub registry variable prints a ⚠️ deprecation
warning without using that token for registry authentication.
For Red Hat Registry, add registry.redhat.io using its registry account and
secret. The legacy RH_REGISTRY_ACCOUNT and RH_REGISTRY_PASSWORD pair still
works when both variables are defined, but prints a ⚠️ deprecation warning.
Migrate the pair to authentication JSON or ci_registry_auth_add.
For Harbor, use the registry hostname and a robot account with the required repository pull/push permissions. Store the robot secret when it is created; see Harbor robot accounts.
For Azure Container Registry, use its login server, a service-principal application ID, and its client secret. Grant the repository permissions required by the registry's RBAC or ABAC mode; see service-principal authentication.
Diagnose missing credentials
If Runner cannot pull a private job image, check its DOCKER_AUTH_CONFIG, the
exact registry hostname, and whether the ref can access the configured variable.
If a command inside the job fails, check the merged configuration's registry
keys and the credential's pull/push scope without printing secret values.
The host-rules input for Renovate configures its dependency queries; it does
not log Runner or OCI command-line clients in.