'How can I tell if I'm logged in to a private Docker registry from a script?

How can I tell whether or not I'm logged in to a private Docker registry server from a script? In other words, has docker login some.registry.com been run successfully (and is still valid)?

Note: I'm asking about an arbitrary private registry, not the docker.io registry.



Solution 1:[1]

if docker login worked, you will find a .docker folder on your home directory (~/.docker/), with a config.json file with credentials in it.

otherwise you would get an error login in.

Note: docker determine what credentials to use by looking at the registry name:

if you do

docker pull myregistry.com/myimage:tag

docker will look if you're logged in, and if not will check if you have the credentials for the registry myregistry.com and login with those.

If not you will get a permission error

Solution 2:[2]

This is a bit hacky, but it works in most of the cases for me:

if ! grep -q "my.private.registry.com" ~/.docker/config.json ; then
    docker login "my.private.registry.com"
fi

Basically, you search if there is a record of "my.private.registry.com" in ~/.docker/config.json. However, if the session is expired, this check won't catch it.

Solution 3:[3]

If you are constrained to examining your local system, it's impossible to know!

... The only way to be sure the credentials docker has stored are still valid is to perform an operation that will cause them to be presented to the registry, and to see if the registry accepts them.

If you want to use the docker CLI to get an answer, then you could use @matanper suggestion of "login again" which will complete automatically if you still have valid credentials.

Another way is to try to pull an image known not to exist, which will show different error message when logged in or not e.g.

# NO VALID LOGIN:

$ docker pull 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist
Error response from daemon: pull access denied for 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image, repository does not exist or may require 'docker login'

versus

# WITH VALID LOGIN:

$ docker pull 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist
Error response from daemon: manifest for 999999999999.dkr.ecr.us-west-2.amazonaws.com/this/image:does_not_exist not found

(presume that you didn't want to pull because you don't want any delay or large data tranfser, so the above method is still 'ok')

In the past, when docker always stored credentials in ~/.docker/config.json (or equivalent for your OS), you could parse that file to get the currently stored credentials and then run a simple list operation using curl or similar. However, recent docker versions store the credentials in host OS specific stores (e.g. the keychain on Mac OS X) so that is no longer a portable methodology. If portability is not important, you could still try something like that - the hash in config.json is just the base64 encoded username & password, separated by a colon, as is standard for HTTP basic auth e.g. on linux, with jq to parse JSON, and base64 to decode base64:

$  cat ~/.docker/config.json  | jq -r '.auths["registry.example.com"].auth' | base64 -d

username:password

So, completing that with a registry list operation using curl:

REGISTRY="registry.example.com"

CREDENTIALS="$(cat ~/.docker/config.json | jq -r ".auths[\"${REGISTRY}\"].auth" | base64 -d)"

curl -sSf --max-time 3 --user "${CREDENTIALS}" "https://${REGISTRY}/v2/_catalog"

will return exit code zero, and a JSON response if the CREDENTIALS are good; or a non-zero exit code if not

{
  "repositories": [
    "jamesjj/test-image",
    "jamesjj/other-image",
    ...
    ...
}

NOTE: When parsing the JSON, the registry address key may or may not include the schema https://, depending on how the original login was performed, so cat ~/.docker/config.json | jq -r ".auths[\"${REGISTRY}\"].auth" | base64 -d)" ... may need to be: cat ~/.docker/config.json | jq -r ".auths[\"https://${REGISTRY}\"].auth" | base64 -d)"

Solution 4:[4]

I believe the error message will vary by registry implementation. However, my own technique is to pull an image that doesn't exist and parse any error message:

$!/bin/sh
repo="$1"
msg=$(docker pull ${repo}/missing:missing 2>&1)
case "$msg" in
  *"requested access to the resource is denied"*|*"pull access denied"*)
    echo "Logged out";;
  *"manifest unknown"*|*"not found"*)
    echo "Logged in, or read access for anonymous allowed";;
  *"Pulling from"*)
    echo "Missing image was not so missing after all?";;
  *) 
    echo "Unknown message: $msg";;
esac

This has been tested with the docker standalone registry and docker_auth. You'll want to test with registries that you may encounter.

