Yuvipanda has submitted this change and it was merged.

Change subject: docker: Add nginx frontend for registry
......................................................................


docker: Add nginx frontend for registry

- Limits PUT, POST, etc behind auth
- Allows anonymous GET access
- Put in a nginx hack to make it work

Change-Id: I7b9e3b5ff2e9821a7b1da9f4c981efab515dd8bb
---
M modules/docker/manifests/registry.pp
A modules/docker/templates/registry-nginx.conf.erb
M modules/role/manifests/toollabs/docker/registry.pp
3 files changed, 119 insertions(+), 15 deletions(-)

Approvals:
  Yuvipanda: Verified; Looks good to me, approved
  jenkins-bot: Verified



diff --git a/modules/docker/manifests/registry.pp 
b/modules/docker/manifests/registry.pp
index c45d0d4..aba26ad 100644
--- a/modules/docker/manifests/registry.pp
+++ b/modules/docker/manifests/registry.pp
@@ -1,5 +1,8 @@
 class docker::registry(
     $datapath = '/srv/registry',
+    $allow_push_from,
+    $ssl_certificate_name,
+    $ssl_settings,
 ){
 
     require_package('docker-registry')
@@ -23,20 +26,9 @@
             },
         },
         'http'     => {
-            'addr' => ':443',
+            'addr' => '127.0.0.1:5000',
             'host' => $::fqdn,
-            'tls'  => {
-                # FIXME: YOU SHOULD FEEL BAD ABOUT HARDCODING
-                'certificate' => '/var/lib/docker-registry/ssl/certs/cert.pem',
-                'key'         => 
'/var/lib/docker-registry/ssl/private_keys/server.key'
-            },
         },
-        'auth'     => {
-            'htpasswd' => {
-                'realm' => 'docker-auth',
-                'path'  => '/etc/docker/registry/htpasswd',
-            }
-        }
     }
 
     file { $datapath:
@@ -57,8 +49,8 @@
     $docker_password_hash = hiera('docker::password_hash')
     file { '/etc/docker/registry/htpasswd':
         content => "${docker_username}:${docker_password_hash}",
-        owner   => 'docker-registry',
-        group   => 'docker-registry',
+        owner   => 'www-data',
+        group   => 'www-data',
         mode    => '0440',
         notify  => Service['docker-registry'],
     }
@@ -86,4 +78,7 @@
             '/etc/docker/registry/config.yml'
         ]
     }
+    nginx::site { 'registry':
+        content => template('docker/registry-nginx.conf.erb'),
+    }
 }
