Docker引擎开启TLS双向认证

Docker引擎开启TLS双向认证

Administrator 39 2023-06-15

[toc]

Docker引擎开启TLS双向认证

以往博客部署中为了方便我使用了IDEA+docker插件的方式一键部署,由于只开启了远程连接并没有配置证书访问导致服务器被黑,辛酸血泪史。。。。本次服务器环境重装重新配置,还是继续使用docker插件一键部署的模式,(真的好用啊),所以试试开启TLS认证

[可以参照docker官方文档](https://docs.docker.com/engine/security/protect-access/#create-a-ca-server-and-client-keys-with-openss)

1. 创建证书目录

[root@YUN911265212 ~]# mkdir -p .docker/cert/

[root@YUN911265212 ~]#cd .docker/cert/

[root@YUN911265212 cert]#

2. 创建CA证书

2.1 创建CA私钥

命令创建ca私钥:openssl genrsa -aes256 -out ca-key.pem 4096 根据提示输入密码

[root@YUN911265212 cert]# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..........................................................................................++
...............................................................++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:
[root@YUN911265212 cert]# ll
total 4
-rw-r--r--. 1 root root 3326 Jun 15 11:17 ca-key.pem
[root@YUN911265212 cert]#

2.2 生成CA证书

命令创建CA证书:openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem 这里会用到创建CA私钥时设置的密码,根据提示输入,注意Common Name

[root@YUN911265212 cert]# openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shanghai
Locality Name (eg, city) [Default City]:Shanghai
Organization Name (eg, company) [Default Company Ltd]:Allen
Organizational Unit Name (eg, section) []:Allen
Common Name (eg, your name or your server's hostname) []:${这里填写你自己的hostName}
Email Address []:314273577@qq.com

[root@YUN911265212 cert]# ll
total 8
-rw-r--r--. 1 root root 3326 Jun 15 11:17 ca-key.pem
-rw-r--r--. 1 root root 2098 Jun 15 11:42 ca.pem

3. 使用CA证书签发服务端证书

现在创建好了 CA,就可以创建服务器密钥和证书签名请求 (CSR)。确保“Common Name”与您用来连接到 Docker 的主机名相匹配:

[root@YUN911265212 cert]# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
........++
.........++
e is 65537 (0x10001)

[root@YUN911265212 cert]# openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr

将 Docker 守护程序密钥的扩展使用属性设置为仅用于服务器身份验证:

[root@YUN911265212 cert]# echo extendedKeyUsage = serverAuth >> extfile.cnf

通过CA公钥和私钥为刚刚生成的证书签名请求 (CSR),生成签名证书:

使用如下命令

openssl x509 -req -days 365 -sha256 \
-in server.csr \
-CA ca.pem \
-CAkey ca-key.pem \
-CAcreateserial \
-out server-cert.pem \
-extfile extfile.cnf

控制台输出

[root@YUN911265212 cert]# openssl x509 -req -days 365 -sha256 \
> -in server.csr \
> -CA ca.pem \
> -CAkey ca-key.pem \
> -CAcreateserial \
> -out server-cert.pem \
> -extfile extfile.cnf
Signature ok
subject=/CN=BAKUMAN
Getting CA Private Key
Enter pass phrase for ca-key.pem:
[root@YUN911265212 cert]# ll
total 28
-rw-r--r--. 1 root root 3326 Jun 15 11:17 ca-key.pem
-rw-r--r--. 1 root root 2098 Jun 15 11:42 ca.pem
-rw-r--r--. 1 root root   17 Jun 15 13:44 ca.srl
-rw-r--r--. 1 root root   30 Jun 15 13:41 extfile.cnf
-rw-r--r--. 1 root root 1862 Jun 15 13:44 server-cert.pem
-rw-r--r--. 1 root root 1582 Jun 15 11:49 server.csr
-rw-r--r--. 1 root root 3243 Jun 15 11:45 server-key.pem
[root@YUN911265212 cert]#

4. docker引擎开启TLS认证并部署证书

编辑配置文件vim /lib/systemd/system/docker.service

找到ExecStart=修改如下

ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --tlsverify --tlscacert=/root/.docker/cert/ca.pem --tlscert=/root/.docker/cert/server-cert.pem --tlskey=/root/.docker/cert/server-key.pem -H unix:///var/run/docker.sock
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --tlsverify --tlscacert=/root/.docker/cert/ca.pem --tlscert=/root/.docker/cert/server-cert.pem --tlskey=/root/.docker/cert/server-key.pem -H unix:///var/run/docker.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
    

使生效

systemctl daemon-reload && systemctl restart docker.service

5. 使用CA证书签发客户端证书

生成客户端密钥和生成客户端证书签名的请求文件

[root@YUN911265212 cert]# openssl genrsa -out client-key.pem 4096
Generating RSA private key, 4096 bit long modulus
...................................................................................................................++
..........................................................................................................................................................................................................................................................++
e is 65537 (0x10001)
[root@YUN911265212 cert]# openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr
[root@YUN911265212 cert]# ll
total 36
-rw-r--r--. 1 root root 3326 Jun 15 15:39 ca-key.pem
-rw-r--r--. 1 root root 2130 Jun 15 15:40 ca.pem
-rw-r--r--. 1 root root   17 Jun 15 15:41 ca.srl
-rw-r--r--. 1 root root 1582 Jun 15 16:22 client.csr
-rw-r--r--. 1 root root 3243 Jun 15 16:22 client-key.pem
-rw-r--r--. 1 root root   30 Jun 15 15:40 extfile.cnf
-rw-r--r--. 1 root root 1887 Jun 15 15:41 server-cert.pem
-rw-r--r--. 1 root root 1590 Jun 15 15:40 server.csr
-rw-r--r--. 1 root root 3247 Jun 15 15:40 server-key.pem

将 Docker 守护程序密钥的扩展使用属性设置为仅用于服务器身份验证:

[root@YUN911265212 cert]# echo extendedKeyUsage = serverAuth >> extfile.cnf

使用CA签名客户端证书:

[root@YUN911265212 cert]# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
>   -CAcreateserial -out client-cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:

后置安全设置

生成client-cert.pemserver-cert.pem您可以安全地删除两个证书签名请求和扩展配置文件:

rm -v client.csr server.csr extfile.cnf extfile-client.cnf

为保护您的密钥免受意外损坏,请删除其写入权限。要使它们只能由您读取,请按如下方式更改文件模式:

chmod -v 0400 ca-key.pem key.pem server-key.pem

chmod -v 0444 ca.pem server-cert.pem cert.pem

测试连接

[root@YUN911265212 cert]# curl https://${hostname}:2375/info --cert ./client-cert.pem --key ./client-key.pem --cacert ./ca.pem
{"ID":"3da5fdd2-f45a-477a-b11e-b692c988dc17","Containers":2,"ContainersRunning":2,"ContainersPaused":0,"ContainersStopped":0,"Images":4,"Driver":"vfs","DriverStatus":null,"Plugins":{"Volume":["local"],"Network":["bridge","host","ipvlan","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","local","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemoryTCP":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":true,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":false,"NFd":38,"OomKillDisable":true,"NGoroutines":52,"SystemTime":"2023-06-15T16:40:30.6036259+08:00","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","CgroupVersion":"1","NEventsListener":0,"KernelVersion":"3.10.0-1160.90.1.el7.x86_64","OperatingSystem":"CentOS Linux 7 (Core)","OSVersion":"7","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":["https://j9b055o0.mirror.aliyuncs.com/"],"Secure":true,"Official":true}},"Mirrors":["https://j9b055o0.mirror.aliyuncs.com/"]},"NCPU":4,"MemTotal":16647389184,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"YUN911265212","Labels":[],"ExperimentalBuild":false,"ServerVersion":"24.0.2","Runtimes":{"io.containerd.runc.v2":{"path":"runc"},"runc":{"path":"runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"3dce8eb055cbb6872793272b4f20ed16117344f8","Expected":"3dce8eb055cbb6872793272b4f20ed16117344f8"},"RuncCommit":{"ID":"v1.1.7-0-g860f061","Expected":"v1.1.7-0-g860f061"},"InitCommit":{"ID":"de40ad0","Expected":"de40ad0"},"SecurityOptions":["name=seccomp,profile=builtin"],"Warnings":null}

image-glho.png