🌊

クラウドプロキシ下の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