Python和请求的自签名CA验证错误

问题描述

由于我的Kubernetes集群没有自己的FQDN,我遇到了一些Python和请求问题。

简而言之,它是一个群集,具有许多不同的名称空间和入口。内部路由是根据请求标头和列入白名单的IP中的主机来管理的。当我尝试将获取请求(带有客户端证书)拍摄到IP时,出现以下异常:
HTTPSConnectionPool(host='*MyExternalIpAddr*',port=443): Max retries exceeded with url: /test(Caused by SSLError(SSLCertVerificationError(1,'[SSL: CERTIFICATE_VERIFY_Failed] certificate verify Failed: unable to get local issuer certificate (_ssl.c:1076)')))

我遇到的问题归因于以下代码

url = "https://*MyExternalIpAddr*/test"
headers = {"Host":"*TheHostnameInTheCluster*"}
cert = (cert_file_path,key_file_path)
r = requests.get(url,headers=headers,cert=cert,auth=auth,verify=ca_file)

我99%的确定IR-url是问题所在,因为如果我将外部IP映射到drivers / etc / host中的主机名(并将URL更改为“ https:// hostname / test”),请求顺利通过。

现在,我假设它与Requests根据rootCA(CN或SAN?)检查客户端证书的方式有关。不幸的是,我还不够聪明,无法用Google搜索过去的经历。

值得一提的是,所有证书都是使用openSSL自行生成的,因此我可以根据需要更改它们。尽管我也许可以将IP放在SAN中,但是由于集群中会有许多具有不同证书包的微服务,所以我认为这可能会导致冲突。(p)。

我希望找到一种聪明的方法来用Python解决这个问题,因此,我向您求助,这是互联网的巨大集体智慧。

期待您的回音(很抱歉,如果我忽略了先前对类似问题的回答;我已经四处搜寻,但无济于事)!

编辑

因此,我逐渐意识到问题与客户端证书无关,而与根CA验证服务器证书的方式有关。

我尝试将IP添加到服务器证书中的SAN中,并且可以正常工作。我的意思是说,当我从IP中“获取”(不得不使用主机文件中的FQDM映射的名称)时,邮递员再也不会摆出乱七八糟的样子了,但是不幸的是,请求没有跟上。有什么想法吗? :)

解决方法

所以我用ForcedIPHTTPSAdapter解决了它。

import requests
from requests.auth import HTTPBasicAuth
from forcediphttpsadapter.adapters import ForcedIPHTTPSAdapter
### You'll have to "pip install requests[security] forcediphttpsadapter" ###


if __name__ == "__main__":
    cert_file_path = r"*path_to*\client.crt"
    key_file_path = r"*path_to*\client.key"
    ca_file = r"*path_to*\rootCA.crt"
    auth = HTTPBasicAuth("*UID*","*PWD*")
    ### Cluster IP ###
    cip = "*127.0.0.1*"
    base_url = "*https://hostname.com*"
    endpoint = "/test"
    cert = (cert_file_path,key_file_path)
    s = requests.Session()
    s.mount(base_url,ForcedIPHTTPSAdapter(dest_ip=cip))
    r = s.get(base_url + endpoint,cert=cert,auth=auth,verify=ca_file)
    if r.status_code == 200:
        print(r.text)

它的另一个好处是不必在标题中指定主机!