(LINUX) LINUX (2021)

Protect Docker Registry by Nginx

Original documentation is placed in this page https://docs.docker.com/registry/recipes/nginx/, but in this page I will investigate some another way.

1. Install docker compose.


# sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# sudo chmod +x /usr/local/bin/docker-compose
# sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# docker-compose --version

2. Create htpasswd file.


# sudo docker run --rm --entrypoint htpasswd registry:2.7.0 -Bbn registry XXXXXXXXXXX > ./auth/nginx.htpasswd     


3.1. Create self-signed certificate.


# mkdir -p auth data
# sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout auth/nginx-selfsigned.key -out auth/nginx-selfsigned.crt

3.2. Create composer definition with related Registry image, copy self-signed certificate to Nginx, and map port 5043->443 and 5000->80.


This is my first attempt. Line 11 and 12 is copy my self-signed certificate inside Nginx image, line 10 is Nginx config, and line 15 is my own implementation of docker Registry.


# cat registry-compose.yml

   1:  nginx:
   2:    image: "nginx:alpine"
   3:    ports:
   4:      - 5000:80
   5:      - 5043:443
   6:    links:
   7:      - registry:registry
   8:    volumes:
   9:      - ./auth:/etc/nginx/conf.d
  10:      - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
  11:      - ./auth/domain.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro
  12:      - ./auth/domain.key:/etc/ssl/private/nginx-selfsigned.key:ro
  13:   
  14:  registry:
  15:    image: 5-shit-money:latest
  16:      volumes:
  17:      - ./var/lib/registry:/var/lib/registry

3.3. Create proxy config.


In this case I created config follow documentation. Nginx will be listen port 443, select domain name and redirect stream to port 5000 (to Registry container). And of course handle file nginx.htpasswd inserting in YML file.


# cat auth/nginx.conf

   1:  events {
   2:      worker_connections  1024;
   3:  }
   4:   
   5:  http {
   6:   
   7:    upstream docker-registry {
   8:      server registry:5000;
   9:    }
  10:   
  11:    ## Set a variable to help us decide if we need to add the
  12:    ## 'Docker-Distribution-Api-Version' header.
  13:    ## The registry always sets this header.
  14:    ## In the case of nginx performing auth, the header is unset
  15:    ## since nginx is auth-ing before proxying.
  16:    map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
  17:      '' 'registry/2.0';
  18:    }
  19:   
  20:    server {
  21:      listen 443 ssl;
  22:      #listen 80;
  23:      server_name registry.XXXXXXXXXXX.io;
  24:   
  25:      # SSL
  26:      ssl_certificate /etc/nginx/conf.d/domain.crt;
  27:      ssl_certificate_key /etc/nginx/conf.d/domain.key;
  28:   
  29:      # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
  30:      ssl_protocols TLSv1.1 TLSv1.2;
  31:      ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  32:      ssl_prefer_server_ciphers on;
  33:      ssl_session_cache shared:SSL:10m;
  34:   
  35:      # disable any limits to avoid HTTP 413 for large image uploads
  36:      client_max_body_size 0;
  37:   
  38:      # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
  39:      chunked_transfer_encoding on;
  40:   
  41:      location /v2/ {
  42:        # Do not allow connections from docker 1.5 and earlier
  43:        # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
  44:        if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
  45:          return 404;
  46:        }
  47:   
  48:        # To add basic authentication to v2 use auth_basic setting.
  49:        auth_basic "Registry realm";
  50:        auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
  51:   
  52:        ## If $docker_distribution_api_version is empty, the header is not added.
  53:        ## See the map directive above where this variable is defined.
  54:        add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
  55:   
  56:        proxy_pass                          http://docker-registry;
  57:        proxy_set_header  Host              $http_host;   # required for docker client's sake
  58:        proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
  59:        proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
  60:        proxy_set_header  X-Forwarded-Proto $scheme;
  61:        proxy_read_timeout                  900;
  62:      }
  63:    }
  64:  }

