Docker 也类似C/S架构,分为了前端和后端,前端可以是Docker Desktop、Portainer等界面软件,提供操作。后端则是Docker Engine,提供docker 的守护进程dockerd
,用于dockerd与前端交互的api,以及docker的命令行客户端。
Dockerd 默认直接开启端口,没有使用加密手段。这对于外部无法访问的内网机器或开发环境来说比较方便,但是如果别人连接上了这个端口,就可以进行任意操作。对于生产环境,就可能会造成严重的安全事故。
生产环境中,需要对docker远程连接进行加密处理。使用加密处理则必须配置 SSL 认证。
注意:
图床还没有搭好,目前只能内网访问,所以图片不能显示,不过不影响使用。
配置 TLS 和 CA 认证
在生产环境中,应从 CA 获取证书。在测试或开发环境中,您可以生成自己的 CA。若要生成 CA 证书,请运行以下命令。
开启加密通信,这里使用 openssl 进行操作
生成 CA 证书
- 生成CA密钥
openssl genrsa -aes256 -out ca-key.pem 4096
这里会提示输入密码,这个密码需要记一下,之后还会用到。
- 生成 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 证书了。
生成服务器证书
- 生成服务端密钥
openssl genrsa -out server-key.pem 4096
- 准备 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
- 生成服务端证书签名的请求文件
# 这里的 `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,则说明配置有误。
- 生成服务端证书
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
生成客户端证书
生成服务器证书步骤和生成服务器步骤基本一样。
- 生成客户端密钥
openssl genrsa -out client.key 4096
- 生成客户端证书签名的请求文件
openssl req -subj '/CN=client' -new -key client.key -out client.csr
- 生成客户端证书
# 这里 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 连接参数:
- portainer 主页选择 Environments 进入 docker 连接管理界面
- 点击
Add environment
添加docker远程连接 - 选择
Docker Standalone
,点击Start Wizard
- 这里选择 API,填入自己想要填写的名字、服务器的域名/ip:port;打开 TLS 选项,选择
ca.crt
、client.crt
、client.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
参考资料
以下是配置过程中参考较多的几篇文章:
-
《Docker开启TLS和CA认证》 https://zhuanlan.zhihu.com/p/403990962 这里主要是根据这篇文章编写的生成脚本
-
Configure HTTPS Access to Harbor: https://goharbor.io/docs/2.6.0/install-config/configure-https/ 这是 harbor 和 Docker 连接的指南,具有一定的参考意义
-
OpenSSL创建生成CA证书、服务器、客户端证书及密钥 https://blog.csdn.net/qq153471503/article/details/109524764
-
openssl - https SAN自签名证书 https://www.zhangwenbing.com/blog/linux/JQIo7dGc1
作者: 三十的南瓜饭
文章链接: https://pumpkinrice.gitlab.io/posts/4ab1a68d4f1bd1e37cab70e1c9661aeh/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 三十的南瓜饭 。