搭建安全的本地Docker Registry
在很多场景下,需要自行搭建本地Docker镜像库,用于存储和维护开发的应用镜像。Docker官方提供了两种Registry:一种为Docker Registry,另一种为Docker Trusted Registry(DTR),其中后者为商业版本,较前者增加了LDAP集成、安全扫描等功能,为付费套餐的一部分,本文介绍第一种镜像库安装方法。
安装Docker CE
安装方法参考官方教程,在Kali Linux中安装可参考博客Kali 2018.1 中安装Docker CE。
创建data文件夹
创建文件夹存放镜像库中的内容:
$ mkdir data
使用基础认证
创建文件夹存放密码文件,假设创建的用户名为testuser,密码为testpassword:
$ mkdir auth
$ docker run \
--entrypoint htpasswd \
registry:2 -Bbn testuser testpassword > auth/htpasswd
增加TLS加密支持
使用基础认证时,必须要增加TLS加密支持,否则用户的登录信息将通过明文传输。下面分别介绍持有证书、使用Let's Encrypt免费证书和使用自签名证书的配置方法。
持有证书
满足下列条件条件:
- 拥有注册的域名
https://your.domain.com。 - 域名指向的主机443端口可访问
- 从认证机构(CA)获取证书
- 创建
certs文件夹
$ mkdir certs
讲证书.crt和.key文件复制到certs文件夹中,下文假设文件名分别为domian.crt和domain.key。
- 启动registry容器
$ sudo docker run -d \
--restart=always \
--name registry \
-v `pwd`/data:/var/lib/registry \
-v `pwd`/auth:/auth \
-v `pwd`/certs:/certs \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" \
-e "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" \
-p 443:443 \
registry:2
使用Let's Encrypt免费证书
Docker Registry官方支持使用Let's Encrypt提供免费的可信证书,但在2018年1月开始,Let's Encrypt出于安全性考虑,取消了TLS-SNI challenge,因此根据官方教程使用Let's Encrypt为Docker Registry提供认证已经无法工作,见官方issue,Docker开发者正在解决该问题。
下面给出按照官方教程,使用Let's Encrypt进行认证的运行命令,现在已无法正常使用,待后续有新的进展后更新该部分内容:
$ touch letsencrypt.json
$ sudo docker run -d \
--restart=always \
--name registry \
-v `pwd`/data:/var/lib/registry \
-v `pwd`/auth:/auth \
-v `pwd`/certs:/certs \
-v `pwd`/letsencrypt.json:/etc/docker/registry/letsencrypt.json \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_LETSENCRYPT_CACHEFILE=/etc/docker/registry/letsencrypt.json" \
-e "REGISTRY_HTTP_HOST=https://your.domain.com" \
-e "REGISTRY_HTTP_TLS_LETSENCRYPT_EMAIL=your@email.com" \
-p 443:443 \
registry:2
该方法已经无法正常使用,下面给出另一种可用的方法。采用文章Docker环境中使用Let's Encrypt为Nginx提供免费SSL证书中的方法生成证书。
然后运行Registry容器
$ sudo docker run -d \
--restart=always \
--name registry \
-v `pwd`/data:/var/lib/registry \
-v `pwd`/auth:/auth \
-v /data/certbot/letsencrypt:/certs \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/live/your.domain.com/fullchain.pem" \
-e "REGISTRY_HTTP_TLS_KEY=/certs/live/your.domain.com/privkey.pem" \
-p 443:443 \
registry:2
即可成功使用Let's Encrypt证书,证书有效期为90天,其更新方法见文章Docker环境中使用Let's Encrypt为Nginx提供免费SSL证书。
使用自签名证书
在没有CA发布的证书时,可使用自签名证书,该方法仅建议在测试或开发环境中使用。
- 生成自签名证书
$ mkdir -p certs
$ openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt
在交互过程中,使用域名your.domain.com作为CN。如没有注册的域名,可自行选取域名,然后更改本机的hosts文件,添加该域名到自身的解析。
- 使用与持有证书相同的命令运行Registry
$ sudo docker run -d \
--restart=always \
--name registry \
-v `pwd`/data:/var/lib/registry \
-v `pwd`/auth:/auth \
-v `pwd`/certs:/certs \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" \
-e "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" \
-p 443:443 \
registry:2
- DNS设置(仅无注册域名时)
对于没有注册域名的用户,可自行选取域名,确保第1步中CN设置与其相同。然后更改hosts文件,添加解析。
本机添加解析记录:在本机的/etc/hosts文件中,127.0.0.1一行后添加your.domain.com。
其他运行Docker daemon的主机:在其/etc/hosts文件中,添加your.domain.com到Registry主机IP地址的解析。
- 其他主机导入证书
其他需要使用Docker Registry服务的主机中,需要导入Registry的证书,使其信任Registry主机。
将domain.crt文件复制为其他主机的/etc/docker/certs.d/your.domain.com/ca.crt文件。
使用本地Registry
- 在Docker Hub中下载镜像
$ sudo docker pull alpine
- 修改tag
容器镜像的tag由两个部分构成,第一个部分包括主机名和端口,第二个部分为镜像名和版本号,版本号缺省情况下为latest。
$ sudo docker tag alpine your.domain.com/alpine
- 登录本地Registry
使用创建的用户名testuser和密码testpassword登录本地Registry。
$ sudo docker login your.domain.com
- Push镜像到本地Registry
$ sudo docker push your.domain.com/alpine
- 删除本机保存的镜像
$ sudo docker rmi alpine
$ sudo docker rmi your.domain.com/alpine
- 在本地Registry中拉取镜像
$ sudo docker pull your.domain.com/alpine