8

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
kazanaki
  • 7,988
  • 8
  • 52
  • 79
halfer
  • 19,824
  • 17
  • 99
  • 186
  • I'm not completely sure, but I think that something is retrieved by `docker login` for future API access. It is stored in `~/.docker/`. – Robert Oct 21 '17 at 20:21
  • You don't have to use the password (which they call token) for future API access. It is used what `docker login` retrieve. See https://docs.docker.com/registry/spec/auth/token/#requirements – Robert Oct 21 '17 at 20:27
  • Thanks @Robert. I gave this a little try, but to no avail. The link you've supplied gives some information about OAuth tokens, which look different to the token in my `.docker/config.json`. Tomorrow I will get some time to add these attempts to the question, but broadly they end in the same `UNAUTHORIZED_ERROR`. – halfer Oct 22 '17 at 09:10
  • I have checked it seems the `_catalog` is not still not accessible even when you give the token. `curl -H "User-Agent: MyClient" --header "Authorization: Authorization: Bearer ..." "https://r.cfcr.io/v2/_catalog" {"errors":[{"code":"UNAUTHORIZED","message":"Expected Bearer auth token in Authorization header."}]}%`. Though I am able to make other calls – Tarun Lalwani Oct 22 '17 at 11:14
  • Ah, thanks @Tarun. I am only passingly familiar with OAuth - is `Authorization: Bearer` the header I need to pass? I've been using `x-access-token`, but I have lost track of whether this is for the open standard Docker API or the proprietary Codefresh API. – halfer Oct 24 '17 at 08:54
  • Seems they have a custom registry and don't implement a `_catalog` and it uses OAuth. The `x-access-token` is for their own API and not for docker registry. So I doubt there is anyway listing all available images, until they expose that – Tarun Lalwani Oct 24 '17 at 09:00
  • Alright, thanks for your efforts @Tarun, appreciated. Would you put an answer, and I will give it the bounty if no other answers appear at expiry time. I may see if I can get in touch with a CF support channel to tempt them into answering also! – halfer Oct 24 '17 at 09:07
  • @Robert: your suggest got me a bit further, thanks (see my third update). However, the registry appears to be empty, so it does rather look like this isn't working (or isn't meant to). – halfer Oct 24 '17 at 10:00
  • @halfer nice job. – Robert Oct 24 '17 at 10:04

3 Answers3

3

You need to first generate a token on CodeFresh User Settings

Docker token

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:

EveryRepo

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
halfer
  • 19,824
  • 17
  • 99
  • 186
Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • Thank you for your great effort. You clearly know the Docker open API way better than me, and if it has got you stumped, I don't have a cat-in-hell's chance `:=)`. I will speak to them again in due course. I did notice, interestingly, that mine is the only Codefresh question on Stack Overflow, so perhaps they are a new start-up, and there are some buglets to iron out. – halfer Oct 24 '17 at 11:01
  • Thanks for that. I don't think there's any value in posting the whole list of users/images, but I will ping CF engineers in chat just now. As you say, there is not much of a sec issue here, but certainly something CF may wish to address. – halfer Oct 24 '17 at 17:57
  • (Whilst your solution would be useful, I imagine CF may wish to stop it happening, so I suspect it would not be something I could rely on `:-)`. I have pointed them here.) – halfer Oct 24 '17 at 18:06
  • 1
    @halfer, its not usable also because you can paginate but you don't know when your repos would come. So it is of no use – Tarun Lalwani Oct 24 '17 at 18:08
  • Just an additional thought on this: would you consider adding your approach to getting the catalogue in a couple of weeks? Even though this is not a pressing sec issue, that strikes me as following the rules of responsible disclosure. – halfer Oct 26 '17 at 17:55
  • I don't have a problem sharing it now also. I would do it when you say. Also on a side note, this was a lot of effort, Alexei's answer was a pointer showing that the repo is GCR backed, but this should be the actual answer as it shows how it needs to be done which the main Qs was about. Just my thought on it :-) – Tarun Lalwani Oct 26 '17 at 18:15
  • Thanks, agree with that. As for credit, I was planning to give Alexei the acceptance, and you the bounty, since I like to reward as many helpful people as possible. I'd prefer it that way around, since your effort was the greatest. Does that seem OK? – halfer Oct 26 '17 at 19:40
  • Yes, that should be OK too – Tarun Lalwani Oct 26 '17 at 20:17
  • Hi Tarun. Would you be willing to update your answer with your technique to list all images? It's been around three weeks, and if this is something that CodeFresh were to fix, they have had ample opportunity. – halfer Nov 16 '17 at 22:24
  • Marvellous, thanks. I will send a reminder to CF to see if they wish to address it (if they have not done so already). – halfer Nov 17 '17 at 08:59
  • I don't recall if I contacted Code Fresh via their chat widget, but Alexei on this page has not replied in some months, despite having signed in. I have pinged CF on their chat widget just now, and will update with whatever replies I get. – halfer Jan 30 '18 at 13:28
  • Well, CF were going to get in touch again, and again did not. I perhaps should move my images from there, since this sort of thing makes me nervous about security generally. Putting it on the task list! – halfer Mar 03 '18 at 23:15
2

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.

Community
  • 1
  • 1
halfer
  • 19,824
  • 17
  • 99
  • 186
2

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.

Alexei
  • 21
  • 1
  • Hi Alexei. Tarun has now updated his post to show how all users' usernames and private image names may be fully indexed on the Code Fresh registry server. I advised this to one of your colleagues via the chat widget a few weeks ago, and they said they'd look into it. Would you advise me here as to whether this behaviour could be modified, since there's no good reason to grant this access? Tarun says the images can't be pulled, thankfully, but it would be good to plug this nevertheless. – halfer Nov 21 '17 at 18:38