docker

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > 云和虚拟化 > docker > Docker Login 登录凭证安全存储

Docker Login 登录凭证安全存储方式

作者:Ramboooooooo

本文主要探讨Docker镜像仓库登录凭证的存储问题,Docker利用docker login命令校验用户镜像仓库的登录凭证,正确的用户名密码会以base64编码格式保存在Docker配置文件中,这种方式极易泄露且不安全

一、凭证存储场景描述

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 /]# 

通过命令行可以将 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 /]# 

通过以上的试验可以发现,将用户登录仓库的凭据信息默认保存在 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

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]# 

四、凭据存储使用总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文