一、凭证存储场景描述
Docker 利用 docker login 命令来校验用户镜像仓库的登录凭证,实际并不是真正意义上的登录。仅仅是一种登录凭证的试探校验。如果用户名密码都正确的情况下,Docker 则会已仓库登录的地址为 key 值,用户名、密码以 base64 的编码格式保存在 Docker 配置文件中。在 Linux 中的路径是 $HOME/.docker/config.json
在从未登录
Docker仓库时,该配置文件不存在首次登录
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 /]#通过命令行可以将
base64加密后的用户名密码解码[root@node103 /]# echo "Y1W2R3t4a5W64768T9W99u0d0G85lgdfHdNdAsMjAyMA==" | base64 --decode username:password [root@node103 /]#从
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 /]#通过以上的试验可以发现,将用户登录仓库的凭据信息默认保存在
Docker的config.json文件中,是及其不安全并且容易泄露的。除非每个用户每次在与镜像仓库交付完成以后,手动执行docker logout删除。Dokcer也考虑到了这一点,针对不同的平台,其提供了不同的辅助工具将仓库的登录凭证保存到其它的安全系数高的存储产品中。所以我们需要采用别的保存密码的产品来保存docker login的密码信息。
二、存储凭证产品选型
点击此处 查看 Docker 提供的产品选型。
本示例以 pass 为例,在 CentOS 操作系统上将 Docker 的 Credetial store 切换到 pass 存储,不再写入 config.json 文件中。
三、切换存储凭证产品
安装
pass所需的依赖组件yum install -y gpg rng-tools安装
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 /]#- 由于
使用
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 ~]#查看
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 ~]#通过上一步骤得到的
pub4096R/后面的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 ~]#验证
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 /]#安装
Docker Credential辅助工具,具体最新版本请点击此处 获取# 进入自定义资源下载目录 cd /usr/local/src # 下载 Docker Credetial wget https://github.com/docker/docker-credential-helpers/releases/download/v0.6.3/docker-credential-pass-v0.6.3-amd64.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 /]#修改
Docker配置# 清空 .docker/config.json 文件内容,然后将下面配置写入 config.json 文件中,注意 credsStore 是各辅助安装包名字的尾缀 [root@node103 /]# cat /root/.docker/config.json { "credsStore": "pass" } [root@node103 /]#初始化
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 /]#再次执行
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 /]#验证以上登录镜像仓库的用户名密码是否保存在
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 /]#
保存密码文件路径
[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的操作脚本都不需要进行相应的变化