私有docker registry的ssl访问实现

作者: My熊猫眼 | 来源:发表于2019-10-02 18:21 被阅读0次

    本文使用的docker registry并非官方的registry, 和official的registry的最大区别是:
    该registry是基于busybox来实现,所以里面没有任何openssl相关的信息, 也没有任何证书的信息. 关于个人这个registry image的生成请参照: 基于busybox的registry docker image

    docker默认情况下,连接registry 时,会使用https连接,如果我们的registry只是支持http连接,那么便会发生如下的错误:

    [root@localhost ~]#  docker pull -a 192.168.0.110:5000/panda/mysql
    Trying to pull repository 192.168.0.110:5000/panda/mysql ...
    Get https://192.168.0.110:5000/v1/_ping: http: server gave HTTP response to HTTPS client
    #这里就是说,客户端发送了https 请求,但是server给的response是http响应;这里客户端的请求就是docker pull -a 192.168.0.110:5000/panda/mysql。
    

    为了解决上述问题,我们有如下的A, B 两种方案:
    A. 配置docker 允许接收http响应,而不单单是接受https相应;具体方法如下:

    1. 查看man dockerd 帮助文档,有如下的一段:
           --insecure-registry=[]
             Enable insecure registry communication, i.e., enable un-encrypted and/or
             untrusted communication.
           List of insecure registries can contain an element with CIDR notation to
             specify a whole subnet. Insecure registries accept HTTP and/or accept HTTPS
             with certificates from unknown CAs.
           Enabling --insecure-registry is useful when running a local registry.
             However, because its use creates security vulnerabilities it should ONLY be
             enabled for testing purposes.  For increased security, users should add their
             CA to their system's list of trusted CAs instead of using
             --insecure-registry.
    

    所以可以在docker.serivce 文件中,添加启动参数 : --insecure-registry=192.168.0.110:5000 , 然后restart docker.service 来解决上面的问题:

    #修改之后,有如下的参数:
    [root@localhost docker]# grep insecure-registry /usr/lib/systemd/system/docker.service
                      --insecure-registry=192.168.0.110:5000
    [root@localhost docker]# systemctl daemon-reload
    [root@localhost docker]# systemctl restart docker.service
    [root@localhost docker]#  docker pull 192.168.0.110:5000/panda/mysql:v1
    Trying to pull repository 192.168.0.110:5000/panda/mysql ...
    v1: Pulling from 192.168.0.110:5000/panda/mysql
    Digest: sha256:258255419e9b96b50bc0114dbe7f9a313cfa6552967b6472f174392fc4cf66e4
    Status: Image is up to date for 192.168.0.110:5000/panda/mysql:v1
    [root@localhost docker]#
    

    B. 对registry配置https 访问支持:

    1. 首先生成registry要使用的证书;这里使用之前所生成的证书:数字证书系列-CA以及用CA 签发用户证书;这里要注意的是:my.crt 绑定的域名为www.my.com ,所以需要在/etc/hosts中指明这种关系,同时在以下的测试中都使用域名www.my.com注意不要把 域名 www.my.com 和127.0.0.1对应起来);
      在网上有很多教程,是直接使用的自签名证书以及相应的密钥:在这里就是CA_Cert.pem以及CA_Key.,本笔记中使用的为:由CA-Cert.pem签名的my.crt证书
    [root@localhost cert_test]# ls -l
    total 24
    -rw-------. 1 root root 1359 Aug 18 21:31 CA_Cert.pem      #自签名的根证书,docker客户端需要信任该证书
    -rw-------. 1 root root 1675 Aug 18 21:20 CA_Key.key   
    -rw-r--r--. 1 root root 1021 Aug 18 17:23 my_cert.csr
    -rw-------. 1 root root 4509 Sep 17 21:49 my.crt         #此证书为registry使用的证书;
    -rw-r--r--. 1 root root 1679 Aug 18 17:18 myprivate.key  #my.crt证书所对应的私钥
    [root@localhost cert_test]#
    
    1. 启动registry容器,通过环境变量来告诉registry证书的路径,对应的环境变量为:
      REGISTRY_HTTP_TLS_CERTIFICATE , 用于指定https证书的位置;
      REGISTRY_HTTP_TLS_KEY, 用于指定https证书对应的私钥key的位置;
    #首先把/root/cert_test/ mapping 到registry 容器的/etc/cert.d目录,然后,设置变量如下:
    #REGISTRY_HTTP_TLS_CERTIFICATE=/etc/cert.d/my.crt
    #REGISTRY_HTTP_TLS_KEY=/etc/cert.d/myprivate.key
    [root@localhost ~]# docker run -d -v /var/my_registry/:/var/lib/registry -v /root/cert_test/:/etc/cert.d -e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/cert.d/my.crt -e REGISTRY_HTTP_TLS_KEY=/etc/cert.d/myprivate.key  -p 5000:5000  my_registry
    4df7d9af67de55149670f6be54e6683d38ec13d8a428ed778442e812500f2d63
    [root@localhost ~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    4df7d9af67de        my_registry         "/my_entry.sh /etc..."   4 seconds ago       Up 3 seconds        0.0.0.0:5000->5000/tcp   jovial_newton
    [root@localhost ~]#
    
    1. registry容器启动后,首先验证https访问是否OK,这里用curl 来测试:
    #没有添加CA到CA Trust列表里面,报如下错误:
    [root@localhost cert_test]# curl -I https://www.my.com:5000/
    curl: (60) Peer's Certificate issuer is not recognized.
    More details here: http://curl.haxx.se/docs/sslcerts.html
    
    curl performs SSL certificate verification by default, using a "bundle"
     of Certificate Authority (CA) public keys (CA certs). If the default
     bundle file isn't adequate, you can specify an alternate file
     using the --cacert option.
    If this HTTPS server uses a certificate signed by a CA represented in
     the bundle, the certificate verification probably failed due to a
     problem with the certificate (it might be expired, or the name might
     not match the domain name in the URL).
    If you'd like to turn off curl's verification of the certificate, use
     the -k (or --insecure) option.
    [root@localhost cert_test]#
    #尝试添加CA到CA TRUST列表,然后再次用curl验证;
    [root@localhost cert_test]# cp CA_Cert.pem /etc/pki/ca-trust/source/anchors/
    [root@localhost cert_test]# update-ca-trust
    [root@localhost cert_test]# curl -I https://www.my.com:5000/
    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Date: Wed, 02 Oct 2019 15:23:49 GMT
    [root@localhost cert_test]#
    #用REST API尝试获取registry中的images. 
    [root@localhost ~]# curl -XGET https://www.my.com:5000/v2/_catalog
    {"repositories":["panda/my_baseimage","panda/my_registry"]}
    
    1. 除了curl测试https连接是否ok, 我们使用的客户端毕竟是docker, 所以接着用docker pull 命令测试,看docker 命令能否成功使用https进行通信:
    [root@localhost ~]# vim /usr/lib/systemd/system/docker.service   #编辑docker.service文件,取消 --insecure-registry=192.168.0.110:5000的配置
    [root@localhost ~]# systemctl daemon-reload
    [root@localhost ~]# systemctl restart docker.service  #重启docker 服务;
    #启动registry 容器,并指定ssl的相关证书
    [root@localhost ~]# docker run -d -v /var/my_registry/:/var/lib/registry -v /root/cert_test/:/etc/cert.d -e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/cert.d/my.crt -e REGISTRY_HTTP_TLS_KEY=/etc/cert.d/myprivate.key  -p 5000:5000  my_registry
    ce31b92655e31d784e338f05067d0c760827903d110353218ba87ae5423cdf49
    #以下的docker pull 是成功的;
    [root@localhost cert_test]#  docker pull -a www.my.com:5000/panda/my_registry
    Trying to pull repository www.my.com:5000/panda/my_registry ...
    v1: Pulling from www.my.com:5000/panda/my_registry
    Digest: sha256:0614f2636b7dc16c8f95be8fff1af4252719955440317fb170abd29863a6ad37
    Status: Downloaded newer image for www.my.com:5000/panda/my_registry
    [root@localhost cert_test]#
    
    
    #停掉支持ssl的registry, 用不支持ssl的registry,重新pull 下进行测试:
    [root@localhost cert_test]# docker run -d -v /var/my_registry/:/var/lib/registry  -p 5000:5000 my_registry
    255446ba982e8661420bd34af79a7c4a5c9d1be52211c66ef6c62f4e7b439059
    #用curl测试,5000端口不支持ssl. 但是支持常规的http
    [root@localhost cert_test]# curl -I https://www.my.com:5000/
    curl: (35) SSL received a record that exceeded the maximum permissible length.
    [root@localhost cert_test]# curl -I http://www.my.com:5000/
    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Date: Wed, 02 Oct 2019 15:33:29 GMT
    #docker pull 出现文章开头的报错;
    [root@localhost cert_test]# docker pull -a www.my.com:5000/panda/my_registry
    Trying to pull repository www.my.com:5000/panda/my_registry ...
    Get https://www.my.com:5000/v1/_ping: http: server gave HTTP response to HTTPS client
    [root@localhost cert_test]#
    

    写了这么多,其实要开启ssl连接支持,只需要如下的条件:
    A. 对于registry,运行容器时需要以下两个参数的值:
    REGISTRY_HTTP_TLS_CERTIFICATE , 用于指定https证书的位置;
    REGISTRY_HTTP_TLS_KEY, 用于指定https证书对应的私钥key的位置;
    B. 而对于docker客户端:
    1.需把自签名的CA证书加入信任列表,不同os 操作方法不同,eg: centos是用update-ca-trust 。
    2.访问registry的时候,指定的地址必须和服务器证书中指定的地址一致,否则证书报错;

    1. 根据官方文档的说明,如果registry使用的证书不是CA根证书签发的,那么需要如下步骤来制作registry的证书: cat domain.crt intermediate-certificates.pem > certs/domain.crt (其中domain.crt 就是签发机构根据你的csr给你签发的证书,一般为crt后缀,而intermediate-certificates.pem 是签发机构自己的证书,一般是pem后缀, 生成的certs/domain.crt为registry需要使用的证书)

    本文原创,转载请注明出处
    参考:https://docs.docker.com/registry/deploying/#run-an-externally-accessible-registry

    相关文章

      网友评论

        本文标题:私有docker registry的ssl访问实现

        本文链接:https://www.haomeiwen.com/subject/upbhpctx.html