Learning paths / Containers / Registries

Private registries and credentials

Reading · 5 min · Module 5, lesson 2 of 422 min left in this module

Module 5 · RegistriesLesson 2 of 4

Goal: Sign in to a private registry with a scoped token, without leaving the token in your shell history.

Key idea

Anyone can pull a public image; a private one needs a sign-in. Sign in with a token made for the job, never your account password, and give each machine the least it needs: push for your laptop or CI, pull only for anything that just runs the image.

Public or private

Public is right for open-source images and for these labs, where ComputeSphere pulls your image with no credentials. Private is right for your company's code: the image contains everything the app ships with, so a public image of a private app is a leak.

Each registry has its own default. A new GHCR package starts private. On Docker Hub you choose when you create the repository.

Tokens, not passwords

Both registries sign you in with a personal access token:

  • Docker Hub: Account settings, then Personal access tokens. Give it the least access the job needs: read to pull, write to push.
  • GHCR: a GitHub personal access token (classic) with write:packages to push, or read:packages to pull. GitHub's fine-grained tokens don't work with GHCR.

A token can be revoked on its own, can be given an expiry date, and does only what its access allows. If one leaks, you revoke one token, not your whole account.

Signing in

docker login can take the token on standard input, the text piped into a command rather than typed after it, so the token never appears in the command or your history:

read -s CR_PAT          # paste the token, then Enter; nothing is shown
echo "$CR_PAT" | docker login ghcr.io -u <your-username> --password-stdin
unset CR_PAT            # forget the token once you're signed in

read -s CR_PAT waits for you to paste a line and stores it in the shell variable CR_PAT without echoing it (-s is silent). echo pipes it into docker login, and unset removes the variable.

With no registry name, docker login signs in to Docker Hub. It prints Login Succeeded, and from then on docker push and docker pull use those credentials for that registry.

Docker keeps the credentials in your system's credential store (the macOS keychain, for example), with just the registry's name in ~/.docker/config.json. docker logout ghcr.io removes them.

Amazon ECR and other cloud registries

Cloud registries sign in through the cloud's own tools. Amazon ECR, for one, hands out passwords that expire after 12 hours, so anything pulling from it has to renew them. ComputeSphere doesn't renew ECR credentials reliably yet, which is why these lessons use Docker Hub and GHCR.

Check yourself

ComputeSphere needs to pull your private GHCR image. Which token do you give it?