An external organization that I work with has given me access to a private (auth token protected) docker registry, and eventually I would like to be able to query this registry, using docker's HTTP API V2, in order to obtain a list of all the repositories and/or images available in the registry.
But before I do that, I'd first like to get some basic practice with constructing these types of API queries on a public registry such as Docker Hub. So I've gone ahead and registered myself with a username and password on Docker Hub, and also consulted the API V2 documentation, which states that one may request an API version check as:
GET /v2/
or request a list of repositories as:
GET /v2/_catalog
Using curl, together with the username and password that I used in order to register my Docker Hub account, I attempt to construct a GET request at the command line:
stachyra> curl -u stachyra:<my_password> -X GET https://index.docker.io/v2/
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":null}]}
stachyra> curl -u stachyra:<my_password> -X GET https://index.docker.io/v2/_catalog
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}
where of course, in place of <my_password>
, I substituted my actual account password.
The response that I had been expecting from this query was a giant json message, listing thousands of repository names, but instead it appears that the API is rejecting my Docker Hub credentials.
Question 1: Do I even have the correct URL (index.docker.io
) for the docker hub registry? (I made this assumption in the first place based upon the status information returned by the command line tool docker info
, so I have good reason to think it's correct.)
Question 2: Assuming I have the correct URL for the registry service itself, why does my query return an "UNAUTHORIZED" error code? My account credentials work just fine when I attempt to login via the web at hub.docker.com, so what's the difference between the two cases?
Santiago Trujillo
Here is an example program to read repositories from a registry. I used it as a learning aid with Docker Hub.
#!/bin/bash
set -e
# set username and password
UNAME="username"
UPASS="password"
# get token to be able to talk to Docker Hub
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${UNAME}'", "password": "'${UPASS}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)
# get list of repos for that user account
REPO_LIST=$(curl -s -H "Authorization: JWT ${TOKEN}"
https://hub.docker.com/v2/repositories/${UNAME}/?page_size=10000 | jq -r '.results|.[]|.name')
# build a list of all images & tags
for i in ${REPO_LIST}
do
# get tags for repo
IMAGE_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}"
https://hub.docker.com/v2/repositories/${UNAME}/${i}/tags/?page_size=10000 | jq -r '.results|.[]|.name')
# build a list of images from tags
for j in ${IMAGE_TAGS}
do
# add each tag to list
FULL_IMAGE_LIST="${FULL_IMAGE_LIST} ${UNAME}/${i}:${j}"
done
done
# output list of all docker images
for i in ${FULL_IMAGE_LIST}
do
echo ${i}
done
(this comes from an article on Docker site that describes how to use the API.)
In essence...
Authorization: JWT <token>
with any API calls you makehttps://hub.docker.com/v2/repositories/<username>/
First thing first, Docker is a protocol, DockerHub is product that implements the Docker protocol but is not limited to it.
hub.docker.com
has the rich DockerHub specific APIs.
index.docker.io
is the generic Docker API V2 implementation for DockerHub that is used in majority of clients that support multiple docker registries.
DockerHub implements the generic Docker HTTP API V2 but it doesn't implement _catalog
API from the generic API set.
In order to use the Docker V2 API, a JWT auth token needs to be generated and that token has to be used as Bearer token in the DockerHub calls at index.docker.io
When you hit the DockerHub APIs like this:
https://index.docker.io/v2/library/alpine/tags/list
and it returns 401,
Look for the response header
www-authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/alpine:pull",error="invalid_token"
This means, you need to explicitly call
https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/alpine:pull
Which will get you the bearer token that you can use in the original index.docker.io
request.
The https://auth.docker.io/token
works without any auth token but only for public repos.
In case you want to access a private repo, you need to add basic auth header to the request.
curl -u username:password https://auth.docker.io/token?service=registry.docker.io&scope=repository:<repo>:pull
NOTE: auth.docker.io
will generate a token anyway even if the request is not valid (creds or scope or anything). To validate the token, if you put the token to jwt.io, you should see the access
field in the payload containing requested scope references.