搭建安全的本地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)获取证书
  1. 创建certs文件夹
$ mkdir certs

讲证书.crt.key文件复制到certs文件夹中,下文假设文件名分别为domian.crtdomain.key

  1. 启动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发布的证书时,可使用自签名证书,该方法仅建议在测试或开发环境中使用。

  1. 生成自签名证书
$ 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文件,添加该域名到自身的解析。

  1. 使用与持有证书相同的命令运行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
  1. DNS设置(仅无注册域名时)

对于没有注册域名的用户,可自行选取域名,确保第1步中CN设置与其相同。然后更改hosts文件,添加解析。

本机添加解析记录:在本机的/etc/hosts文件中,127.0.0.1一行后添加your.domain.com

其他运行Docker daemon的主机:在其/etc/hosts文件中,添加your.domain.com到Registry主机IP地址的解析。

  1. 其他主机导入证书

其他需要使用Docker Registry服务的主机中,需要导入Registry的证书,使其信任Registry主机。

domain.crt文件复制为其他主机的/etc/docker/certs.d/your.domain.com/ca.crt文件。

使用本地Registry

  1. 在Docker Hub中下载镜像
$ sudo docker pull alpine
  1. 修改tag

容器镜像的tag由两个部分构成,第一个部分包括主机名和端口,第二个部分为镜像名和版本号,版本号缺省情况下为latest

$ sudo docker tag alpine your.domain.com/alpine
  1. 登录本地Registry

使用创建的用户名testuser和密码testpassword登录本地Registry。

$ sudo docker login your.domain.com
  1. Push镜像到本地Registry
$ sudo docker push your.domain.com/alpine
  1. 删除本机保存的镜像
$ sudo docker rmi alpine
$ sudo docker rmi your.domain.com/alpine
  1. 在本地Registry中拉取镜像
$ sudo docker pull your.domain.com/alpine