今天排查了一个HTTPS证书的问题, 虽然很快的就解决了, 但里面涉及到的东西学是蛮多啊的,学习一下
问题是这样, 一个运行在容器中的服务给一个https地址发送POST请求时提示x509: certificate signed by unknown authority
大家都知道, 一般https都需要通过ca认证,问题很显然, 证书认证不过, 但是为何会出这个问题呢?
要回答这个问题, 自然就引出另一个问题:当我们访问https的问题, 一般不会带上跟证书相关的参数,那又是如何验证网站身份的呢
这里使用curl来模拟,效果一样
curl
在ubuntu上16.04, 内核4.4.0-130-generic
上运行curl
1 | curl https://baidu.com -v |
关注重点信息:
1 | * found 148 certificates in /etc/ssl/certs/ca-certificates.crt |
/etc/ssl
从上面可以看出, 在/etc/ssl
中发现大量的certificates
, 可以来看看/etc/ssl
,
这个目录在使用命令apt install ca-certificates
后生成
/etc/ssl
该目录下只有certs openssl.cnf private
这几个文件,有用的为certs目录,这个目录下有大量跟证书相关的pem文件, 其中就包含ca-certificates.crt
文件.
pem跟crt都是证书相关的文件,不同的格式罢了,这个不是重点
重点在于,在使用curl的时候,如果不带证书相关的参数,则会引用默认的证书路径(依操作系统不同而不同)
这个默认值怎么来确定呢? 可以确认是curl底层的代码根据环境因素定义的默认值,可以通过strace
方式来查看
strace curl https://www.baidu.com |& grep open
从上面可以看到, curl如果不指定ca参数的话,则会到/etc/ssl
目录下查找
同时, curl也是支持传递参数来实现https的访问
我们可以通过 man curl
来查看几个重要的跟参数相关的参数,写的很详细,这里就不翻译了
1 | --cacert <CA certificate> |
1 | --capath <CA certificate directory> |
ca-certificates
ca-certificates则是一个包, 用于维护根证书库, 所有的 CA 根证书实际上是由 Mozilla 维护的
可以通过dpkg -L ca-certificates
来查看证书相关信息
也可以通过apt-cache show ca-certificates
查看相关信息,当然太多,看不出什么来,就是一堆证书
那么可能有人会问, 一般情况下, 系统安装好之后基本就不会再做操作了,那如何更新根证书呢?
有一个工具update-ca-certificates
可以手动更新根证书信息, 可以使用man
update-ca-certificates`, 说的非常清楚
因此可以手工执行以下命令来更新根证书列表
1 | update-ca-certificates |
Resolve
通过curl可以知道, 访问https的时候默认会到/etc/ssl目录下查找根证书,通过根证书验证对端网站的身份,因为对端的证书一般也是由这些根证书签名我, 因此可以难通过
那么出现开头的问题的原因在于, 使用的镜像本身没有包含/etc/ssl
目录,同时在Dockerfile中也没有使用apt install ca-certificates
来安装, 因此在所有请求https时都会出现问题.
这里提一下, 在安装curl
的时候,默认会安装ca-certificates
,实际上这个包由 OpenSSL 安装的
Curl 是通过 OpenSSL 实现客户端 HTTPS 协议的,就是说在 Curl/OpenSSL 平台下,Curl 使用的根证书库都是由 ca-certificates 包处理
curl也是一种上层应用, 对于其它的比如golang程序出现这个问题,原理都是一样的.
修改镜像,问题解决