Skip to content

Router forwards host urls without ports when serving on non-default ports #11820

Description

@miminar

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
  1. deploy registry
  2. 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 -
  3. expose the registry using route: oc expose service docker-registry --hostname=registry.f24-ose.vm -n default
  4. Add --insecure-registry=registry.f24-ose.vm:5000 to docker daemon's flags.
  5. docker login -u unused -p $(oc whoami -t) -e unused registry.f24-ose.vm:5000
  6. docker tag busybox registry.f24-ose.vm:5000/$proj/buxybox
  7. 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.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions