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