how much pull left for docker hub rate limit? - docker

I am trying to find out a way to check how much pulls i have left but this page https://www.docker.com/blog/checking-your-current-docker-pull-rate-limits-and-status/ does not really explain that
the page only explains how to find the rate limit plan, either anonymous or authenticated BUT i want to find out how much pulls i have left for docker pulls
Is there a way i can find this stat? Check how much pulls i have left within the time limit?

As per https://docs.docker.com/docker-hub/download-rate-limit/, requests to the manifest API receive the following headers:
RateLimit-Limit
RateLimit-Remaining
the latter one being the one you're interested in.

I've written a regclient project that includes regctl that recently added an image ratelimit command. It uses an HTTP HEAD request to avoid using any quota in checking your current rate limit:
$ regctl image ratelimit regclient/regctl
{
"Remain": 2500,
"Limit": 2500,
"Reset": 0,
"Set": true
}
If the command has access to your ~/.docker folder, or you run a registry login, it will use your credentials to give the limit that applies to yourself rather than anonymous user rates applied to your IP address.
There's also this blog post that shows how to do this with curl and jq commands. The following is an example with anonymous requests to a specific test repo:
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl -v -I -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest 2>&1 | grep -i RateLimit

Related

Fetch single layer from image repository using docker or other tooling?

Our build creates temporary images which we store to the repository for caching purposes as subsequent images are relying on them.
The images are untagged afterwards. The layer ID I can get from the build log.
But as they might contain credentials in some layers (set in Dockerfile via "ENV API_KEY=$API_KEY) I just want to fetch these layers and make sure that nobody can extract the credentials.
Is there an easy way of doing so?
I am unsure if you are actually referencing whole image ID or single layer ID. Usually you should see whole digest of image as well. With whole image digest you can do following. Also final steps can be done for single layers if you don't know specific layer of configuration file layer.
But in general, this depends on the manifest schema version. With schema version 1, you can see environment variables on manifest. With schema version 2 it is two step process. Examples are based on Docker Hub registry, but same API is applied elsewhere.
In both cases, you need authentication token at first, which can be acquired:
curl -sSL "https://auth.docker.io/token?service=registry.docker.io&scope=repository:<repository>:pull" > auth.json
Then pull manifest in version 1 schema and get history section which contains environment variables:
curl --request GET -sLH "Authorization: Bearer `jq -r '.token' auth.json`" -H "Accept: application/vnd.docker.distribution.manifest.v1+json”" "https://index.docker.io/v2/<repository>/manifests/latest" | jq ".history"
Manifest v2 schema uses different Accept header and is more supported in these days and provides more information:
curl --request GET -sLH "Authorization: Bearer `jq -r '.token' auth.json`" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "https://index.docker.io/v2/<repository>/manifests/latest"
On response there is config section:
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 5802,
"digest": "sha256:2ff217b387d7bbc0ad3fb1cbb2cdae9f7e562f26065f847a1b69964fcb71108"
}
And finally download whole blob:
curl --request GET -LOH "Authorization: Bearer `jq -r '.token' auth.json`" "https://index.docker.io/v2/<repository>/blobs/sha256:2ff217b387d7bbc0ad3fb1cbb2cdae9f7e562f26065f847a1b69964fcb71108"
See contents of whole configuration file which contains environment variables with included history:
jq . sha256:2ff217b387d7bbc0ad3fb1cbb2cdae9f7e562f26065f847a1b69964fcb71108

How to pull all alternative tags of a docker image?

