CentOS下Python脚本更换SSL后报hostname.bundle错误
问题排查与解决方案
你遇到的FileNotFoundError是老版本cheroot(Python3.6源内置版本普遍存在该问题)的误导性报错,绝大多数场景下并非真的找不到hostname.bundle文件,而是证书链格式错误、权限/SELinux拦截、参数兼容问题导致OpenSSL加载链失败,被异常捕获逻辑统一抛出了文件不存在的错误。
第一步:排除隐性路径/权限问题
不要通过root用户肉眼核查路径权限,必须以实际运行Python脚本的系统用户身份验证文件可读性,同时修复CentOS默认开启的SELinux上下文问题:
- 执行以下三条命令验证文件可读性,将命令中的
服务运行用户替换为你实际启动脚本的用户(比如普通web用户、www用户等,不要用root测试):sudo -u 服务运行用户 cat /etc/pki/tls/certs/hostname.cert > /dev/null sudo -u 服务运行用户 cat /etc/pki/tls/private/hostname.key > /dev/null sudo -u 服务运行用户 cat /etc/pki/tls/certs/hostname.bundle > /dev/null - 如果任意一条命令返回
Permission denied,先不要手动改777权限,直接执行以下命令修复/etc/pki目录下的SELinux安全上下文即可:restorecon -Rv /etc/pki/tls/ - 如果三条命令均无任何输出(代表可读),则可确定是证书链内容/配置参数的问题。
第二步:生成正确格式的hostname.bundle
你当前把服务器证书副本作为bundle内容是完全错误的,DigiCert通配符证书的bundle文件(即CA证书链)不能包含你自己的服务器证书,仅需按固定顺序拼接所有上级CA证书:
- 从你下载的DigiCert证书包中找到两个CA证书文件:
- 中间CA证书:文件名通常类似
DigiCert TLS RSA SHA256 2020 CA1.crt - 根CA证书:文件名通常类似
DigiCert Global Root CA.crt
- 中间CA证书:文件名通常类似
- 严格按照「中间证书在前、根证书在后」的顺序拼接,生成正确的bundle文件:
cat /path/to/你的DigiCert中间证书.crt /path/to/你的DigiCert根证书.crt > /etc/pki/tls/certs/hostname.bundle - 校验bundle格式正确性,执行以下命令无报错、能正常输出两个证书的主题/颁发者信息即为合格:
openssl crl2pkcs7 -nocrl -certfile /etc/pki/tls/certs/hostname.bundle | openssl pkcs7 -print_certs -noout
注意:拼接时要确保证书文件没有多余的空行、乱码,每个证书的
-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----首尾行完整无缺失,不要把自己的域名服务器证书内容追加到bundle中,否则会直接触发加载失败。
第三步:规避老版本cheroot的参数兼容bug
你当前使用的Python3.6对应版本的BuiltinSSLAdapter对certificate_chain参数的处理存在已知bug,如果按上述步骤生成正确bundle后仍然报错,可以直接换用全版本兼容的配置方式:
- 把CA证书链内容直接追加到
hostname.cert文件末尾,顺序为:你的域名服务器证书 → 中间CA证书 → 根CA证书 - 修改Python脚本的SSL配置,去掉
certificate_chain参数:HTTPServer.ssl_adapter = BuiltinSSLAdapter( certificate = "/etc/pki/tls/certs/hostname.cert", private_key = "/etc/pki/tls/private/hostname.key" )
验证
重启脚本后,执行以下命令验证证书链加载正常,输出中无verify error、能看到完整的三级证书链即为配置成功:
openssl s_client -connect 你的服务域名:服务端口 -showcerts
内容的提问来源于stack exchange,提问作者The Oz Snowman
相关产品推荐
相关产品推荐