diff --git a/modules/docker/templates/registry-nginx.conf.erb 
b/modules/docker/templates/registry-nginx.conf.erb
new file mode 100644
index 0000000..8a87839
--- /dev/null
+++ b/modules/docker/templates/registry-nginx.conf.erb
@@ -0,0 +1,99 @@
+upstream registry {
+  server 127.0.0.1:5000;
+}
+
+map $http_upgrade $connection_upgrade {
+    default upgrade;
+    '' close;
+}
+
+server {
+    listen 443 default_server ssl;
+    ssl_certificate /etc/ssl/localcerts/<%= @ssl_certificate_name 
%>.chained.crt;
+    ssl_certificate_key /etc/ssl/private/<%= @ssl_certificate_name %>.key;
+
+    # Copied from modules/tlsproxy/templates/nginx.conf.erb. Eugh
+    # Enable a shared cache, since it is defined at this level
+    # it will be used for all virtual hosts. 1m = 4000 active sessions,
+    # so we are allowing 200,000 active sessions.
+    ssl_session_cache shared:SSL:50m;
+    ssl_session_timeout 5m;
+
+    <%= @ssl_settings.join("\n") %>
+
+    # Images can be pretty large!
+    client_max_body_size 0;
+
+    # Avoids 411 errors!
+    chunked_transfer_encoding on;
+
+    # Tell everyone we're v2, not v1!
+    add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;
+
+    # Let me prefix by saying that the Docker v2 registry protocol apparently
+    # is much better than the v1 protocol. I have not read enough about both
+    # to make a comparative analysis, but I can tell that the auth design for
+    # v2 is just terribly done!
+    #
+    # So for a v2 to client to decide if it needs to authenticate or not, it
+    # first makes a GET request to /v2/, and based on wether it gets back a 2xx
+    # or a 401, decides to authenticate for all other requests in that session.
+    # This practically means it is really hard to do something like restrict
+    # write access to only a certain group while allowing read access to other
+    # groups - since it categorizes the whole registry based on the response
+    # code of one endpoint....
+    #
+    # I have hacked around this in the following manner:
+    #  - Tell nginx that you can be whitelisted by IP or by specifying a 
password
+    #  - Whitelist the whole world!
+    #  - Blacklist the one IP that needs to specify password (to push)
+    #
+    # This causes nginx to return a 401 only to the IP that I want to push, and
+    # since this IP will have the password it'll be able to authenticate. The
+    # rest of the world will just be allowed via IP, and hence not be asked for
+    # passwords.
+    #
+    # This special case handling is only for the root endpoint - all other 
endpoints
+    # are handled in the location stanza below this, and require 
authentication for
+    # POST/PUT/DELETE etc. We're only doing this special hack to convince the
+    # docker client to send/not send basic auth credentials depending on what 
we
+    # want them to do.
+    #
+    # Fuck you docker.
+    location = /v2/ {
+      satisfy any;
+
+      deny <%= @allow_push_from %>;
+      allow all;
+
+      auth_basic "docker-registry";
+      auth_basic_user_file /etc/docker/registry/htpasswd;
+
+      proxy_pass http://registry;
+      proxy_redirect off;
+      proxy_buffering off;
+      proxy_http_version 1.1;
+      proxy_set_header Host $host;
+    }
+
+    location /v2 {
+      # Require auth for POST, PUT, DELETE, ... requests
+      limit_except GET HEAD OPTIONS {
+        auth_basic "docker-registry";
+        auth_basic_user_file /etc/docker/registry/htpasswd;
+      }
+
+      add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;
+
+      proxy_pass http://registry;
+      proxy_redirect off;
+      proxy_buffering off;
+      proxy_http_version 1.1;
+      proxy_set_header Upgrade $http_upgrade;
+      proxy_set_header Connection $connection_upgrade;
+      proxy_set_header Proxy-Connection "Keep-Alive";
+      proxy_set_header X-Real-IP $remote_addr;
+      proxy_set_header X-Forwarded-Proto $scheme;
+      proxy_set_header Host $host;
+    }
+}
diff --git a/modules/role/manifests/toollabs/docker/registry.pp 
b/modules/role/manifests/toollabs/docker/registry.pp
index c8a71ed..1c7fa45 100644
--- a/modules/role/manifests/toollabs/docker/registry.pp
+++ b/modules/role/manifests/toollabs/docker/registry.pp
@@ -3,7 +3,17 @@
 
     require role::labs::lvm::srv
 
+    sslcert::certificate { 'star.tools.wmflabs.org':
+        skip_private => true,
+        before       => Class['::docker::registry'],
+    }
+
+    $builder = ipresolve(hiera('docker::builder_host'), 4, $::nameservers[0])
+
     class { '::docker::registry':
-        datapath => '/srv/registry',
+        datapath             => '/srv/registry',
+        allow_push_from      => $builder,
+        ssl_certificate_name => 'star.tools.wmflabs.org',
+        ssl_settings         => ssl_ciphersuite('nginx', 'compat'),
     }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/281998
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I7b9e3b5ff2e9821a7b1da9f4c981efab515dd8bb
Gerrit-PatchSet: 10
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Yuvipanda <[email protected]>
Gerrit-Reviewer: Yuvipanda <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to