在 ubuntu 搭建需要簽名認證的私有 docker registry 倉庫
在前面的一篇博客《在 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 倉庫