Docker Login 登录凭证安全存储

一、凭证存储场景描述

  Docker 利用 docker login 命令来校验用户镜像仓库的登录凭证,实际并不是真正意义上的登录。仅仅是一种登录凭证的试探校验。如果用户名密码都正确的情况下,Docker 则会已仓库登录的地址为 key 值,用户名、密码以 base64 的编码格式保存在 Docker 配置文件中。在 Linux 中的路径是 $HOME/.docker/config.json

  1. 在从未登录 Docker 仓库时,该配置文件不存在

  2. 首次登录 Docker 仓库后,登录信息和配置文件存储信息如下

    [root@node103 /]# docker login 192.169.5.207:8004
    Username: admin
    Password: 
    WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    
    Login Succeeded
    [root@node103 /]# cat /root/.docker/config.json 
    {
    	"auths": {
    		"192.169.5.207:8004": {
    			"auth": "Y1W2R3t4a5W64768T9W99u0d0G85lgdfHdNdAsMjAyMA=="
    		}
    	},
    	"HttpHeaders": {
    		"User-Agent": "Docker-Client/19.03.12 (linux)"
    	}
    }[root@node103 /]# 
    
  3. 通过命令行可以将 base64 加密后的用户名密码解码

    [root@node103 /]# echo "Y1W2R3t4a5W64768T9W99u0d0G85lgdfHdNdAsMjAyMA==" | base64 --decode
    username:password
    [root@node103 /]# 
    
  4. config.json 数据结构可以了解到,Docker 针对每一个镜像仓库,只会保存最近一次有效的用户名和密码,之后执行 docker login $domain 会直接使用 config.json 中对应域名的用户名和密码登录,当处理完毕以后,可以执行 docker logout $domain 将指定仓库的用户登录凭证从 config.json 中删除。

    [root@node103 /]# docker logout 192.169.5.207:8004
    Removing login credentials for 192.169.5.207:8004
    [root@node103 /]# cat /root/.docker/config.json 
    {
    	"auths": {},
    	"HttpHeaders": {
    		"User-Agent": "Docker-Client/19.03.12 (linux)"
    	}
    }
    [root@node103 /]# 
    
  5. 通过以上的试验可以发现,将用户登录仓库的凭据信息默认保存在 Dockerconfig.json 文件中,是及其不安全并且容易泄露的。除非每个用户每次在与镜像仓库交付完成以后,手动执行 docker logout 删除。Dokcer 也考虑到了这一点,针对不同的平台,其提供了不同的辅助工具将仓库的登录凭证保存到其它的安全系数高的存储产品中。所以我们需要采用别的保存密码的产品来保存 docker login 的密码信息。

二、存储凭证产品选型

点击此处 查看 Docker 提供的产品选型。

本示例以 pass 为例,在 CentOS 操作系统上将 DockerCredetial store 切换到 pass 存储,不再写入 config.json 文件中。

