Jenkins API调用报CERTIFICATE_VERIFY_FAILED证书错误如何解决
问题背景
部署若干虚拟机后,编写Python脚本对接内部运行的Jenkins站点,脚本在原有环境运行一切正常:
将完全相同的代码迁移到另一台服务器运行时,抛出如下错误:
$ py test.py Traceback (most recent call last): File "C:\programs\python3102\lib\site-packages\urllib3\connectionpool.py", line 597, in urlopen httplib_response = self._make_request(conn, method, url, File "C:\programs\python3102\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request self._validate_conn(conn) File "C:\programs\python3102\lib\site-packages\urllib3\connectionpool.py", line 839, in _validate_conn conn.connect() File "C:\programs\python3102\lib\site-packages\urllib3\connection.py", line 337, in connect self.sock = ssl_wrap_socket( File "C:\programs\python3102\lib\site-packages\urllib3\util\ssl_.py", line 344, in ssl_wrap_socket return context.wrap_socket(sock, server_hostname=server_hostname) File "C:\programs\python3102\lib\ssl.py", line 512, in wrap_socket return self.sslsocket_class._create( File "C:\programs\python3102\lib\ssl.py", line 1070, in _create self.do_handshake() File "C:\programs\python3102\lib\ssl.py", line 1341, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\programs\python3102\lib\site-packages\requests\adapters.py", line 439, in send resp = conn.urlopen( File "C:\programs\python3102\lib\site-packages\urllib3\connectionpool.py", line 637, in urlopen retries = retries.increment(method, url, error=e, _pool=self, File "C:\programs\python3102\lib\site-packages\urllib3\util\retry.py", line 398, in increment raise MaxRetryError(_pool, url, error or ResponseError(cause)) urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='xxx.com', port=443): Max retries exceeded with url: /crumbIssuer/api/json (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)'))) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\usnname\Desktop\test.py", line 20, in <module> test = jenkins_connection.get_node_info(node) File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 1504, in get_node_info response = self.jenkins_open(requests.Request( File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 557, in jenkins_open return self.jenkins_request(req, add_crumb, resolve_auth).text File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 573, in jenkins_request self.maybe_add_crumb(req) File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 370, in maybe_add_crumb response = self.jenkins_open(requests.Request( File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 557, in jenkins_open return self.jenkins_request(req, add_crumb, resolve_auth).text File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 576, in jenkins_request self._request(req)) File "C:\programs\python3102\lib\site-packages\jenkins\__init__.py", line 550, in _request return self._session.send(r, **_settings) File "C:\programs\python3102\lib\site-packages\requests\sessions.py", line 646, in send r = adapter.send(request, **kwargs) File "C:\programs\python3102\lib\site-packages\requests\adapters.py", line 514, in send raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='xxx.com', port=443): Max retries exceeded with url: /crumbIssuer/api/json (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)')))
已知环境信息:
- 两台服务器均运行Python 3.10.2版本,安装的依赖包完全一致
- 两台机器通过Chrome浏览器访问该Jenkins站点均无证书报错
- 测试代码如下:
try: import jenkins except ImportError: import pip pip.main(["install", "--upgrade", "python-jenkins"]) import jenkins # 登录配置 JENKINS_URL = "https://xxx.com" USERNAME = "xxx" API_TOKEN = "xxx" JENKINS_NODES = ["PD100089"] # 通过API令牌连接服务 jenkins_connection = jenkins.Jenkins(JENKINS_URL, USERNAME, API_TOKEN) # 遍历节点列表将节点置为在线状态 for node in JENKINS_NODES: # 获取节点配置信息 test = jenkins_connection.get_node_info(node) # 检查节点在线状态 if not test['offline']: print("- " + node + " is already online...") continue # 重新上线节点 print("- Turning " + node + " back online...") jenkins_connection.enable_node(node)
根因分析
报错核心是SSL证书校验失败,证书链中存在自签名证书。
Chrome访问正常但Python请求报错,根源是两者使用的证书信任库不互通:Chrome默认调用Windows系统自带的证书信任存储,而Python 3.10+版本的requests/urllib3请求栈默认使用certifi包维护的独立根证书列表,不会自动读取系统层面信任的内部CA证书、自签名证书。
两台环境表现不一致,直接核对两个差异点即可定位:
- 旧服务器的Python环境已经导入过Jenkins站点的内部根证书,或者配置了全局
REQUESTS_CA_BUNDLE环境变量指向内部CA证书路径 - 新服务器未做上述证书配置,Python校验证书链时找不到可信根证书,直接抛出校验失败错误
修复方案
按场景选择对应方案,生产环境优先使用证书信任配置,不推荐直接关闭校验。
方案1:导入内部根证书到Python信任链(生产环境推荐)
- 从Chrome导出Jenkins站点的根CA证书:访问Jenkins站点时点击地址栏左侧锁形图标,依次进入「连接是安全的」-「证书有效」-「证书路径」,选中最顶层的根证书,点击「查看证书」-「详细信息」-「复制到文件」,导出为Base64编码的CER格式文件,例如命名为
jenkins_root.cer。 - 执行以下命令获取当前Python环境的certifi证书存储路径:
import certifi print(certifi.where())
- 将导出的根证书文本内容,追加到上一步输出的
cacert.pem文件末尾,重新运行脚本即可正常通过证书校验。
如果不想修改全局certifi证书配置,也可以在初始化Jenkins连接时单独指定CA证书路径:
jenkins_connection = jenkins.Jenkins( JENKINS_URL, USERNAME, API_TOKEN, ssl_ca_cert="本地存放jenkins_root.cer的绝对路径" )
方案2:临时关闭SSL校验(仅内网测试环境使用)
如果是测试环境无需配置证书,可在初始化连接时传入ssl_verify=False参数关闭证书校验,同时关闭urllib3的SSL警告避免多余输出:
import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) jenkins_connection = jenkins.Jenkins( JENKINS_URL, USERNAME, API_TOKEN, ssl_verify=False )
注意:该方案会跳过所有SSL证书校验逻辑,存在中间人攻击风险,禁止在生产环境使用。
内容的提问来源于stack exchange,提问作者Mads Sander Høgstrup
相关产品推荐
相关产品推荐

