github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/docs/nginx.md (about) 1 <!--[metadata]> 2 +++ 3 title = "Authenticating proxy with nginx" 4 description = "Restricting access to your registry using a nginx proxy" 5 keywords = ["registry, on-prem, images, tags, repository, distribution, nginx, proxy, authentication, TLS, recipe, advanced"] 6 +++ 7 <![end-metadata]--> 8 9 # Authenticating proxy with nginx 10 11 12 ## Use-case 13 14 People already relying on a nginx proxy to authenticate their users to other services might want to leverage it and have Registry communications tunneled through the same pipeline. 15 16 Usually, that includes enterprise setups using LDAP/AD on the backend and a SSO mechanism fronting their internal http portal. 17 18 ### Alternatives 19 20 If you just want authentication for your registry, and are happy maintaining users access separately, you should really consider sticking with the native [basic auth registry feature](deploying.md#native-basic-auth). 21 22 ### Solution 23 24 With the method presented here, you implement basic authentication for docker engines in a reverse proxy that sits in front of your registry. 25 26 While we use a simple htpasswd file as an example, any other nginx authentication backend should be fairly easy to implement once you are done with the example. 27 28 We also implement push restriction (to a limited user group) for the sake of the example. Again, you should modify this to fit your mileage. 29 30 ### Gotchas 31 32 While this model gives you the ability to use whatever authentication backend you want through the secondary authentication mechanism implemented inside your proxy, it also requires that you move TLS termination from the Registry to the proxy itself. 33 34 Furthermore, introducing an extra http layer in your communication pipeline will make it more complex to deploy, maintain, and debug, and will possibly create issues. Make sure the extra complexity is required. 35 36 For instance, Amazon's Elastic Load Balancer (ELB) in HTTPS mode already sets the following client header: 37 38 ``` 39 X-Real-IP 40 X-Forwarded-For 41 X-Forwarded-Proto 42 ``` 43 44 So if you have an nginx sitting behind it, should remove these lines from the example config below: 45 46 ``` 47 X-Real-IP $remote_addr; # pass on real client's IP 48 X-Forwarded-For $proxy_add_x_forwarded_for; 49 X-Forwarded-Proto $scheme; 50 ``` 51 52 Otherwise nginx will reset the ELB's values, and the requests will not be routed properly. For more information, see [#970](https://github.com/docker/distribution/issues/970). 53 54 ## Setting things up 55 56 Read again [the requirements](recipes.md#requirements). 57 58 Ready? 59 60 -- 61 62 Create the required directories 63 64 ``` 65 mkdir -p auth 66 mkdir -p data 67 ``` 68 69 Create the main nginx configuration you will use. 70 71 ``` 72 73 cat <<EOF > auth/nginx.conf 74 upstream docker-registry { 75 server registry:5000; 76 } 77 78 ## Set a variable to help us decide if we need to add the 79 ## 'Docker-Distribution-Api-Version' header. 80 ## The registry always sets this header. 81 ## In the case of nginx performing auth, the header will be unset 82 ## since nginx is auth-ing before proxying. 83 map \$upstream_http_docker_distribution_api_version \$docker_distribution_api_version { 84 'registry/2.0' ''; 85 default registry/2.0; 86 } 87 88 server { 89 listen 443 ssl; 90 server_name myregistrydomain.com; 91 92 # SSL 93 ssl_certificate /etc/nginx/conf.d/domain.crt; 94 ssl_certificate_key /etc/nginx/conf.d/domain.key; 95 96 # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html 97 ssl_protocols TLSv1.1 TLSv1.2; 98 ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; 99 ssl_prefer_server_ciphers on; 100 ssl_session_cache shared:SSL:10m; 101 102 # disable any limits to avoid HTTP 413 for large image uploads 103 client_max_body_size 0; 104 105 # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) 106 chunked_transfer_encoding on; 107 108 location /v2/ { 109 # Do not allow connections from docker 1.5 and earlier 110 # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents 111 if (\$http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*\$" ) { 112 return 404; 113 } 114 115 # To add basic authentication to v2 use auth_basic setting. 116 auth_basic "Registry realm"; 117 auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd; 118 119 ## If $docker_distribution_api_version is empty, the header will not be added. 120 ## See the map directive above where this variable is defined. 121 add_header 'Docker-Distribution-Api-Version' \$docker_distribution_api_version always; 122 123 proxy_pass http://docker-registry; 124 proxy_set_header Host \$http_host; # required for docker client's sake 125 proxy_set_header X-Real-IP \$remote_addr; # pass on real client's IP 126 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; 127 proxy_set_header X-Forwarded-Proto \$scheme; 128 proxy_read_timeout 900; 129 } 130 } 131 EOF 132 ``` 133 134 Now, create a password file for "testuser" and "testpassword" 135 136 ``` 137 docker run --entrypoint htpasswd httpd:2.4 -bn testuser testpassword > auth/nginx.htpasswd 138 ``` 139 140 Copy over your certificate files 141 142 ``` 143 cp domain.crt auth 144 cp domain.key auth 145 ``` 146 147 Now create your compose file 148 149 ``` 150 cat <<EOF > docker-compose.yml 151 nginx: 152 image: "nginx:1.9" 153 ports: 154 - 5043:443 155 links: 156 - registry:registry 157 volumes: 158 - `pwd`/auth/:/etc/nginx/conf.d 159 160 registry: 161 image: registry:2 162 ports: 163 - 127.0.0.1:5000:5000 164 volumes: 165 - `pwd`/data:/var/lib/registry 166 EOF 167 ``` 168 169 ## Starting and stopping 170 171 Now, start your stack: 172 173 docker-compose up -d 174 175 Login with a "push" authorized user (using `testuserpush` and `testpasswordpush`), then tag and push your first image: 176 177 docker login myregistrydomain.com:5043 178 docker tag ubuntu myregistrydomain.com:5043/test 179 docker push myregistrydomain.com:5043/test 180 docker pull myregistrydomain.com:5043/test