三、切换存储凭证产品
  1. 安装 pass 所需的依赖组件

    yum install -y gpg rng-tools
    
  2. 安装 pass 存储程序

    • 由于 pass 不支持 yum 直接下载安装,我们点击此处寻找合适的源码包方式进行安装
    # 进入源码包下载自定义规划目录
    cd /usr/local/src
    
    # 下载指定版本的源码包
    wget https://git.zx2c4.com/password-store/snapshot/password-store-1.7.3.tar.xz
    
    # 将源码包解压缩到自定义程序安装目录
    tar Jxf password-store-1.7.3.tar.xz -C /usr/local/
    
    # 进入源码解压后的目录
    cd /usr/local/password-store-1.7.3
    
    # 编译安装
    make install
    
    # 验证安装结果
    [root@node103 /]# pass version
    ============================================
    = pass: the standard unix password manager =
    =                                          =
    =                  v1.7.3                  =
    =                                          =
    =             Jason A. Donenfeld           =
    =               Jason@zx2c4.com            =
    =                                          =
    =      http://www.passwordstore.org/       =
    ============================================
    [root@node103 /]# 
    
  3. 使用 GPG 生成 KEY

    [root@node103 ~]# gpg --gen-key
    gpg (GnuPG) 2.0.22; Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Please select what kind of key you want:
       (1) RSA and RSA (default)
       (2) DSA and Elgamal
       (3) DSA (sign only)
       (4) RSA (sign only)
    Your selection? 1
    RSA keys may be between 1024 and 4096 bits long.
    What keysize do you want? (2048) 4096
    Requested keysize is 4096 bits
    Please specify how long the key should be valid.
             0 = key does not expire
          <n>  = key expires in n days
          <n>w = key expires in n weeks
          <n>m = key expires in n months
          <n>y = key expires in n years
    Key is valid for? (0) 0
    Key does not expire at all
    Is this correct? (y/N) y
    
    GnuPG needs to construct a user ID to identify your key.
    
    Real name: Rambo
    Email address: rambo1203@sina.com
    Comment: blog.rambo123.com
    You selected this USER-ID:
        "Rambo (blog.rambo123.com) <rambo1203@sina.com>"
    
    Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
    You need a Passphrase to protect your secret key.
    
    -------------------------------------------------------
    | Enter passphrase                                    |
    |                                                     |
    |                                                     |
    | Passphrase ******__________________________________ |
    |                                                     |
    |       <OK>                             <Cancel>     |
    -------------------------------------------------------
    
    ----------------------------------------------------------------------
    | Warning: You have entered an insecure passphrase.                  |
    | A passphrase should be at least 8 characters long.                 |
    |                                                                    |
    | <Take this one anyway>                      <Enter new passphrase> |
    ----------------------------------------------------------------------
    
    -------------------------------------------------------
    | Please re-enter this passphrase                     |
    |                                                     |
    | Passphrase ******__________________________________ |
    |                                                     |
    |       <OK>                             <Cancel>     |
    -------------------------------------------------------
    
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    gpg: /root/.gnupg/trustdb.gpg: trustdb created
    gpg: key 93B4B164 marked as ultimately trusted
    public and secret key created and signed.
    
    gpg: checking the trustdb
    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    pub   4096R/93B4B164 2020-08-29
          Key fingerprint = 769F 06F1 EA11 7BBB 1725  9BCE 20A6 9A00 93B4 B164
    uid                  Rambo (blog.rambo123.com) <rambo1203@sina.com>
    sub   4096R/4981C1FF 2020-08-29
    
    [root@node103 ~]# 
    
  4. 查看 GPG 生成的 KEY

    [root@node103 ~]# gpg --list-keys
    /root/.gnupg/pubring.gpg
    ------------------------
    pub   4096R/93B4B164 2020-08-29
    uid                  Rambo (blog.rambo123.com) <rambo1203@sina.com>
    sub   4096R/4981C1FF 2020-08-29
    
    [root@node103 ~]# 
    
  5. 通过上一步骤得到的 pub 4096R/ 后面的 id 来初始化 pass

    [root@node103 ~]# pass init
    Usage: pass init [--path=subfolder,-p subfolder] gpg-id...
    [root@node103 ~]# pass init "93B4B164"
    mkdir: created directory ‘/root/.password-store/’
    Password store initialized for 93B4B164
    [root@node103 ~]# 
    
  6. 验证 pass 的密码本

    # 为 key 设置密码并保存在 pass 密码本中
    [root@node103 ~]# pass insert admin
    # 设置 key 为 admin 的密码
    Enter password for admin: 
    Retype password for admin: 
    # 显示 key 为 admin 的密码
    [root@node103 ~]# pass show admin
    
    -------------------------------------------------------
    | Please re-enter this passphrase                     |
    |                                                     |
    | Passphrase ******__________________________________ |
    |                                                     |
    |       <OK>                             <Cancel>     |
    -------------------------------------------------------
    
    # 保存 admin 的密码为 123456    
    123456
    [root@node103 ~]# 
    
    # 更多操作请参考 pass help
    [root@node103 /]# pass help
    ============================================
    = pass: the standard unix password manager =
    =                                          =
    =                  v1.7.3                  =
    =                                          =
    =             Jason A. Donenfeld           =
    =               Jason@zx2c4.com            =
    =                                          =
    =      http://www.passwordstore.org/       =
    ============================================
    
    Usage:
        pass init [--path=subfolder,-p subfolder] gpg-id...
            Initialize new password storage and use gpg-id for encryption.
            Selectively reencrypt existing passwords using new gpg-id.
        pass [ls] [subfolder]
            List passwords.
        pass find pass-names...
        	List passwords that match pass-names.
        pass [show] [--clip[=line-number],-c[line-number]] pass-name
            Show existing password and optionally put it on the clipboard.
            If put on the clipboard, it will be cleared in 45 seconds.
        pass grep [GREPOPTIONS] search-string
            Search for password files containing search-string when decrypted.
        pass insert [--echo,-e | --multiline,-m] [--force,-f] pass-name
            Insert new password. Optionally, echo the password back to the console
            during entry. Or, optionally, the entry may be multiline. Prompt before
            overwriting existing password unless forced.
        pass edit pass-name
            Insert a new password or edit an existing password using vi.
        pass generate [--no-symbols,-n] [--clip,-c] [--in-place,-i | --force,-f] pass-name [pass-length]
            Generate a new password of pass-length (or 25 if unspecified) with optionally no symbols.
            Optionally put it on the clipboard and clear board after 45 seconds.
            Prompt before overwriting existing password unless forced.
            Optionally replace only the first line of an existing file with a new password.
        pass rm [--recursive,-r] [--force,-f] pass-name
            Remove existing password or directory, optionally forcefully.
        pass mv [--force,-f] old-path new-path
            Renames or moves old-path to new-path, optionally forcefully, selectively reencrypting.
        pass cp [--force,-f] old-path new-path
            Copies old-path to new-path, optionally forcefully, selectively reencrypting.
        pass git git-command-args...
            If the password store is a git repository, execute a git command
            specified by git-command-args.
        pass help
            Show this text.
        pass version
            Show version information.
    
    More information may be found in the pass(1) man page.
    [root@node103 /]# 
    
  7. 安装 Docker Credential 辅助工具,具体最新版本请点击此处 获取

    # 进入自定义资源下载目录
    cd /usr/local/src
    
    # 下载 Docker Credetial 
    wget https://github.com/docker/docker-credential-helpers/archive/refs/tags/v0.6.3.tar.gz
    
    # 解压 Docker Credential 
    tar zxvf docker-credential-pass-v0.6.3-amd64.tar.gz
    
    # 为 Docker Credential 赋予可执行权限
    chmod +x docker-credential-pass
    
    # 将 Docker Credential 移动到环境变量中
    mv docker-credential-pass /usr/local/bin/
    
    # 查看 Docker Credentail 的版本
    [root@node103 /]# docker-credential-pass version
    0.6.3
    [root@node103 /]# 
    
  8. 修改 Docker 配置

    # 清空 .docker/config.json 文件内容,然后将下面配置写入 config.json 文件中,注意 credsStore 是各辅助安装包名字的尾缀  
    [root@node103 /]# cat /root/.docker/config.json 
    {
        "credsStore": "pass"
    }
    [root@node103 /]# 
    
  9. 初始化 docker password store

    [root@node103 /]# pass insert docker-credential-helpers/docker-pass-initialized-check
    # 密码本保存文件目录
    mkdir: created directory ‘/root/.password-store/docker-credential-helpers’
    # 密码本访问密码
    Enter password for docker-credential-helpers/docker-pass-initialized-check: 
    Retype password for docker-credential-helpers/docker-pass-initialized-check: 
    # 密码本中保存的密码信息,验证初始化结果
    [root@node103 /]# docker-credential-pass list
    {}
    [root@node103 /]# 
    
    # 也可以通过 show 来查看刚刚创建密码本的密码(执行的过程中无需输入密码)
    [root@node103 /]# pass show docker-credential-helpers/docker-pass-initialized-check
    123456
    [root@node103 /]# 
    
  10. 再次执行 docker login 登录镜像仓库,同时查看 $HOME/.docker/config.json 文件内容

    # 登录之前查看 config.json 文件中的内容
    [root@node103 /]# cat /root/.docker/config.json 
    {
        "credsStore": "pass"
    }
    
    # 采用用户名密码登录镜像仓库
    [root@node103 /]# docker login 192.169.5.207:8004
    Username: admin
    Password: 
    
    # 登录成功也没有警告提示了
    Login Succeeded
    
    # 再次查看 config.json 文件内容,发现用户名密码也没有保存在该文件中,而是保存到了加密文件中去了
    [root@node103 /]# cat /root/.docker/config.json 
    {
    	"auths": {
    		"192.169.5.207:8004": {}
    	},
    	"HttpHeaders": {
    		"User-Agent": "Docker-Client/19.03.12 (linux)"
    	},
    	"credsStore": "pass"
    }
    
    # 重启 Docker  以免下次登录出现以下情况
    [root@node103 /]# docker login 192.169.5.207:8004
    Authenticating with existing credentials...
    Login did not succeed, error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
    Username (admin): ^C
    [root@node103 /]# systemctl restart docker
    [root@node103 /]# docker login 192.169.5.207:8004
    Authenticating with existing credentials...
    Login Succeeded
    [root@node103 /]# 
    
  11. 验证以上登录镜像仓库的用户名密码是否保存在 pass

    • 由于需要使用 tree 命令,这里需要安装

      yum install tree -y
      
    • 查看密码本中的密码原文

      [root@node103 /]# docker-credential-pass list
      {"192.169.5.207:8004":"admin"}
      [root@node103 /]# pass
      Password Store
      ├── admin
      └── docker-credential-helpers
          ├── docker-pass-initialized-check
          └── MTkyLjE2OS41LjIwNzo4MDA0
              └── admin
      [root@node103 /]# pass show docker-credential-helpers/MTkyLjE2OS41LjIwNzo4MDA0/admin
      这里将显示设置的密码明文
      [root@node103 /]# 
      
  12. 保存密码文件路径

    [root@node103 MTkyLjE2OS41LjIwNzo4MDA0]# cd /root/.password-store/docker-credential-helpers/MTkyLjE2OS41LjIwNzo4MDA0
    [root@node103 MTkyLjE2OS41LjIwNzo4MDA0]# ll
    total 4
    -rw------- 1 root root 591 Aug 29 14:36 admin.gpg
    [root@node103 MTkyLjE2OS41LjIwNzo4MDA0]# 
    
四、凭据存储使用总结
  • Docker 默认采用 config.json 文件保存 docker login 的用户名密码

  • 并且这些用户名密码都是通过 base64 加密存储的很容易被泄露

  • 我们应该切换用户名密码保存源,如 pass

  • 在需要保存 Docker 用户名密码的操作客户端都安装 pass 并根据以上配置即可

  • 配置完成通过 docker login 进行一次登录验证

  • 重启 Docker 在进行一次登录验证(此次是不需要输入登录密码的)

  • dokcer login 的操作脚本都不需要进行相应的变化

  • 25
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值