I administer a gitlab with a build pipeline. All components are encapsulated in docker images from the official gitlab maintainer.
Whenever I update - usually once a week - I need to check whether the gitlab/gitlab-runner-helper still works for the current latest version of gitlab. This can only be checked by executing a pipeline. If it does not work, the log tells me exactly what image it needs and I proceed to pull it.
The image in question is also tagged with a latest tag, which I cannot use, due to the hard dependency to the non-volatile tag.
$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
gitlab/gitlab-runner-helper x86_64-8af42251 1ee5a99eba5f 20 hours ago 43.7MB
gitlab/gitlab-runner-helper x86_64-latest 1ee5a99eba5f 20 hours ago 43.7MB
To automate my update process, I'd like to know, how I could pull the latest image with all alternative tags?
The man page of docker pull says, there is a --all-tags option, to load any tagged image from the repository, but this cannot be combined with a tag.
As far as I know, there is no really efficient or built in way to do this. Instead, you need to query your registry via REST, first for the tag list for that repository:
GET http://<registry>/v2/<repository>/tags/list
Then, for each tag, a manifest:
GET http://<registry>/v2/<repository>/manifests/<tag>
Each manifest will have a hash associated with it, which you should be able to get from the HTTP headers of the response. You may even be able to make a HEAD request for it and avoid the rest of the manifest payload, but I haven't tried this recently.
Now you have a list of tags and manifest hashes, and you just need to find all the tags with hashes that match the latest tag.
This is a little tedious, but it's actually not that bad to script out with curl and jq, especially if you don't need to worry about security.
Script:
#!/bin/sh
TOKEN=`curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:gitlab/gitlab-runner-helper:pull" | jq '.token' | sed 's/"//g'`
TAGS=`curl -s https://registry.hub.docker.com/v2/gitlab/gitlab-runner-helper/tags/list -H "Authorization: Bearer $TOKEN" | jq ".tags[]" | sed 's/"//g' | grep x86_64`
for tag in $TAGS;
do
# is $tag an old entry?
if grep -Fxq $tag tags.list
then
# already processed
continue
else
echo "new tag found: $tag"
newSHA=`curl -s https://registry.hub.docker.com/v2/gitlab/gitlab-runner-helper/manifests/$tag -H "Authorization: Bearer $TOKEN" | jq ".fsLayers[] .blobSum" | sed 's/"//g'`
latestSHA=`curl -s https://registry.hub.docker.com/v2/gitlab/gitlab-runner-helper/manifests/x86_64-latest -H "Authorization: Bearer $TOKEN" | jq ".fsLayers[] .blobSum" | sed 's/"//g'`
if [ "$newSHA" = "$latestSHA" ]
then
echo "$tag is new latest version"
docker pull gitlab/gitlab-runner-helper:$tag
echo $tag >> tags.list
fi
fi
done
The above script utilizes a file named tags.list, that is placed next to it. This file contains the older tags, to prevent issuing 500+ HTTP requests. If a tag from the TAGS is not yet present in the file, it does not mean, it is the latest. Sometimes tags appear, that eventually will become the latest version. Those tags are probed, but will not be inserted into the file. This might become an issue in the future, if those versions will be skipped as latest.
Note: The script above only focuses on a specific subset of tags (x86_64).

Double tagging docker images (latest + set version) + deploy latest to k8s + then lookup real tag?

