首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

一个因 CA 根证书过期引起的故障,真相竟然是…

服务器上的应用服务对外发送的一些 https 请求都失败了,真相竟然是……

问题

10点左右,同事反馈咨询线上的Sentry 服务器现在是否正常。之后去检查 Sentry 服务,运行正常,但是该应用服务对接的Sentry频道已经很久没有事件进来了。

感觉不太对劲,再去检查下 Sentry worker专用的容器,发现该Worker服务中中有些错误日志:

代码语言:javascript
复制
E, [2020-06-01T04:02:03.670850 #6] ERROR -- sentry: ** [Raven] Unable to record event with remote Sentry server (Raven::Error - SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (certificate has expired)):  /usr/local/bundle/gems/sentry-raven-2.7.3/lib/raven/transports/http.rb:34:in `rescue in send_event'  /usr/local/bundle/gems/sentry-raven-2.7.3/lib/raven/transports/http.rb:16:in `send_event'  /usr/local/bundle/gems/sentry-raven-2.7.3/lib/raven/client.rb:37:in `send_event'  /usr/local/bundle/gems/sentry-raven-2.7.3/lib/raven/instance.rb:81:in `send_event'  /app/src/worker.rb:26:in `perform'  /usr/local/bundle/gems/sidekiq-5.1.3/lib/sidekiq/processor.rb:187:in `execute_job'  /usr/local/bundle/gems/sidekiq-5.1.3/lib/sidekiq/processor.rb:169:in `block (2 levels) in process'  /usr/local/bundle/gems/sidekiq-5.1.3/lib/sidekiq/middleware/chain.rb:128:in `block in invoke'  /usr/local/bundle/gems/sentry-raven-2.7.3/lib/raven/integrations/sidekiq.rb:9:in `call'  /usr/local/bundle/gems/sidekiq-5.1.3/lib/sidekiq/middleware/chain.rb:130:in `block in invoke'  /usr/local/bundle/gems/sidekiq-5.1.3/lib/sidekiq/middleware/chain.rb:133:in `invoke'  E, [2020-06-01T04:02:03.671130 #6] ERROR -- sentry: ** [Raven] Failed to submit event: <no message value> 

奇怪?sentry-worker 在连sentry server 时请求域名的证书过期了?

分析

针对上面的错误信息,先去检查了相关调用的域名证书的有效期,发现都在有效期内。而且印象中都是年初刚更换的。所以排除了是域名证书问题。

然后根据错误日志,尝试在自己电脑上用下curl 命令,巧合的很,也遇到了类似的错误。

代码语言:javascript
复制
$ curl https://sentry.xxx.com  curl: (60) SSL certificate problem: certificate has expired  More details here: https://curl.haxx.se/docs/sslcerts.html  curl failed to verify the legitimacy of the server and therefore could not  establish a Secure connection to it. To learn more about this situation and  how to fix it, please visit the web page mentioned above. 

我又去找了其它一台 Centos 主机,发现 curl 返回的结果是正常的,从 web 端和centos 客户端 curl 都成功的看,像是我本机电脑的 curl 和sentry-worker主机出了问题。

之后用到网上找到使用openssl命令排查ssl错误的方法:

代码语言:javascript
复制
$ openssl s_client -showcerts -servername sentry.xxx.com -connect sentry.xxx.com:443  CONNECTED(00000003)  depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root  verify error:num=10:certificate has expired  notAfter=May 30 10:48:38 2020 GMT  ---  Certificate chain  0 s:/OU=Domain Control Validated/OU=GoGetSSL Wildcard SSL/CN=*.xxx.com  i:/C=LV/L=Riga/O=GoGetSSL/CN=GoGetSSL RSA DV CA  -----BEGIN CERTIFICATE-----  #...省略 

从上面执行命令返回的内容来看,这里的 CA 证书 AddTrust External CA Root 在 May 30 10:48:38 2020 GMT 这个时间过期了。

上网查了下相关的资料,发现他们官方发过一篇通告:Sectigo-AddTrust-External-CA-Root-Expiring-May-30-2020.

https://support.sectigo.com/articles/Knowledge/Sectigo-AddTrust-External-CA-Root-Expiring-May-30-2020

解决方案

现在算是找到为什么请求 https 会出现证书过期的原因了。接下来看下如何解决:

  1. 修改服务器ca配置
  2. 更新ca库信息

主机(Ubuntu)

修改服务器 CA 配置

修改服务器 ca 证书配置文件:/etc/ca-certificates.conf

代码语言:javascript
复制
sed -i "/AddTrust_External_Root.crt/d" /etc/ca-certificates.conf 

更新 CA 库

使用update-ca-certificates该命令用以更新目录/etc/ssl/certs来保存SSL证书,并生成 ca-certificates.crt:

代码语言:javascript
复制
$ sudo update-ca-certificates --fresh  Clearing symlinks in /etc/ssl/certs...  done.  Updating certificates in /etc/ssl/certs...  147 added, 0 removed; done.  Running hooks in /etc/ca-certificates/update.d...  done. 

重启主机上的应用程序。

容器(Docker-Alpine OS)

容器同主机上的修改差不太多。修改ca配置文件,之后执行更新命令。以下以alpine系统为例:

修改配置文件:

代码语言:javascript
复制
sed -i "/AddTrust_External_Root.crt/d" /etc/ca-certificates.conf 

更新 ca 证书链:

代码语言:javascript
复制
update-ca-certificates -f -v 

当然上面的两条命令最好是放在 Dockerfile 中,你知道,在容器里做的任何修改都是不可靠的(除非挂载了共享或卷)。

Dockerfile 示例,在 CMD 之前添加一行:

省略...

代码语言:javascript
复制
RUN sed -i "/AddTrust_External_Root.crt/d" /etc/ca-certificates.conf \  && update-ca-certificates -f -v  MacOS 

我自己电脑上的curl也是同样的问题,目前没找到好的自动修改的方式。不过找到了系统上的 ca 文件路径。

先备份下文件:

代码语言:javascript
复制
sudo cp /etc/ssl/cert.pem ~/etc-ssl-cert.pem-20200601 

之后,运行以下命令可以禁用掉过期的 CA 证书:

代码语言:javascript
复制
sudo sed -i "/^### AddTrust/,/^-.*END/ s/^/#/g" /etc/ssl/cert.pem 

上面是注释掉,当然你也可以直接编辑文件删除这些行。

验证

修改更新完 ca 配置后,再次执行curl 命令去访问之前的网站:

代码语言:javascript
复制
$ curl https://sentry.xxx.com 

这次访问正常了。

其他问题

当时出现问题时,还有另外一个现象,就是用 curl 访问其他网站(如,bing.com、qq.com)都是正常的。怀疑是不是目标域名使用的证书链不一样, 导致了只有我们业务域名出现了问题呢?

验证下猜想

使用 openssl 检查下我们业务域名证书的链:

代码语言:javascript
复制
# openssl s_client -connect sentry.xxx.com:443  CONNECTED(00000003)  depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority  verify return:1  depth=1 C = LV, L = Riga, O = GoGetSSL, CN = GoGetSSL RSA DV CA  verify return:1  depth=0 OU = Domain Control Validated, OU = GoGetSSL Wildcard SSL, CN = *.xxx.com  verify return:1  ---  Certificate chain  0 s:/OU=Domain Control Validated/OU=GoGetSSL Wildcard SSL/CN=*.xxx.com  i:/C=LV/L=Riga/O=GoGetSSL/CN=GoGetSSL RSA DV CA  1 s:/C=LV/L=Riga/O=GoGetSSL/CN=GoGetSSL RSA DV CA  i:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority  2 s:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority  i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root  ---  Server certificate  省略... 

在检测下上面说的其他网站 bing.com:

代码语言:javascript
复制
$ openssl s_client -connect cn.bing.com:443  CONNECTED(00000003)  depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root  verify return:1  depth=1 C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, OU = Microsoft IT, CN = Microsoft IT TLS CA 2  verify return:1  depth=0 CN = www.bing.com  verify return:1  ---  Certificate chain  0 s:/CN=www.bing.com  i:/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Microsoft IT/CN=Microsoft IT TLS CA 2  1 s:/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Microsoft IT/CN=Microsoft IT TLS CA 2  i:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root  ---  省略... 

我又测试了其他几个大的站点,发现都正常。为什么唯独我们的SSL证书链中的其中一个 CA(Sectigo AddTrust)过期了呢?

去查找下相关的文章,关键词 sectigo gogetssl 2020 may 30.

发现第三条记录中有gogetssl发布的新闻,标题是:Sectigo AddTrust External CA Root Expired May 30, 2020,感兴趣的可以点击进去看看。

https://www.gogetssl.com/news/23.html

新闻大致的意思:

由于Sectigo AddTrust外部CA根证书过期,影响了一些旧的设备或者一些老服务器,因为上面的根证书链中还存在该过期的 CA 证书。对于客户端(浏览器/SDK)来说,他们是不受该 CA 过期的问题影响。所以最大影响是在server端. 可以通过下载最新的 AddTrust RSA 证书替换过期的。

总结

目前该问题的影响面广不广,这个还暂时未知,不过根据我遇到的情况来看,影响大多在服务器端的外部服务之间的调用。对web用户端来说,因为浏览器内证书链是更新的,不涉及该问题。但对于服务端来说,对于一些对外调用的 https 请求,如果对方域名证书链中涉及到该过期CA的话,可能会访问失败。

Tips1:如果你的应用程序的部署方式是直接运行在主机上的话,可以使用配置管理工具(ansible/saltstack),统一修改。如果是容器话部署的情况,可能涉及的稍微多一些,需要修改项目的 Dockerfile,之后滚动更新该服务(当然如果你的应用不涉及到对外访问 https/ssl 调用,理论上可以延后更改!)。

Tips2:删除过期证书后,记得要重启主机上运行的服务!!!

  • 发表于:
  • 原文链接http://news.51cto.com/art/202006/619093.htm
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券