クラウドプロキシ下のSSLErrorについて
業務中に発生したクラウドプロキシ下でのPythonでHTTPSリクエストする際に発生するSSLErrorについての覚書
前提
使用クラウドプロキシ
Zscaler
RootCAは取得可能
エラー例
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)
いつ発生するか?
PythonのrequestsライブラリでHTTPS通信を行う際
requests.get('https://hoge.com', verify='/path/to/certfile')
Pythonのurllib3ライブラリでHTTPS通信を行う際
http = urllib3.PoolManager()
url = 'http://fuga/get'
response = http.request('GET', url)
urllib3を使用しているライブラリ例.
- gcloud
- kubectl?(状況から推測、実際に使ってるかはわからない)
修正方法
RootCAを各ツールごとに設定する
→基本的に、プロキシの証明書が原因でSSLエラーになるパターンでは環境変数に設定すれば反映されることが多い
下記、ChatGPTで出力した主要なツールの環境変数パターン
(さすがに全部覚えてないので生成AIを使用、間違ってたらそのうち直します、あくまで例としてみてください)
🌐 共通(多くのCLIツールで有効)
環境変数 内容
SSL_CERT_FILE PEM形式のCA証明書ファイルのパス
🐍 Python / pip / requests
環境変数 内容
SSL_CERT_FILE PythonでのSSL通信に使用するCA証明書ファイル
REQUESTS_CA_BUNDLE requestsライブラリ専用のCA証明書パス
PIP_CERT pip専用のCA証明書パス
💡 通常は SSL_CERT_FILE だけで済みますが、pipやrequestsには個別に指定が必要な場合があります。
🦀 Node.js / npm / yarn
環境変数 内容
NODE_EXTRA_CA_CERTS 追加のCA証明書ファイル(PEM形式)を指定
🐘 Git
環境変数 / 設定項目 内容
GIT_SSL_CAINFO Gitで使用するCA証明書ファイルのパス
http.sslCAInfo (git config) 上記と同様、.gitconfig でも指定可能
☕ Java (JVM)
環境変数 / 起動オプション 内容
-Djavax.net.ssl.trustStore TrustStoreのパス(JKS or PKCS12)
-Djavax.net.ssl.trustStorePassword TrustStoreのパスワード
-Djavax.net.ssl.trustStoreType TrustStoreのタイプ(例:JKS、PKCS12)
※JavaはPEM形式をそのまま扱えないため、keytoolなどでJKSに変換する必要があります。
🐳 Docker
環境変数 内容
SSL_CERT_FILE または /etc/docker/certs.d/ 配下のCA証明書設置
Docker自体は環境変数よりも証明書の配置による対応が主流です。
🐧 curl / wget
ツール 環境変数・オプション
curl CURL_CA_BUNDLE または --cacert
wget --ca-certificate または .wgetrc に ca_certificate = /path/to/ca.pem
今回の例だと、Pythonのrequestsライブラリの場合はREQUESTS_CA_BUNDLEに設定すればうまく通信ができるようになる。
が、urllib3を使っている場合が少し面倒くさい。
urllib3の場合
urllib3の場合、内部的にcertifi.where()を呼び出してcertifiのCAバンドルを使ってSSL検証する。
このcertifi.where()が厄介で、環境変数を読み込んでいない。
※ドキュメントとか見たわけじゃないのでおそらくです。知ってる人いたら教えてください。
じゃあどこからCAバンドルを読み込むかというと、
/path/to/python/site-packages/certifi/cacert.pem
※/path/toはそれぞれの環境でのPythonインストール先
を読み込んでいる。
urllib3の場合は、このcacert.pemを開いて適当なところにZscalerのRootCA(pem形式)を張り付けて保存することでその証明書を使用してSSL通信をするようになる。
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgIUR4FkgdNfTzN+R1L1Jz7FykmUwD0wDQYJKoZIhvcNAQEL
BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQHDAZTYW5Kb3Nl
MQ8wDQYDVQQKDAZFeGFtcGxlMRcwFQYDVQQDDA5FeGFtcGxlIFJvb3QgQ0EwHhcN
MjQwMTAxMDAwMDAwWhcNMzQwMTAxMDAwMDAwWjBSMQswCQYDVQQGEwJVUzELMAkG
A1UECAwCQ0ExDzANBgNVBAcMBlNhbkpvc2UxDzANBgNVBAoMBkV4YW1wbGUxFzAV
BgNVBAMMDkV4YW1wbGUgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALRGrhJpZ3K91W1eJ+XJxUMH/ZT0YOC5jC6kGwKIPpN+Qk9n2WDVphmT
0U5V2ZOhVOY+HhB8f0sK2TJJ6kZUlGBjz2h3kLuG1kaKfEp5n7n3hv7BPtB7ZDld
94gBZhVJvvF3vQ+tL9XZUG9N9A4aJDr3z9ZCrTuPQ79EiE6DAk5WRGLQ7lAvIV0P
t0WEe1MBKglhF79cV8NKw1kkIBSxZcYu2rCwLxqEB5cMcPQcF3Vy+45CslVaIxar
AzYuG9Ij0eJSpNk8Blz2GEZNgjJxCSaJd5zSL9CgQgWprH96dpEyhRL5UPIukYMd
1ThUw38KbRV0yKzTBN91XxECb1DOPmECAwEAAaNTMFEwHQYDVR0OBBYEFLiKcF+b
y9PfZb8Qyy6+PhY1E4vSMB8GA1UdIwQYMBaAFLiKcF+by9PfZb8Qyy6+PhY1E4vS
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABJ3R1OmR7d9G9zq
h6c2VUzFE6Q0GcN3o6EhiuABtMH6hNskEJg6vRZ4xK/yjcQImtYF+apvH2iKJ7Er
0LVc0IgpSRYVPpqUl8nFBDTCePz5DLx6F9ujAhNzXyOhwSnngvIV4xjYZ+1L2Q5D
iEipR7q0P7eNDvh4OhmN9h9tB5rR0+dceMf7m1K9cCAwrGRzFsbEiVcEBcNL9aqG
XKY3OUWr3bT88lwCQcZslYx3KeUwDe8P+yA1aDUCJ5Tsk4cDqSpkYLoQ6IG74N3H
8j2kQK5kEcRHTF7kD0F0GkhRfsNLiYG+q3q/NmWMyD+WDWzoLpyGxgx04ViQfGjq
xGo=
-----END CERTIFICATE-----
※上記はChatGPTで生成したダミーの証明書
kubectlの場合はこれをやると通信が可能になったのでurllib3を利用していると判断した。
逆に、gcloudはライブラリのソース見る限りだとurllib3を使ってるのに、上記を行うだけではまだSSLエラーが出る状態だった。
なぜ…。
gcloudの場合
実は、gcloudの場合は
/path/to/gcloud/configurations/config_default
に設定ファイルを持っており、ここに指定されているCAバンドルを優先して使用する
[core]
custom_ca_certs_file = /path/to/your/cacert.pem
私の場合、ここがなぜか変な値で設定されており、優先的に使用されることでエラーが発生していた。
何もしていないはずなのになぜ…。
※何もしていないのにパソコンが壊れた!並みの信用
ここを先ほどの
/path/to/python/site-packages/certifi/cacert.pem
にすることで無事に疎通した。
(当然ZscalerのRootCAは追記している前提)
まとめ
HTTPS通信でssl.SSLCertVerificationErrorが発生した!
- ツールごとに適切な環境変数を設定しよう
それでもエラーが出る!! or そもそも適切な環境変数が見つからない!!
- urllib3を使用しているか確認
- 使用している場合は、
/path/to/python/site-packages/certifi/cacert.pem
に追記 - ライブラリが使用している場合もあるので、Pythonっぽかったらとりあえず追記しとくと良い
- 使用している場合は、
それでもエラーが出る!!! and 対象はgcloud!!!
- /path/to/gcloud/configurations/config_defaultを見る
- custom_ca_certs_file = /path/to/your/cacert.pemをクラウドプロキシを含んだCAバンドル指定するように修正する
それでもエラーが出る!!!!
\\_
:三ニ=:::::::ヽ
:ヽ.ニ=::て.>廴_
三.ヽ= (⌒ヽ;:;:;,.二)
ニ=-ヽ:ヽ、,∠.^^ぅ わからん。その願いは私の力を超えている。
〃,べ= ̄ニ二 ̄
/;:ィリ ノノ ,.へヽ
;:ヘ/ ̄ ̄ ̄Vヽヽ
ソ ├┤|
完
Discussion