AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

简介

在前面的一些文章中,我们用到了 AWS Cli。比如为 ECS Fargate 建 Task 和 Service。

处于安全原因,很多公司都是通过 http 代理访问 internet,这时使用 AWS Cli 操作 AWS 时,可能会碰到“SSL validation failed”错误。

比如运行如下命令

aws sts get-caller-identity

会产生如下报错

SSL validation failed for https://sts.cn-north-1.amazonaws.com.cn/ [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

图 1
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

这时可以用“–no-verify-ssl”参数解决

aws sts get-caller-identity --no-verify-ssl

但这种方式不但降低了安全性,而且结果总会带有一长串恼人的告警

urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host 'pitc-zscaler-americas-cincinnati3pr.proxy.corporate.ge.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

图 2
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

本文分析产生这种问题的原因,并给出解决方法,使得通过 http 代理使用 AWS CLi 时不再需要“–no-verify-ssl”参数。

AWS CLi 用的是 Python,所以此方法也适用于单纯的 Python 报此错误

本文主要以 AWS Cli version 2 为例说明,最后会给出 AWS Cli version 1 的解决方法。

目录

  • 环境(配置)
  • AWS Cli 简介
  • 实战步骤
    1. 报错重现
      • 安装 AWS Cli
      • 测试报错
    2. 错误分析与解决方法
      • 错误分析
      • 解决方法
      • AWS Cli version 1
  • 总结
  • 引申
  • 后记

环境(配置)

  • AWS 中国或 Global 帐号,可在官网申请,一年内使用指定资源免费
  • AWS cli version 2,Win10 + terminal

AWS Cli 简介

AWS Command Line Interface(AWS CLi)是 AWS 开源工具,允许用户以命令行的形式对 AWS 资源进行操作。

AWS CLi 可以实现 AWS 网页控制台一样的功能,而且有些 AWS 特性只能通过 AWS Cli 实现。

AWS Cli 虽然使用起来没在网页上操作那么直观,但更简洁高效,生产中用AWS Cli其实也更多一些。

另外在与 Jenkins 做 CICD 集成时,除了用 aws 插件,使用 AWS CLi 也是经常使用的方式。

AWS Cli 支持两种系统

  • Linux shells Linux 或者 macOS
  • Windows command line cmd 或者 PowerShell

AWS Cli 版本

  • 2.x 当前主流版本,与 python 集成,不需要单独安装 python
  • 1.x 老版本,需独立安装 python

实战步骤

1. 报错重现

首先,我们在 linux 环境下安装 AWS Cli 2

安装 AWS Cli 2

运行以下命令安装

#下载安装包
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip"
#解压到本地aws目录
unzip awscliv2.zip
#用root用户安装
sudo ./aws/install

安装完成后,可以用如下命令测试

aws --version

图 3
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

测试报错

在公司的内网中,没加公司 http 代理,运行命令
export AWS_PROFILE=YOUR_CONFIGURED_IAM_USER
aws sts get-caller-identity

说明:此命令用来返回当前用户的信息,使用 aws configure 配置后即可使用。

报错

Could not connect to the endpoint URL: "https://sts.cn-north-1.amazonaws.com.cn/"

无法连到https://sts.cn-north-1.amazonaws.com.cn/

图 4
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

在公司的内网中,加上公司代理,运行命令失败,报错
export AWS_PROFILE=YOUR_CONFIGURED_IAM_USER
export http_proxy=YOUR_HTTP_PROXY_NAME:80
export https_proxy=YOUR_HTTP_PROXY_NAME:80
aws sts get-caller-identity
SSL validation failed for https://sts.cn-north-1.amazonaws.com.cn/ [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

图 5
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

在公司的内网中,加上公司代理,加上“–no-verify-ssl”参数,运行命令成功,但是有告警
export AWS_PROFILE=YOUR_CONFIGURED_IAM_USER
export http_proxy=YOUR_HTTP_PROXY_NAME:80
export https_proxy=YOUR_HTTP_PROXY_NAME:80
aws sts get-caller-identity --no-verify-ssl

图 2
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

如果我们在相同的环境下,直接连接 internet(比如,我用的手提断开公司连接,直接连 wifi)运行命令,成功

图 6
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

2. 错误分析与解决方法

错误分析

我们在公司内网中,使用代理,再一次运行相同的命令,这次加上“–debug”参数

aws sts get-caller-identity --debug

加上 debug 参数后,输出信息非常长,这里只截取了其中一段

MainThread - botocore.httpsession - DEBUG - Certificate path: /usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem

图 7
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

输出信息显示 AWS Cli 从“/usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem”文件中查找网站证书。

结合测试中的报错信息“unable to get local issuer certificate”

我们可以推断出,“/usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem”中缺少必要的证书。

这个证书是什么?

