Docker配置远程连接(TLS&CA认证) @ 三十的南瓜饭 | 2023-07-07T02:07:49+08:00 | 5 分钟阅读 | 更新于 2023-07-08T13:43:40+08:00

Docker 也类似C/S架构,分为了前端和后端,前端可以是Docker Desktop、Portainer等界面软件,提供操作。后端则是Docker Engine,提供docker 的守护进程dockerd,用于dockerd与前端交互的api,以及docker的命令行客户端。

Dockerd 默认直接开启端口,没有使用加密手段。这对于外部无法访问的内网机器或开发环境来说比较方便,但是如果别人连接上了这个端口,就可以进行任意操作。对于生产环境,就可能会造成严重的安全事故。

生产环境中,需要对docker远程连接进行加密处理。使用加密处理则必须配置 SSL 认证。

注意:

图床还没有搭好,目前只能内网访问,所以图片不能显示,不过不影响使用。

配置 TLS 和 CA 认证

在生产环境中,应从 CA 获取证书。在测试或开发环境中,您可以生成自己的 CA。若要生成 CA 证书,请运行以下命令。

开启加密通信,这里使用 openssl 进行操作

生成 CA 证书

  1. 生成CA密钥
openssl genrsa -aes256 -out ca-key.pem 4096

这里会提示输入密码,这个密码需要记一下,之后还会用到。

  1. 生成 CA 证书
openssl req -new -x509 -sha512 -days 3650 \
	-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com/emailAddress=youremail" \
	-key ca-key.pem \
	-out ca-cert.pem 