I want to double tag docker images (latest + a version e.g. 1.3.0-78) at build/docker push time.
Then I want to deploy all my applications to kubernetes with the latest tag, if tests pass then look up the "real" tag (1.3.0-78) from the image digest I can get from kubernetes associated with the "latest", then create a manifest of all the docker tags as a release candidate.
Unfortunately, I haven't found a good way to find the "real" tag just based on a digest.
It appears you have to iterate all the tags in the entire repository and look for a matching digest. Given there can be hundreds or thousands of tags for a specific image this could take a really long time.
Here is a script that finds all the tags that have the same digest, but it's very slow:
REPOSITORY=$1
TARGET_TAG=$2
# find all tags
ALL_TAGS=$(curl -s $REPOSITORY/tags/list | jq -r .tags[])
# get image digest for target
TARGET_DIGEST=$(curl -s -D - -H "Accept: application/vnd.docker.distribution.manifest.v2+json" $REPOSITORY/manifests/$TARGET_TAG | grep Docker-Content-Digest | cut -d ' ' -f 2)
# for each tags
for tag in ${ALL_TAGS[#]}; do
echo "checking tag ${tag}"
# get image digest
digest=$(curl -s -D - -H "Accept: application/vnd.docker.distribution.manifest.v2+json" $REPOSITORY/manifests/$tag | grep Docker-Content-Digest | cut -d ' ' -f 2)
# check digest
if [[ $TARGET_DIGEST = $digest ]]; then
echo "$tag $digest"
fi
done
Does anyone have another approach?
Then I want to deploy all my applications to kubernetes with the latest tag
No, you most certainly do not; you want to create what GitLab calls an environment using the release-candidate image, and then promote the RC into the real Deployment if all goes well. Using :latest is a recipe for disaster in almost all circumstances.
If you insist on using :latest, then I would suggest putting the "real" image tag in an annotation, label, or environment variable of the temporary Deployment so you will be able to acquire that information later, not only for your sanity but also make it available to the process that is presumably tearing down the temp stack and promoting the image to the production stack.

How to get Openshift session token using rest api calls

As part of an automated tests suite I have to use OpenShift's REST APIs to send commands and get OpenShift's status. To authenticate these API calls I need to embed an authorization token in every call.
Currently, I get this token by executing the following commands with ssh on the machine where OpenShift is installed:
oc login --username=<uname> --password=<password>
oc whoami --show-token
I would like to stop using the oc tool completely and get this token using HTTP calls to the APIs but am not really able to find a document that explains how to use it. If I use the option --loglevel=10 when calling oc commands I can see the HTTP calls made by oc when logging in but it is quite difficult for me to reverse-engineer the process from these logs.
Theoretically this is not something specific to OpenShift but rather to the OAuth protocol, I have found some documentation like the one posted here but I still find it difficult to implement without specific examples.
If that helps, I am developing this tool using ruby (not rails).
P.S. I know that normally for this type of job one should use Service Account Tokens but since this is a testing environment the OpenShift installation gets removed and reinstalled fairly often. This would force me to re-create the service account every time with the oc command line tool and again prevent me from automatizing the process.
I have found the answer in this GitHub issue.
Surprisingly, one curl command is enough to get the token:
curl -u joe:password -kv -H "X-CSRF-Token: xxx" 'https://master.cluster.local:8443/oauth/authorize?client_id=openshift-challenging-client&response_type=token'
The response is going to be an HTTP 302 trying to redirect to another URL. The redirection URL will contain the token, for example:
Location: https://master.cluster.local:8443/oauth/token/display#access_token=VO4dAgNGLnX5MGYu_wXau8au2Rw0QAqnwq8AtrLkMfU&expires_in=86400&token_type=bearer
You can use token or combination user/password.
To use username:password in header, you can use Authorizartion: Basic. The oc client commands are doing simple authentication with your user and password in header. Like this
curl -H "Authorization: Basic <SOMEHASH>"
where the hash is exactly base64 encoded username:password. (try it with echo -n "username:password" | base64).
To use token, you can obtain the token here with curl:
curl -H Authorization: Basic $(echo -n username:password | base64)" https://openshift.example.com:8443/oauth/authorize\?response_type\=token\&client_id\=openshift-challenging-client
But the token is replied in the ugly format format. You can try to grep it
... | grep -oP "access_token=\K[ˆ&]*"
You need to use the correct url for your oauth server. In my case, I use openshift 4.7 and this is the url:
https://oauth-openshift.apps.<clustername><domain>/oauth/authorize\?response_type\=token\&client_id\=openshift-challenging-client
oc get route oauth-openshift -n openshift-authentication -o json | jq .spec.host
In case you are using OpenShift CRC:
Then the URL is: https://oauth-openshift.apps-crc.testing/oauth/authorize
Command to get the Token:
curl -v --insecure --user developer:developer --header "X-CSRF-Token: xxx" --url "https://oauth-openshift.apps-crc.testing/oauth/authorize?response_type=token&client_id=openshift-challenging-client" 2>&1 | grep -oP "access_token=\K[^&]*"
Note:
2>&1 is required, because curl writes to standard error
--insecure: because I have not set up TLS certificate
Adjust the user and password developer as needed (crc developer/developer is standard user in crc, therefore good for testing.)
Token is per default 24h vaild
Export the Token to an environment Variable
export TOKEN=$(curl -v --insecure --user developer:developer --header "X-CSRF-Token: xxx" --url "https://oauth-openshift.apps-crc.testing/oauth/authorize?response_type=token&client_id=openshift-challenging-client" 2>&1 | grep -oP "access_token=\K[^&]*")
And Use the token then in, e.g., oc login:
oc login --token=$TOKEN --server=https://api.crc.testing:6443

How to list Docker images in a Codefresh private registry?

I'm currently using Codefresh's free private registry to store my images. I am using CircleCI for my Docker builds, so from there I use docker login so I can push and pull to the Codefresh registry. This works fine. However, Codefresh only lists images in its web app for which it did the building, so I cannot easily see a catalogue of them. I suspect this is by design, so that users stick with Codefresh for CI. However, if possible, I would like to list the images I have in the registry.
I assume that this registry is a basic v2 version of the standard Docker Registry. So, I have had a hunt around, and found this console utility to manage images. However, it does not seem to work for me. I don't know whether this is because registry management tools are still immature generally (web searches indicate they were added much later, and there are lot of folks for whom this simple task has become a substantial undertaking) or whether there is something unusual with Codefresh.
Here is what I am trying:
reg -d -r r.cfcr.io -u myusername -p cfaccesstoken
(The -d is for debug).
This results in:
2017/10/18 11:24:43 registry.ping url=https://r.cfcr.io/v2/
2017/10/18 11:24:44 registry.catalog url=https://r.cfcr.io/v2/_catalog
2017/10/18 11:25:53 registry.catalog url=https://r.cfcr.iohttps://r.cfcr.io/v2/_catalog?n=1000&last=davigsantos/davigsantos/codeflix
FATA[0075] Get https://r.cfcr.iohttps//r.cfcr.io/v2/_catalog?n=1000&last=davigsantos/davigsantos/codeflix: dial tcp: lookup r.cfcr.iohttps on 127.0.1.1:53: no such host
The penultimate line contains a container name I don't recognise - I hope it is a public one, and not one I should not be seeing!
The last line indicates some sort of fatal error, with all sorts of URL fragments mashed together in ways that definitely won't work.
I have also discovered that dropping the access token makes no difference; the output is exactly the same:
reg -d -r r.cfcr.io -u myusername
What else can I try? I am running Mint Linux and would be fine with swapping to another utility if necessary. Is there something wrong about the way I am issuing this command, or is Codefresh running a non-standard registry that is incompatible with standard API calls?
Update
It looks like Codefresh also has their own API, though it does not seem to be documented as far as I can tell. Running the get operation produces this error:
Failed to authenticate request because no token was provided
That's encouraging, so I will try to find out how to provide a token in a curl call; the Swagger web interface does not seem to permit it. However I am conscious that, if I can get the API working, it may not list my Docker images anyway, since they were not built by Codefresh.
Update 2
I have found some articles on the Codefresh blog that hint how to authenticate on the API, the format is a header thus:
--header "x-access-token: (token)"
However I get this error:
{"status":401,"code":"2401","name":"UNAUTHORIZED_ERROR","message":"Failed to authenticate request because token is not valid","context":{}}
The token I am using is the same one as I use for docker login, which works. I notice I was not specifying my username, so I am also adding this curl option:
-u (user):(token)
As you can see, I am close to trying random things now, as there does not seem to be official help online.
Update 3
Prompted by a comment below, it seems that Docker maintains an access token after login is used, in ~/.docker/config.json.
I therefore tried this:
reg -d -r r.cfcr.io -u myusername -p dockeraccesstoken
(Note how cfaccesstoken has been changed to dockeraccesstoken).
This returns much more quickly now (as opposed to appearing to hang), but returns nothing:
2017/10/24 10:56:16 registry.ping url=https://r.cfcr.io/v2/
2017/10/24 10:56:18 registry.catalog url=https://r.cfcr.io/v2/_catalog
Repositories for r.cfcr.io
You need to first generate a token on CodeFresh User Settings
Next I will show you how to login from terminal
curl -H 'Host: r.cfcr.io' -H 'User-Agent: ItsMe' -H 'Authorization: Basic <AUTH>' --compressed 'https://r.cfcr.io/v2/token?account=xxxx&scope=repository%3A<user>/<name>%3Apush%2Cpull&service=r.cfcr.io'
You can get the <AUTH> by running
echo <account>:<token> | base64
This will return you a big token
{"expires_in":43200,"issued_at":"2017-10-24T03:34:54.118390368-07:00","token":"APMm...P91"}%
Now you can use that token to make a docker API call
$ curl -IH 'Host: r.cfcr.io' -H 'User-Agent: ItsMe' -H 'Authorization: Bearer APMm+...aRL' -X HEAD 'https://r.cfcr.io/v2/<user>/<user>/testci/blobs/sha256:c7fefcc4c54c63f32b5422ede095793eb5ff0f45ad7a22861974ec9b61e7749b'
HTTP/1.1 200 OK
Docker-Distribution-API-Version: registry/2.0
Content-Length: 22488057
Date: Tue, 24 Oct 2017 10:42:23 GMT
Content-Type: text/html
Server: Docker Registry
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
For registry search access below should have worked
curl -H 'Host: r.cfcr.io' -H 'User-Agent: ItsMe' -H 'Authorization: Basic ' --compressed 'https://r.cfcr.io/v2/token?account=xxxx&scope=registry%3Acatalog%3Asearch&service=r.cfcr.io'
But it doesn't and neither does registry:catalog:* for scopes. This is like hitting a target with blind folds and not even knowing in which direction we stand. You best bet is to get them to disclose some information to you
Edit-1: Getting the catalog
So I finally managed to crack it, but the result is a bit unfortunate. I ended up getting catalog/repositories of every single user. I checked, you still can't pull those repo. So their docker images are safe as such. These look like so:
Edit-2: Fetching all repos
After we notified Codefresh of this situation, here is how to do the fetch. One needs to first generate a token using below:
curl -H 'Host: r.cfcr.io' -H 'User-Agent: MyAgent' -H 'Authorization: Basic .....' --compressed 'https://r.cfcr.io/v2/token?account=<account>&service=r.cfcr.io'
And then using the same we can query the complete catalog:
curl -H "User-Agent: ItsMe" -H 'Authorization: Bearer <TOKEN>' 'https://r.cfcr.io/v2/_catalog?n=10' --compressed
I have a partial answer, and I think it is useful enough on its own for others approaching the same difficulty. I got some kind assistance via the chat widget on Codefresh's support page.
Proprietary API
Regarding the Codefresh API, I had not spotted that the domain g.codefresh.io is the same as their control panel. So, to authenticate, all I had to do was log into the control panel - oops! That reveals the call to https://g.codefresh.io/api/images and a much more complicated access token than I've been using - perhaps it is OAuth. It looks like this:
curl \
-X GET \
--header "Accept: application/json" \
--header "x-access-token: (36chars).(143chars).(22chars)-(4chars)-(15chars)" \
"https://g.codefresh.io/api/images"
As I considered in the question, it does look like the /api/images endpoint is for Codefresh builds only. So, this is out for me - I want everything in the registry.
Open API
So, turning to Docker's open standard for accessing registry, my support contact said this:
if you want to connect to cfcr.io through docker CLI, you can.
The username is your username at Codefresh. The password is a token you can generate at user settings -> "GENERATE" button at the Codefresh registry section.
That's what I've been doing so far, and it works for login, push and pull. It does not seem to work for the reg utility in ls mode though. Either I am still doing something wrong, or there are restrictions at Codefresh as to how the private registry may be used.
Unfortunately, it's not possible to use search and catalog commands for Codefresh Registry. The Codefresh registry (r.cfcr.io) is based on Google Container Registry (aka GCR) and Google Registry does not implement v1 Docker registry API and _catalog function.
Once they do, things will work for Codefresh Registry too.

Resources