moby: Docker version 1.8.2 does not send auth header with PATCH HTTP request when pushing to default port
This issue is related to https://github.com/docker/docker/issues/16728 , but bear with me please. (bug report at the bottom)
Environment:
Docker registry (Artifactory) behind NginX. Port 443 (standard HTTPS) redirects to the Docker endpoint and should be used to access it. I am logged in through docker login
The problem:
-
docker push docker.int.domain.com:443/some-image
works -
docker push docker.int.domain.com/some-image
does not. The output:The push refers to a repository [docker.int.domain.com/testtest/ubuntu] (len: 1) 8d885ef1e201: Pushing [==================================================>] 30.9 MB unauthorized: The client does not have permission to push to the repository.
I had a look at NginX’s access logs and this is what I found:
- When pushing to the “port-less” address, the request is directed to the port 443, so those commands should behave the same way.
- The PATCH HTTP request does not contain auth header, yet all other requests do. This causes the push command to fail with
unauthorized: The client does not have permission to push to the repository.
This issue is present in version 1.8.2. With version 1.7.x pushing without explicitly specifying the port was possible.
NginX’s access log:
- The second column is the name of the authenticated user
- p: denotes port
- The last number is response HTTP code
docker push docker.int.domain.com/some-image
192.168.33.3 , - , [07/Dec/2015:14:32:04 +0100] , p:443 , "GET /v2/", 401
192.168.33.3 , melka , [07/Dec/2015:14:32:06 +0100] , p:443 , "HEAD /v2/testtest/ubuntu/(...)", 404
192.168.33.3 , melka , [07/Dec/2015:14:32:07 +0100] , p:443 , "POST /v2/testtest/ubuntu/(...)", 202
192.168.33.3 , - , [07/Dec/2015:14:33:08 +0100] , p:443 , "PATCH /v2/testtest/ubuntu/(...)" , 403
docker push docker.int.domain.com:443/some-image
192.168.33.3 , - , [07/Dec/2015:14:43:23 +0100] , p:443 , "GET /v2/", 401
192.168.33.3 , melka , [07/Dec/2015:14:43:24 +0100] , p:443 , "HEAD /v2/testtest/ubuntu/(...)", 404
192.168.33.3 , melka , [07/Dec/2015:14:43:24 +0100] , p:443 , "POST /v2/testtest/ubuntu/(...) HTTP/1.1", 202
192.168.33.3 , melka , [07/Dec/2015:14:43:27 +0100] , p:443 , "PATCH /v2/testtest/ubuntu/(...)", 202
192.168.33.3 , melka , [07/Dec/2015:14:43:27 +0100] , p:443 , "PUT /v2/testtest/ubuntu/(...)", 201
(...)
As you can see, for some reason when pushing without specifying port, the name is empty. That causes the push to fail. When a port is set, the push continues with more log messages below.
Just to be on the safe side, here is my NginX config: (I have tried removing the X-Forwarded-headers as suggested here https://docs.docker.com/registry/nginx/ - that did not help).
server {
listen 80;
server_name docker.int.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443;
server_name docker.int.domain.com;
ssl on;
ssl_certificate /etc/nginx/cert/artifactory-ca.crt;
ssl_certificate_key /etc/nginx/cert/artifactory-ca.key;
access_log /var/log/nginx/docker.int.domain.com.443.access.log myformat;
error_log /var/log/nginx/docker.int.domain.com.443.error.log;
proxy_set_header Host $host:443;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Original-URI $request_uri;
proxy_pass_header Server; # To help debugging, list the server that actually did the reply rather than nginx
proxy_read_timeout 900;
client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
location /v2 {
proxy_pass http://localhost:8081/artifactory/api/docker/docker/v2;
}
}
We want to be able to refer to the repository just by the server name, without having to specify the port. But right now, that is only possible using the older docker client.
Thanks for taking a look at this
BUG REPORT INFORMATION
docker version:
Client:
Version: 1.8.2
API version: 1.20
Package Version: docker-1.8.2-7.el7.centos.x86_64
Go version: go1.4.2
Git commit: bb472f0/1.8.2
Built:
OS/Arch: linux/amd64
docker info:
Containers: 3
Images: 17
Storage Driver: devicemapper
Pool Name: docker-253:0-69269427-pool
Pool Blocksize: 65.54 kB
Backing Filesystem: xfs
Data file: /dev/loop0
Metadata file: /dev/loop1
Data Space Used: 4.353 GB
Data Space Total: 107.4 GB
Data Space Available: 8.753 GB
Metadata Space Used: 3.731 MB
Metadata Space Total: 2.147 GB
Metadata Space Available: 2.144 GB
Udev Sync Supported: true
Deferred Removal Enabled: false
Data loop file: /var/lib/docker/devicemapper/devicemapper/data
Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
Library Version: 1.02.93-RHEL7 (2015-01-28)
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.10.0-229.14.1.el7.x86_64
Operating System: CentOS Linux 7 (Core)
CPUs: 2
Total Memory: 3.703 GiB
Name: localhost.localdomain
ID: UGHD:SKNU:RRGU:GERL:KGDA:3Q7I:T5L5:LWGO:AM2Z:LTRX:MIX4:XBK3
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
uname -a:
Linux localhost.localdomain 3.10.0-229.14.1.el7.x86_64 #1 SMP Tue Sep 15 15:05:51 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Running in VirtualBox.
List the steps to reproduce the issue:
- Have a registry behind NginX (I have Artifactory-based)
- Set up NginX so that the registry is accessible on port 443.
- Push an image to the registry, without specifying the port number
Describe the results you received:
- I expect the image to be pushed successfully, because port 443 is the default.
Describe the results you expected:
- The push fails with an error:
unauthorized: The client does not have permission to push to the repository.
----------END REPORT ---------
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 18 (6 by maintainers)
Commits related to this issue
- Merge branch 'host-header-exclude-std-ports' into 'master' Exclude standard ports from Host header Docker registry does not behave properly when standard ports are included. See https://github.com/d... — committed to gitlabhq/omnibus-gitlab by maxlazio 8 years ago
- Merge branch 'host-header-exclude-std-ports' into 'master' Exclude standard ports from Host header Docker registry does not behave properly when standard ports are included. See https://github.c... — committed to gitlabhq/omnibus-gitlab by maxlazio 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to stanhu/distribution by stanhu 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to stanhu/distribution by stanhu 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to stanhu/distribution by stanhu 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to stanhu/distribution by stanhu 8 years ago
- Merge branch 'host-header-exclude-std-ports' into 'master' Exclude standard ports from Host header Docker registry does not behave properly when standard ports are included. See https://github.com/d... — committed to gitlabhq/omnibus-gitlab by maxlazio 8 years ago
- Merge branch 'host-header-exclude-std-ports' into 'master' Exclude standard ports from Host header Docker registry does not behave properly when standard ports are included. See https://github.com/d... — committed to gitlabhq/omnibus-gitlab by maxlazio 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to stanhu/distribution by stanhu 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to sergeyfd/distribution by stanhu 8 years ago
- Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail beca... — committed to dalsh/distribution by stanhu 8 years ago
- UPSTREAM: docker/distribution: drop: Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH reques... — committed to dmage/origin by stanhu 8 years ago
- UPSTREAM: docker/distribution: <drop>: Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH requ... — committed to dmage/origin by stanhu 8 years ago
Based on the investigation I have done so far, it seems like it is because the Host header contains the default port of 443, the docker registry sends back a Location header with a URL which also contains the port 443 thereby making docker client/engine to think this is a different registry. I think the fix should be to not have the default ports in the URL when sending back the Location headers.
I had the same issue described here. After some playing with the registry config I found that changing REGISTRY_HTTP_HOST: https://address:443 to https://address solved the issue and PATCH and PUT both sent the credentials, whereas before only POST would.