Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

docker

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.

like image 576
scjody Avatar asked Apr 13 '16 20:04

scjody


People also ask

How do I know if I am logged in to docker?

If you are trying to see if you already have an active session with private.registry.com, try to login again: bash$ docker login private.registry.com Username (logged-in-user): If you get an output like the above, it means logged-in-user already had an active session with private.registry.com .

Can you tell the approach to login to the docker registry?

To run the docker login command non-interactively, you can set the --password-stdin flag to provide a password through STDIN . Using STDIN prevents the password from ending up in the shell's history, or log-files.

Is docker repository Public or private?

You can decide if your registry is public or private. You'll need the latest version of Docker (>=0.5. 0) to use this new feature, and you must run this version as both the daemon and the client. You'll also need the Docker registry code.


7 Answers

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

like image 116
MrE Avatar answered Oct 21 '22 16:10

MrE


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.

like image 33
Vlad Frolov Avatar answered Oct 21 '22 18:10

Vlad Frolov


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)"

like image 31
JamesJJ Avatar answered Oct 21 '22 16:10

JamesJJ


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
like image 27
BMitch Avatar answered Oct 21 '22 17:10

BMitch


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
like image 45
matanper Avatar answered Oct 21 '22 16:10

matanper


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.

like image 31
kichik Avatar answered Oct 21 '22 18:10

kichik


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.

like image 44
jwm Avatar answered Oct 21 '22 18:10

jwm