1. 程式人生 > >在 ubuntu 搭建需要簽名認證的私有 docker registry 倉庫

在 ubuntu 搭建需要簽名認證的私有 docker registry 倉庫

.com chunked required 社區 apach proto remote tps grep

前言

在前面的一篇博客《在 ubuntu 搭建 docker registry 私有倉庫》介紹了一種簡單的搭建 docker 私有倉庫了的方法。但是當時使用的是修改“--insecure-registry”參數的辦法,這種辦法在局域網中使用,還勉強合適。但如果要搭建一個生產環境的私有倉庫服務器,就存在很大的安全風險了。所以,這裏介紹一種使用簽名認證的實現方式,主要通過nginx 的反向代理,將不受信任的客戶端請求都拒絕,以達到安全的目的。

實驗環境

服務端系統: ubuntu 16.04  
                      docker  17.12.0-ce

客戶端系統: ubuntu  14.04
                       docker  17.12.0-ce

如果想升級自己系統中的docker 版本,請參考這篇文章:《Ubuntu Docker 版本的更新與安裝》。
或者參考:《Docker ubuntu 16.04 安裝穩定版本,社區版版本》。

開始實驗

因為我們使用的是 nginx 服務作為安全認證的服務器,所以我們還需要安裝 apache2-utils ,這個是用來生成用戶和用戶密碼。我們這裏使用 docker-compse,用來定義和運行多個docker 容器。我們還需要使用curl 工具,這個主要用於測試實驗結果。

開始做實驗前,請確認已經安裝好docker-ce 的版本了。

下面開始做實驗。

1 安裝必要的工具

apt-get   install  -y  docker-compose  apache2-utils  curl  

2 創建一些文件目錄

mkdir  /docker-registry
mkdir  /docker-registry/data
mkdir  /docker-registry/nginx
chown  root:root  /docker-registry

cd   /docker-registry

3 創建 docker-compose.yml 文件(用於定義docker container properties)

root@ubuntu:/docker-registry# cat docker-compose.yml 

nginx:
  image: "nginx:1.9"
  ports:
    - 443:443
  links:
    - registry:registry
  volumes:
    - /docker-registry/nginx/:/etc/nginx/conf.d

registry:
  image: registry:2
  ports:
    - 127.0.0.1:5000:5000
  environment:
    REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
  volumes:
    - /docker-registry/data:/data

說明:
docker-compose.yml 文件首先會創建一個 registry 容器,它的5000端口和宿主機的5000端口映射。它存儲鏡像的目錄是 /data 目錄,與宿主機的 /docker-registry/data 綁定。

然後,nginx 容器也會被創建,nginx 容器通過 -link 參數,與 registry 容器連接,這樣nginx 容器就知道怎麽和 registry 容器通信了(其實,registry 容器的 IP 會被綁定在 nginx 容器的 /etc/hosts 文件)。

4 啟動容器

docker-compose  up

說明: 這條命令 docker-compose 會通過剛剛寫好的 docker-compose.yml 腳本,生成兩個容器,正常會是以下的輸出技術分享圖片
如果要停止,只能使用 (Ctrl + C )了。

如果想在後臺運行,可以使用

docker-compose   up   -d

創建 docker-registry.service 文件

因為 ubuntu 在14.01之前的版本都只支持upstart 的方式,所以,如果你想使用 systemd 的管理方式,則需要使用 ubuntu 15.01 以上的版本了。因此,我這裏使用了 ubuntu 16.04的系統版本,自帶了systemd 服務。

vi     /etc/systemd/system/docker-registry.service   :

[Unit]
Description=Starting docker registry

[Service]
Environment= MY_ENVIRONMENT_VAR = /docker-registry/docker-compose.yml
WorkingDirectory=/docker-registry
ExecStart=/usr/bin/docker-compose up
Restart=always

[Install]
WantedBy=multi-user.target

說明:現在,我們就能使用 service docker-registry start/stop/restart 的命令來管理 nginx 和 registry 容器了,非常方便。

測試:
技術分享圖片
說明一切正常。

好吧,從這裏開始,我們就可以使用 service docker-registry restart 來重啟容器了。

5 設置 nginx 服務的配置文件

vi /docker-registry/nginx/registry.conf

upstream docker-registry {
  server registry:5000;
}

server {
  listen 443;
  server_name myregistrydomain.com;

  # SSL
  # ssl on;
  # ssl_certificate /etc/nginx/conf.d/domain.crt;
  # ssl_certificate_key /etc/nginx/conf.d/domain.key;

  # disable any limits to avoid HTTP 413 for large image uploads
  client_max_body_size 0;

  # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
  chunked_transfer_encoding on;

  location /v2/ {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
      return 404;
    }

    # To add basic authentication to v2 use auth_basic setting plus add_header
    # auth_basic "registry.localhost";
    # auth_basic_user_file /etc/nginx/conf.d/registry.password;
    # add_header ‘Docker-Distribution-Api-Version‘ ‘registry/2.0‘ always;

    proxy_pass                          http://docker-registry;
    proxy_set_header  Host              $http_host;   # required for docker client‘s sake
    proxy_set_header  X-Real-IP         $remote_addr; # pass on real client‘s IP
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
}
測試
service  docker-registry   restart 
curl   http://localhost:5000/v2/