首先是 openssl 后面的 req(关于 PKCS:PKCS#1、PKCS#5、PKCS#7、PKCS#8到底是什么?):

openssl-req - PKCS#10 certificate request and certificate generating command openssl 的 req 指令用 PKCS#10 标准进行证书申请和生成。 —— man openssl-req

sub:

C—–国家(Country Name) ST—-省份(State or Province Name) L—-城市(Locality Name) O—-公司(Organization Name) OU—-部门(Organizational Unit Name) CN—-产品名(Common Name) emailAddress—-邮箱(Email Address) ——OpenSSL创建生成CA证书、服务器、客户端证书及密钥

这条指令生成的 ca-cert.pem 就是生成的 CA 证书了。

生成服务器证书

  1. 生成服务端密钥
openssl genrsa -out server-key.pem 4096
  1. 准备 x509 v3 扩展文件 这里参考Harbor提供的配置方法Configure HTTPS Access to Harbor,根据openssl - https SAN自签名证书进行了修改(其实没有harbor里面的成分了):
cat > v3.ext <<-EOF
[req]
req_extensions = v3_ca
distinguished_name = req_distinguished_name
authorityKeyIdentifier=keyid,issuer

[req_distinguished_name]

[alt_names]
IP.1=ip1
IP.2=ip2
DNS.1=domain1
DNS.2=domain2

[v3_ca] #  v3_ca 放在后面避免 printf 输出之后 openssl 处理出错
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names
EOF
  1. 生成服务端证书签名的请求文件
# 这里的 `v3_ca` 要和 ext 文件里面的字段名对应
openssl req -new -sha512 \
	-subj "/CN=$HOSTNAME" \
	-reqexts v3_ca \ 
	-config v3.ext \
	-key server.key \
	-out server.csr

当请求文件生成完成之后,通过 openssl req -text -in server.csr | less 查看,有以下信息:

Certificate Request: Data: Version: 1 (0x0) …… Attributes: Requested Extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature, Key Encipherment X509v3 Subject Alternative Name: IP Address:[yourIP] X509v3 Extended Key Usage: TLS Web Server Authentication

如果不是x509v3,则说明配置有误。

  1. 生成服务端证书
openssl x509 -req -days 3650 \
	-sha512 \
	-CA ca.crt -CAkey ca.key -CAcreateserial \
	-extensions v3_ca \
	-extfile <(cat v3.ext \
		<(printf "extendedKeyUsage=serverAuth")) \
	-passin "pass:$PASSWORD" \
	-in server.csr\
	-out server.crt

当服务端证书生成完成之后,通过 openssl x509 -text -in server.crt | less 查看,有以下信息:

Certificate: Data: Version: 3 (0x2) …… X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature, Key Encipherment

生成客户端证书

生成服务器证书步骤和生成服务器步骤基本一样。

  1. 生成客户端密钥
openssl genrsa -out client.key 4096
  1. 生成客户端证书签名的请求文件
openssl req -subj '/CN=client' -new -key client.key -out client.csr
  1. 生成客户端证书
# 这里 extendedKeyUsage=serverAuth 改成了 client
openssl x509 -req -days 3650 \
	-sha512 \
	-extensions v3_ca \
	-extfile <(cat v3.ext \
		<(printf "extendedKeyUsage=clientAuth")) \
	-CA ca.crt -CAkey ca.key -CAcreateserial \
	-passin "pass:$PASSWORD" \
	-in client.csr \
	-out client.crt

同样在生成之后可以使用 openssl [req/x509] -test -in file 查看x509字段。

证书测试

单向认证测试

  • 服务器命令
openssl s_server -CAfile ./ca.crt -cert server.crt -key server.key -accept [port]
  • 客户端命令
openssl s_client -CAfile ca.crt -cert client.crt -key client.key -connect [ip] -port [port]

双向认证测试

  • 服务器命令
openssl s_server -CAfile ./ca.crt -cert server.crt -key server.key -accept [port]
  • 客户端命令
openssl s_client -CAfile ./ca.crt -cert server.crt -key server.keym -cert client.crt -key client.key -connect [ip] -port [port]

双向认证测试和单向之间的区别在于,双向认证需要服务器对客户端提交的 key 进行验证,同时客户端也要验证服务器回报的key(大概吧,张口就来 😥)。

SAN 证书

关于SAN证书大家可以先自行了解,这里就不做介绍了。

Portainer 环境配置&错误记录

Portainer 连接配置

这里主要就是添加 portainer 连接参数:

  1. portainer 主页选择 Environments 进入 docker 连接管理界面
  2. 点击 Add environment 添加docker远程连接
  3. 选择 Docker Standalone,点击 Start Wizard
  4. 这里选择 API,填入自己想要填写的名字、服务器的域名/ip:port;打开 TLS 选项,选择 ca.crtclient.crtclient.key三个文件,然后就能连接了。

tls: private key does not match public key

tls: private key does not match public key

  • 如果这里对TLS 证书进行了测试,且测试通过,则可能是文件填写错误。
  • 如果没有测试,可能是生成过程存在错误。

X509: certificate relies on legacy Common Name field…

这个可能是最常见的问题,原因是生成的证书不是 SAN 证书。 这个在 csr 和 crt 文件生成之后查看 x509v3 字段,如果字段不存在,则会产生这个错误。

解决方法主要是设置 v3.ext。

CA 证书生成脚本

这个脚本根据Docker开启TLS和CA认证提供的脚本修改而来,直接使用原来的脚本在 portainer 设置时会提示 x509: cannot validate certificate because of not containing any IP SANs,然后失败。

# !/bin/bash

# 一键生成TLS和CA证书

# Create : 2021-08-25
# Update : 2021-08-25
# @Autor : wuduoqiang

# 服务器主机名
SERVER="ip/domain"
# 密码
PASSWORD="password"
# 国家
COUNTRY="CN"
# 省份
STATE="SiChuan"
# 城市
CITY="ChengDu"
# 机构名称
ORGANIZATION="organization"
# 机构单位
ORGANIZATIONAL_UNIT="ou"
# 邮箱
EMAIL="name@email.com"

cat > v3.ext <<-EOF
[req]
req_extensions = v3_ca
distinguished_name = req_distinguished_name
authorityKeyIdentifier=keyid,issuer

[req_distinguished_name]

[alt_names]
IP.1=ip1
IP.2=ip2
DNS.1=domain1
DNS.2=domain2

[v3_ca] # 把 v3_ca 放在后面,避免 printf 输出之后 openssl 处理出错
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names
EOF

# 生成CA密钥
openssl genrsa -aes256 -passout pass:$PASSWORD -out ca.key 4096

# 生成CA证书
openssl req -new -x509 -sha512 -days 3650 \
	-passin "pass:$PASSWORD" \
	-subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$SERVER/emailAddress=$EMAIL" \
	-key ca.key \
	-out ca.crt 

# 生成服务端密钥
openssl genrsa -out server.key 4096

# 生成服务端证书签名的请求文件
openssl req -new -sha512 \
	-subj "/CN=$HOSTNAME" \
	-reqexts v3_ca \ 
	-config v3.ext \
	-key server.key \
	-out server.csr

# 生成服务端证书
openssl x509 -req -days 3650 \
	-sha512 \
	-CA ca.crt -CAkey ca.key -CAcreateserial \
	-extensions v3_ca \
	-extfile <(cat v3.ext \
		<(printf "extendedKeyUsage=serverAuth")) \
	-passin "pass:$PASSWORD" \
	-in server.csr\
	-out server.crt

# 生成客户端密钥
openssl genrsa -out client.key 4096

# 生成客户端证书签名的请求文件
openssl req -subj '/CN=client' -new -key client.key -out client.csr

# 生成客户端证书
openssl x509 -req -days 3650 \
	-sha512 \
	-extfile <(cat v3.ext \
		<(printf "extendedKeyUsage=clientAuth")) \
	-CA ca.crt -CAkey ca.key -CAcreateserial \
	-passin "pass:$PASSWORD" \
	-in client.csr \
	-out client.crt

# 更改密钥权限
chmod 0400 ca.key server.key client.key
# 更改证书权限
chmod 0444 ca.crt server.crt client.crt
# 删除无用文件
# rm ca-cert.srl client-req.csr server-req.csr v3.ext

参考资料

以下是配置过程中参考较多的几篇文章:

  1. 《Docker开启TLS和CA认证》 https://zhuanlan.zhihu.com/p/403990962 这里主要是根据这篇文章编写的生成脚本

  2. Configure HTTPS Access to Harbor: https://goharbor.io/docs/2.6.0/install-config/configure-https/ 这是 harbor 和 Docker 连接的指南,具有一定的参考意义

  3. OpenSSL创建生成CA证书、服务器、客户端证书及密钥 https://blog.csdn.net/qq153471503/article/details/109524764

  4. openssl - https SAN自签名证书 https://www.zhangwenbing.com/blog/linux/JQIo7dGc1


作者: 三十的南瓜饭

文章链接: https://pumpkinrice.gitlab.io/posts/4ab1a68d4f1bd1e37cab70e1c9661aeh/

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 三十的南瓜饭 。

💬 评论

© 2023 南瓜饭的博客

Powered by Hugo with theme Dream.

误入迷途而知路之难返

avatar
Me

你好,我是南瓜饭,喜欢的东西很多。

一个不喜欢和人讲道理的理工宅男。

不过不是不讲道理。。。。