Reputation: 2798
Inspired by this article https://www.jfrog.com/knowledge-base/how-do-i-access-multiple-artifactory-docker-repositories-from-a-single-url/ we have configured multiple docker repositories on artifactory using nginx as reverse proxy.
There are three docker repositories accessible:
All three repos have their own users with the permissions.
Pull is fine, but push to repository-a or repository-b do not work properly if user is not allowed to push to default repository. All uploads during the push are stored in the default repository first and only at the end they are moved to repository-a.
As I can see in artifactory logs, when I'm pushing something like
docker push docker.acme.com/repository-a/myimage:1.0.0
docker does some POST requests, receives from artifactory upload locations and proceeds with PATCH to upload layers. But responses from artifactory do not contain any repository path in the Location:
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http upstream request:
"/artifactory/api/docker/repository-a/v2/myimage/blobs/uploads/?
from=repository-
a%2Fmyimage&mount=sha256%3A6a8bd10c9278a8e1b59bc85f634dd4045e953
63c3b29366e9e8200ac2cd56735"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http upstream process
header
2017/11/08 12:35:17 [debug] 19310#0: *6107899 malloc:
0000000000EA8EF0:4096
2017/11/08 12:35:17 [debug] 19310#0: *6107899 recv: fd:23 427 of 4096
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy status 202
"202 Accepted"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy header:
"Server: Artifactory/5.0.1"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy header: "X-
Artifactory-Id: 1cfb2a5a96486c54:43202ab7:15ced9e7676:-8000"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy header:
"Docker-Distribution-Api-Version: registry/2.0"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy header:
"Docker-Upload-Uuid: d0d4ed31-6539-43a3-bb03-35e47fa13676"
2017/11/08 12:35:17 [debug] 19310#0: *6107899 http proxy header:
"Location: https://docker.acme.com/v2/myimage/blobs/uploads/d0d4ed31-
6539-43a3-bb03-35e47fa13676"
and thus all next PATCHes are going to the default repo but not to the repository-a.
Upvotes: 2
Views: 812
Reputation: 621
EDIT:
Nginx appears to be enforcing the "Internet Hosts" RFC to some extent (also see this wikipedia section), and would reject any Host headers that contain illegal characters in them, such as the slash character with a 400 response code. The article you referenced uses Apache, which does not appear to have similar restrictions on the Host header. You might be able to workaround this by finding a different character to use to separate the repository name in the Host header while still keeping it valid. This will obviously require adjustments in the reverse proxy configuration as well, particularly, for the part where the response Location header is being modified as explained below. However, I should have mentioned from the beginning that this solution is definitely a hack and probably not the most robust solution anyway, as it piggybacks on undocumented API behavior with Docker V2 repositories in Artifactory. It is particularly useful for users who cannot set up a flexible subdomain-based mechanism for docker repositories, because they are not able to use a wildcard certificate, for example. That said, if you haven't done so already, you should at least consider using one of the two documented options in this page.
ORIGINAL ANSWER
It looks like the original POST request's "Host" header might not include the repository name in it, otherwise Artifactory would have included the physical repository name in the Location header of the response. The solution you referred to requires the Host header to be in the format of $host/$repo, i.e:
Host: docker.acme.com/repository-a
Artifactory then constructs the Location header for the PATCH endpoint using this information. Here's a reproduction case with curl:
Good request:
curl -XPOST -H "Host: docker.acme.com/repository-a" "http://localhost:8080/artifactory/api/docker/repository-a/v2/myimage/blobs/uploads/?from=repository-a%2Fmyimage&mount=sha256%3A6a8bd10c9278a8e1b59bc85f634dd4045e95363c3b29366e9e8200ac2cd56735" -v
Good Location header in the response:
Location: https://docker.acme.com/repository-a/v2/myimage/blobs/uploads/fc325614-0e65-4c9a-a879-449ac9e8c66
A bad request would be:
curl -XPOST -H "Host: docker.acme.com" https://...
Note that the Location header has the "v2" and "repoName" elements in reversed order to how the Apache server would intercept them. The trick here is to change the order on the Apache config by editing the Location header of the response:
Header edit* Location "^https://<apache-server-name>/(.*?)/v2/(.*)$" "https://<apache-server-name>:<port#>/v2/$1/$2"
HTH,
Upvotes: 1