結果會是這樣:
{}root@ubuntu:/docker-registry#

6 設置安全權限認證,創建用戶

cd   /docker-registry/nginx
htpasswd -c registry.password mydocker
New password:
Re-type new password:
Adding password for user mydocker

說明:利用 apache2-utils 的 htpasswd 工具,創建一個包含用戶名和用戶密碼的文件

再次打開 registry.conf 文件
vi   /docker-registry/nginx/registry.conf
將下面幾行的註釋去掉
auth_basic "registry.localhost";
auth_basic_user_file /etc/nginx/conf.d/registry.password;
add_header ‘Docker-Distribution-Api-Version‘ ‘registry/2.0‘ always;
再測試
service docker-registry restart
curl  http://localhost:443/v2/
root@ubuntu:~/docker-registry/nginx#  curl http://localhost:5043/v2/401 Authorization Required
401 Authorization Required
nginx/1.9.15
用用戶名和用戶密碼再測試一次
curl http://mydocker:123456@localhost:443/v2/
{}root@ubuntu:~/docker-registry/nginx#

說明:到這裏,其實我們就完成了一個局域網的認證功能了,但是還不能作為一個服務器使用。因為,還需要設置ssl 安全認證。

7 設置 SSL 安全認證

7.1 再次打開 registry.conf 文件
vi  /docker-registry/nginx/registry.conf

將下面的幾行取消註釋並且修 域名:

upstream docker-registry {
server registry:5000;
}

server {
listen 443;
server_name docker-server.com;

# SSL
ssl on;
ssl_certificate /etc/nginx/conf.d/domain.crt;
ssl_certificate_key /etc/nginx/conf.d/domain.key;
7.2 創建 Certification Authority
cd  /docker-registry/nginx

創建新的 root key:

openssl genrsa -out dockerCA.key 2048

創建 root certificate
在Common Name 裏填入 docker-server.com 就可以了,其他內容隨便填。

openssl req -x509 -new -nodes -key dockerCA.key -days 10000 -out dockerCA.crt

創建 server key (這個是被nginx ssl_certificate_key 引用的)

openssl genrsa -out domain.key 2048

再創建一個新的 certificate
Common Name 繼續填 docker-server.com,不用設置密碼。

openssl req -new -key domain.key -out docker-registry.com.csr

最後,進行簽名:

openssl x509 -req -in docker-registry.com.csr -CA dockerCA.crt -CAkey dockerCA.key -CAcreateserial -out domain.crt -days 10000

復制 dockerCA.crt

cd /docker-registry/nginx
cp dockerCA.crt /usr/local/share/ca-certificates/

為了讓服務器信任我們的 Certification Authority 認證,我們需要

update-ca-certificates && service docker restart && service docker-registry restart

測試

curl https://mydocker:[email protected]/v2/
#output should be
{}root@ubuntu:/docker-registry/nginx#

8 將 dockerCA.crt 復制到客戶端

scp dockerCA.crt   [email protected]:/usr/local/share/ca-certificates
[email protected]‘s password:
dockerCA.crt 100% 1302 1.3KB/s 00:00

如果客戶端沒有 /usr/local/share/ca-certificates 目錄,則需要創建

9 客戶端登錄服務器倉庫

update-ca-certificates && service docker restart
#test login to fresh created repository:
docker login https://docker-server.com
Username: mydocker
Password:
Login Succeeded

需要在 /etc/hosts 文件中添加
192.168.188.113 docker-server.com #(這是我做實驗的服務端的 IP 地址)

9.1 在客戶端推送鏡像
docker  pull    ubuntu    # 嘗試在 docker hub 下載鏡像
docker  tag   ubuntu    docker-server.com/test-ubuntu  #  將鏡像打標簽,作為區別
docker   push  docker-server.com/test-ubuntu   # 推送到 私有 docker registry 倉庫

確認測試

在客戶端將 docker-server.com/test-ubunt 鏡像刪除:
docker   image  rm -f  ubuntu

從 docker-server.com 倉庫下載 test-ubnutn 鏡像:
docker   pull   docker-server.com/test-ubuntu

過程截圖:
技術分享圖片

ok,成功了。

如果在實驗的過程中遇到什麽問題,請查找docker 的日誌文件

journalctl -u docker # for docker logs in the systemd journal
journalctl | grep docker # for system logs that mention docker

總結

主要利用裏nginx 的反向代理服務器的功能,實現了安全認證管理,加強了訪問私有倉庫的安全權限管理。

參考文章:
《Private Docker Registry in Ubuntu Server 16.04》

在 ubuntu 搭建需要簽名認證的私有 docker registry 倉庫