If your registry server allows anonymous pulls and you want to verify a push is possible, you can create a dummy empty image and replace the pull with a push of that image. E.g.

#!/bin/sh
repo=$1
# note, I do not like the "." here, better to change it to an empty directory
# see "mktemp" for an option if you cannot make your own empty directory somewhere
docker build -t "${repo}/empty:test" -f - . <<EODF
FROM scratch
EODF
msg=$(docker push "${repo}/empty:test" 2>&1)
rc=$?
if [ "$rc" = "0" ]; then
  echo "Access granted to push"
else
  case "$msg" in
    *"requested access to the resource is denied"*)
      echo "Access denied";;
    *) 
      echo "Unknown error message: $msg";;
  esac
fi

Solution 5:[5]

This is a little hacky, I think until docker will have a command to check login, there won't be any good solution.
You can in your bash script try to login with timeout of x seconds, if you aren't logged in the command will try to prompt for username and then it will timeout with status 124. If you are indeed logged in, it will just log you in again using the save credentials and continue with status 0

#!/bin/bash
timeout -s SIGKILL 3s docker login some.registry.com >/dev/null 2>&1
if [ $? -eq 0 ]
then
   echo Logged In!
else
   echo Not logged in...
fi

Solution 6:[6]

You can parse .docker/config.json and try to manually connect to each registry specified in the file. The file contains the registry address and encoded username and password so you can script this process. You can do that using a library like docker-registry-client.

pip install docker-registry-client

And then:

import base64
import docker_registry_client
import json
import os.path

def get_authed_registries():
  result = []
  config_path = os.path.expanduser("~/.docker/config.json")
  if not os.path.isfile(config_path):
    print("No docker config")
    return []

  docker_config = json.load(open(config_path))

  for registry, auth in docker_config.get("auths", {}).items():
    username, password = base64.b64decode(auth["auth"]).decode("utf-8").split(":", 1)
    if not registry:
      registry = "https://index.docker.io/v1/"
    if not registry.startswith("http"):
      registry = "https://" + registry
    try:
      rc = docker_registry_client.DockerRegistryClient(registry, username=username, password=password)
      result.append(registry)
    except Exception, e:
      print(registry, "failed:", e)

  return result


get_authed_registries()

A few caveats:

  • This may fail if you're using a credential store.
  • Tested on Python 2.7. Might need small adjustments for Python 3.
  • This code works for authentication, but any further actions on the registry fail. You will need to strip away API version (/v1, /v2, etc.) from the host name for that.
  • The code assumes all registries are HTTPS (unless specified otherwise in config.json)
  • An even more correct version will probably strip away anything but the hostname and try both v1 and v2.

That said, I was able to get a list of logged-in registries and it correctly ignored expired ECR login.

Solution 7:[7]

This is somewhat old, but I needed the same thing today. I found this question first, and from that, I derived this, which I think answers the OP's question directly:

# try to login. If you are logged in, it exits happily. If you aren't, it prompts
# for credentials. By redirecting stdin to /dev/null, we guarantee this fails
docker login ${MY_REG} < /dev/null >& /dev/null
if [ $? -eq 0]; then
  echo "Already logged in"
else
  echo "Login required"
fi

If MY_REG is unset, it will check against docker.io. Otherwise, against the registry you set.

I do understand that there is a difference between storing credentials and authenticating with the registry, and perhaps that's an important nuance in the OP's use case. In my case, I just wanted to know the former. If the latter is important, then by all means, pull an image.

Solution 8:[8]

When you do the

Docker login <private registry> -u <user> -p <password> 

command from your terminal, you will have a response: (stored in $?)

0
Login Succeeded

if you were successful.

In your shell script, you could just look at the response you're receiving, if it does not equal 0, you've failed to login.

sudo docker login <registry> -u <uname> -p <password>
if [ $? -ne 0 ]; then
    echo Login failed!
else
    echo Login OK!
fi

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MrE
Solution 2 Vlad Frolov
Solution 3 JamesJJ
Solution 4 BMitch
Solution 5 matanper
Solution 6
Solution 7
Solution 8 Joe