19.1.4.4 Push Auth Requirement
A focused guide to Push Auth Requirement, connecting core concepts with practical Docker and container operations.
Pushing a Docker image to a registry requires the client to be authenticated with that registry. Without valid credentials, the push is rejected with an authorization error. This requirement exists to protect registry resources, enforce access control, and prevent unauthorized publishing of images.
Why Authentication Is Required
Registries are gated services. Whether hosted publicly or privately, they need to verify the identity of the caller before allowing write operations. Pushing an image is a write operation — it adds or overwrites layers and manifests stored in the registry. Authentication ensures that only authorized users or systems can modify repository contents.
Even Docker Hub, which allows public image pulls without credentials, requires a logged-in account to push images.
How Docker Handles Credentials
When you run docker login, Docker stores credentials in ~/.docker/config.json. On systems with a credential helper configured (such as the macOS keychain, Windows Credential Manager, or pass on Linux), the credentials are stored there instead and config.json only holds a reference to the helper.
An entry in config.json without a credential helper looks like:
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dXNlcm5hbWU6cGFzc3dvcmQ="
}
}
}
The auth value is a Base64-encoded username:password string. This is not encrypted — it is only encoded. Systems with sensitive credentials should use a credential store instead.
Logging In Before Pushing
Authentication is performed with docker login:
docker login
For Docker Hub, this prompts for a Docker ID and password. For a private registry:
docker login myregistry.example.com
Credentials are then stored and reused automatically for all subsequent pushes to that registry host.
Logging In Programmatically
For CI/CD pipelines and scripts, interactive login is not feasible. Credentials are passed non-interactively:
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
Using --password-stdin avoids exposing the password as a shell argument, which would be visible in process listings (ps aux) and shell history.
What Happens Without Authentication
Attempting to push without prior login produces an error:
unauthorized: authentication required
Or in some registries:
denied: requested access to the resource is denied
The push operation is aborted immediately. No layers are transferred.
Token-Based Authentication (OAuth2 / Bearer Tokens)
Modern container registries implement the Docker Registry HTTP API V2 authentication protocol, which uses OAuth2-style bearer tokens. When Docker initiates a push, the interaction proceeds as follows:
The registry responds to the initial push request with a 401 Unauthorized status code and includes a Www-Authenticate header pointing to the authentication server and the required scope. Docker then requests a bearer token from that server using the stored credentials, and retries the push with the token in the Authorization header.
Access Token Scopes
The token requested specifies what the client is allowed to do. For a push, the scope typically includes push and pull permissions on the target repository. A token scoped only for pull will fail a push attempt even if it is otherwise valid.
Service Account Credentials in Automated Systems
In containerized CI systems or Kubernetes environments, credentials are often provided through service accounts rather than personal tokens. Examples include:
- Amazon ECR: IAM roles grant permission; tokens are retrieved via the AWS SDK.
- Google Artifact Registry: Workload Identity or service account JSON keys grant access.
- GitLab Registry: CI job tokens (
CI_JOB_TOKEN) are injected automatically into pipeline jobs.
Example with GitLab CI:
docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
Credential Helpers
Docker supports pluggable credential helpers that integrate with system keychains:
| Helper binary | Platform | Store |
|---|---|---|
docker-credential-osxkeychain | macOS | macOS Keychain |
docker-credential-wincred | Windows | Windows Credential Manager |
docker-credential-pass | Linux | GPG-encrypted pass store |
docker-credential-ecr-login | Any | AWS ECR |
docker-credential-gcr | Any | Google Cloud |
These are configured in ~/.docker/config.json:
{
"credsStore": "osxkeychain"
}
With a credential helper active, docker login stores the credentials in the system store instead of Base64-encoding them in config.json, improving security.
Revoking Access
After pushing in a shared or ephemeral environment:
docker logout myregistry.example.com
This removes stored credentials for that registry from config.json or the credential store, preventing credential leakage if the environment persists or is inspected later.