3.4. Start compose as daemon with disconnected mode and with full log.

Composer can started in two mode, with full log.


# sudo docker-compose -f registry-compose.yml logs --follow


And in disconnected mode as daemon.

# sudo docker-compose -f registry-compose.yml up -d

3.5. Check endpoint with docker and CURL.


# sudo docker login -u=registry  https://registry.XXXXXXXXXXX.io:5043

And second way check external endpoint with authentication by curl.


# sudo curl -v --user registry:YYYYYYYYYYYYY https://localhost:5043/v2/_catalog


Unfortunately this way don't follow me to success, "x509: certificate signed by unknown authority".



But this is full workflow to set up authentication proxy to protect docker registry.

4.1. Create self-signed certificate.


This is temporary workable scheme for development process without AU and before certificate will be ready.


# cat registry-compose.yml

   1:  nginx:
   2:    # Note : Only nginx:alpine supports bcrypt.
   3:    # If you don't need to use bcrypt, you can use a different tag.
   4:    # Ref. https://github.com/nginxinc/docker-nginx/issues/29
   5:    image: "nginx:alpine"
   6:    ports:
   7:      - 6000:80
   8:    links:
   9:      - registry:registry
  10:    volumes:
  11:      - ./auth:/etc/nginx/conf.d
  12:      - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
  13:      - ./auth/domain.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro
  14:      - ./auth/domain.key:/etc/ssl/private/nginx-selfsigned.key:ro
  15:   
  16:  registry:
  17:    image: 5-shit-money:latest
  18:      #volumes:
  19:      #- ./var/lib/registry:/var/lib/registry

# cat auth/nginx.conf

   1:  events {
   2:      worker_connections  1024;
   3:  }
   4:   
   5:  http {
   6:   
   7:    upstream docker-registry {
   8:      server registry:5000;
   9:    }
  10:   
  11:    ## Set a variable to help us decide if we need to add the
  12:    ## 'Docker-Distribution-Api-Version' header.
  13:    ## The registry always sets this header.
  14:    ## In the case of nginx performing auth, the header is unset
  15:    ## since nginx is auth-ing before proxying.
  16:    map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
  17:      '' 'registry/2.0';
  18:    }
  19:   
  20:    server {
  21:      #listen 443 ssl;
  22:      listen 80;
  23:      server_name registry.XXXXXXXXXX.io;
  24:   
  25:      # SSL
  26:      #ssl_certificate /etc/nginx/conf.d/domain.crt;
  27:      #ssl_certificate_key /etc/nginx/conf.d/domain.key;
  28:   
  29:      # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
  30:      #ssl_protocols TLSv1.1 TLSv1.2;
  31:      #ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  32:      #ssl_prefer_server_ciphers on;
  33:      #ssl_session_cache shared:SSL:10m;
  34:   
  35:      # disable any limits to avoid HTTP 413 for large image uploads
  36:      client_max_body_size 0;
  37:   
  38:      # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
  39:      chunked_transfer_encoding on;
  40:   
  41:      location /v2/ {
  42:   
  43:        # To add basic authentication to v2 use auth_basic setting.
  44:        # auth_basic "Registry realm";
  45:        # auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
  46:   
  47:        ## If $docker_distribution_api_version is empty, the header is not added.
  48:        ## See the map directive above where this variable is defined.
  49:        add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
  50:   
  51:        proxy_pass                          http://docker-registry;
  52:        proxy_set_header  Host              $http_host;   # required for docker client's sake
  53:        proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
  54:        proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
  55:        proxy_set_header  X-Forwarded-Proto $scheme;
  56:        proxy_read_timeout                  900;
  57:      }
  58:    }
  59:  }




Comments ( )
Link to this page: http://www.vb-net.com/DockerRegistryProxy/Index.htm
< THANKS ME>