With default haproxy router, if I expose registry on port 5000, the router strips the port on each request from Host header.
When registry redirects the client as a response to POST request initiating blob upload, it will use just the url in Host header as a base for the value in Location header.
During the next client request, the Location will be used resulting in failure because port 80 is not exposed.
Version
master
Steps To Reproduce
- deploy registry
- deploy router like this:
oadm router router --ports 5000:5000 -o json | oc env -f - --output=json ROUTER_SERVICE_HTTP_PORT=5000 | oc create -n default -f -
- expose the registry using route:
oc expose service docker-registry --hostname=registry.f24-ose.vm -n default
- Add
--insecure-registry=registry.f24-ose.vm:5000 to docker daemon's flags.
docker login -u unused -p $(oc whoami -t) -e unused registry.f24-ose.vm:5000
docker tag busybox registry.f24-ose.vm:5000/$proj/buxybox
docker push registry.f24-ose.vm:5000/$proj/buxybox
Current Result
The push fails on PATCH request: Upload failed: dial tcp 192.168.100.80:80: getsockopt: connection refused (extracted from docker daemon log).
Note the port 80 as a result of Location header in registry's response to POST: http://registry.f24-ose.vm/v2/pjoe/hello-world/blobs/uploads/3d70392c-0751-4190-9508-ab9efb450d99?_state=6VTnYEsxOJZCFVr8zthbXcPCV4t4S__QMsNL1OCLHaN7Ik5hbWUiOiJwam9lL2hlbGxvLXdvcmxkIiwiVVVJRCI6IjNkNzAzOTJjLTA3NTEtNDE5MC05NTA4LWFiOWVmYjQ1MGQ5OSIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxNi0xMC0xMlQxMzo1MDozNS4xNjI4MDQ4MzlaIn0%3D
(Note the missing :5000).
Take a look at original request from docker daemon to registry's proxy:
GET /openshift/token?account=unused&scope=repository%3Apjoe%2Fhello-world%3Apush%2Cpull HTTP/1.1
Host: registry.f24-ose.vm:5000
User-Agent: docker/1.12.1 go/go1.7 git-commit/23cf638 kernel/4.7.6-1-ARCH os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.1 \(linux\))
Authorization: Basic dW51c2VkOlV1WGoyTGdTWkk4TGc0azY1bXFwc3ZlT1VKdXg1NnFDMTJXMThRdUdYOG8=
Accept-Encoding: gzip
Connection: close
And the same request going from proxy to registry application:
GET /openshift/token?account=unused&scope=repository%3Apjoe%2Fhello-world%3Apush%2Cpull HTTP/1.1
Host: registry.f24-ose.vm
User-Agent: docker/1.12.1 go/go1.7 git-commit/23cf638 kernel/4.7.6-1-ARCH os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.1 \(linux\))
Authorization: Basic dW51c2VkOlV1WGoyTGdTWkk4TGc0azY1bXFwc3ZlT1VKdXg1NnFDMTJXMThRdUdYOG8=
Accept-Encoding: gzip
Connection: close
X-Forwarded-Host: registry.f24-ose.vm
X-Forwarded-Port: 5000
X-Forwarded-Proto: http
Forwarded: for=192.168.100.80;host=registry.f24-ose.vm;proto=http
X-Forwarded-For: 192.168.100.80
The registry takes just a value of X-Forwarded-Host to form redirect location url. It pays no attention to X-Forwarded-Port which is far less common.
Expected Result
Proxy should pass the Host header unmodified (including the port) to the exposed service if it is serving on non-default port. Also for and host parameters of Forwarded header need to include the same port.
Additional info
The above is addressed by #11391 which makes the registry smarter. Nevertheless, to avoid problems with ingenuous services, router should forward proper values.
This is reopened on behalf of docker/distribution upstream which considers our port forwarding wrong:
Also, it looks like the implementation of Forwarded in your examples is not following the rfc7230, in that it is missing a port.
See the whole discussion at distribution/distribution#2008.
With default haproxy router, if I expose registry on port
5000, the router strips the port on each request fromHostheader.When registry redirects the client as a response to POST request initiating blob upload, it will use just the url in
Hostheader as a base for the value inLocationheader.During the next client request, the
Locationwill be used resulting in failure because port80is not exposed.Version
master
Steps To Reproduce
oadm router router --ports 5000:5000 -o json | oc env -f - --output=json ROUTER_SERVICE_HTTP_PORT=5000 | oc create -n default -f -oc expose service docker-registry --hostname=registry.f24-ose.vm -n default--insecure-registry=registry.f24-ose.vm:5000to docker daemon's flags.docker login -u unused -p $(oc whoami -t) -e unused registry.f24-ose.vm:5000docker tag busybox registry.f24-ose.vm:5000/$proj/buxyboxdocker push registry.f24-ose.vm:5000/$proj/buxyboxCurrent Result
The push fails on
PATCHrequest:Upload failed: dial tcp 192.168.100.80:80: getsockopt: connection refused(extracted from docker daemon log).Note the port 80 as a result of
Locationheader in registry's response toPOST:http://registry.f24-ose.vm/v2/pjoe/hello-world/blobs/uploads/3d70392c-0751-4190-9508-ab9efb450d99?_state=6VTnYEsxOJZCFVr8zthbXcPCV4t4S__QMsNL1OCLHaN7Ik5hbWUiOiJwam9lL2hlbGxvLXdvcmxkIiwiVVVJRCI6IjNkNzAzOTJjLTA3NTEtNDE5MC05NTA4LWFiOWVmYjQ1MGQ5OSIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxNi0xMC0xMlQxMzo1MDozNS4xNjI4MDQ4MzlaIn0%3D(Note the missing
:5000).Take a look at original request from docker daemon to registry's proxy:
And the same request going from proxy to registry application:
The registry takes just a value of
X-Forwarded-Hostto form redirect location url. It pays no attention toX-Forwarded-Portwhich is far less common.Expected Result
Proxy should pass the
Hostheader unmodified (including the port) to the exposed service if it is serving on non-default port. Alsoforandhostparameters ofForwardedheader need to include the same port.Additional info
The above is addressed by #11391 which makes the registry smarter. Nevertheless, to avoid problems with ingenuous services, router should forward proper values.
This is reopened on behalf of docker/distribution upstream which considers our port forwarding wrong:
See the whole discussion at distribution/distribution#2008.