从上述测试可以看到,如果连接 internet 时使用了公司代理,则或者报错,或者告警;而不使用代理直接连接 internet 则完全没有问题。

所以客户端(AWS Cli)和服务器端(sts.cn-north-1.amazonaws.com.cn)都没有问题,问题出在使用的 http 代理服务器上。

也就是说 cacert.pem 缺少的应该是代理服务器的证书。

解决方法

代理服务器的证书,一般需要向公司网络管理员获取。(我所在的环境中,公司提供了下载此证书的网站,所以可以自行下载)

用本文编辑打开公司证书,把内容复制到“/usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem”的最后

公司证书内容如下

-----BEGIN CERTIFICATE-----
MIIDozCCAougAwIBAgIQeO8XlqAMLhxvtCap35yktzANBgkqhkiG9w0BAQsFADBS
....
5ad/qyN+Zgbjx8vEWlywmhXb78Gaf/AwSGAwQPtmQ0310a4DulGxo/kcuS78vFH1
mwJmHm9AIFoqBi8XpuhGmQ0nvymurEk=
-----END CERTIFICATE-----

可用 vi 命令,复制到 cacert.pem 的最后

sudo vi /usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem

保存后,我们重新在公司内网加代理的环境下测试

export AWS_PROFILE=YOUR_CONFIGURED_IAM_USER
export http_proxy=YOUR_HTTP_PROXY_NAME:80
export https_proxy=YOUR_HTTP_PROXY_NAME:80
aws sts get-caller-identity

这时运行成功,和直接连接 internet 的情况一样了

图 6
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

说明我们的猜测是正确的,由于本地环境中缺少 http 代理服务器的证书,导致 AWS Cli 报 SSL: CERTIFICATE_VERIFY_FAILED 错误。

AWS Cli version 1

上述分析和解决是基于 AWS Cli 2,AWS Cli 1 的处理方法略有不同。

在 AWS CLi 1 的环境下运行 debug 时,输出的的信息中并没有提供类似“Certificate path: /usr/local/aws-cli/v2/2.1.30/dist/botocore/cacert.pem”这样的信息。

AWS CLi 1 与 AWS CLi 2 不同,需要单独安装 python,所以我们可以通过 python 找到证书路径。

首先,确定 AWS Cli 使用的 python 版本

aws --version

图 8
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

然后运行如下 python 命令,查看 request 使用的证书路径

python
import requests as r
print(r.certs.where())

图 9
AWS CLI SSL: CERTIFICATE_VERIFY_FAILED 错误分析与解决

最后,像上面一样把公司代理服务器的证书,添加到此路径证书的最后即可。

总结

AWS Cli 报 SSL: CERTIFICATE_VERIFY_FAILED 错误,是调用 Python 代码报的错 python 包 urllib3 传递 https 请求时,会要求网站证书或其根证书。

当通过公司代理服务器时访问外网时,urllib3 也会要求代理服务器的证书。

但 python 安装时(如果安装了 request 包或者 certifi 包),只会包含大型证书服务商提供的根证书,并不会包含公司内部代理服务器的证书。所以会报找不到证书的错误。

这时我们要么选择用“–no-verify-ssl”,要么手工导入代理服务器证书。

在 Python 官网上 request 一段可以查到如下内容

Finally, note that using a proxy for https connections typically requires your local machine to trust the proxy’s root certificate.

引申

如果是自己部署的 http 代理服务器,也可以用下列 openssl 命令产生代理服务器的自签名证书,然后复制 example.crt 中的内容。

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -subj "/CN=YOUR_PROXY_NAME.com"

AWS CLi 这个错是 python 的错,搞清楚了这个问题,在 python 代码中遇到同样的错也可以用相同的方法解决。

网上也有说用如下命令,解决类似问题

pip install certifi

但 Certifi 里面是 Mozilla 提供的一组根证书,只可以解决连接大部分网站的证书问题。

如果是公司内网的代理服务器,基本上是不可能通过这种方法解决的,只能通过手工导入解决。

资源下载

这篇文章讲的很详细,很有启发
https://lukasa.co.uk/2013/07/Python_Requests_And_Proxies/

这个讨论挺有帮助
https://*.com/questions/22027418/openssl-python-requests-error-certificate-verify-failed

Python 官网上那段可在下列链接中找到
https://docs.python-requests.org/en/master/user/advanced/

后记

之前也尝试解决这个问题,可惜一直没成功。主要还是不明白其中的原理,只是把网上 X 度搜到的方法机械的试一遍。

这次查了不少资料,连蒙带试,终于把 SSL: CERTIFICATE_VERIFY_FAILED 这个老问题解决了。

把详细分析和解决过程记下来,省得以后忘了,另外也分享给有需要的人。

更多内容,请关注微信公众号“全是 AWS 干货”

上一篇:springcloud-服务发现Discovery


下一篇:springboot应用在Eureka安全下线