WordPress が内部で呼び出した cURL で自己認証局の証明書を見てくれない謎

スポンサーリンク

はじめに

 現在 LAN 内でのみ動作させている動作テスト用 WordPress では HTTPS でアクセスするときのサーバー証明書は自己認証局で署名した物にしている。通称オレオレ証明書という代物。
 OS である CentOS のシステムでは自己認証局の証明書 ca.crt を信頼するように設定している。
 「cp ca.crt /usr/share/pki/ca-trust-source/anchors/」をして「update-ca-trust extract」を行うアレ

 WordPress 内部から呼び出される cURL ではこの信頼したと判断すべきファイルをなんでか見てくれないので色々問題が起きたというお話しに。

問題の無いところ

 で、cURL 自体はコマンドラインからの実行で何ら問題なく自己認証局による署名を行ったサーバー証明書でもアクセスが出来る。

curl -v -I --http2 https://test.example.com/
*   Trying 192.168.1.8...
* TCP_NODELAY set
* Connected to example.com (192.168.1.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
(snip..
*  issuer: C=JP; ST=Kanagawa; L=Yokohama; O=bp7.org; CN=OreOreCA; emailAddress=xxx
*  SSL certificate verify ok.

 ググってて見つけた PHP で cURL を用いる次のスクリプトも同様に動作した。結果は上に全く同じ。

<?php
    $ch = curl_init("https://example.com/");
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
?>

困った問題

 しかし WordPress が内部で呼び出している cURL に関してのみ /etc/pki/tls/certs/ca-bundle.crt を見てくれていない様で証明書の検証がエラーを吐いて動作してくれず、次のようなエラーを吐く。

cURL error 60: SSL certificate problem: unable to get local issuer certificate

 そんなもんで動作している PHP の設定ファイル php.ini にて次のような設定を行った。

[curl]
curl.cainfo = /etc/ssl/certs/ca-bundle.crt
[openssl]
openssl.cafile = /etc/ssl/certs/ca-bundle.crt
openssl.capath= /etc/ssl/certs

 設定の反映を確認する。

php -i | grep -E "ca(info|file|path)"
openssl.cafile => /etc/ssl/certs/ca-bundle.crt => /etc/ssl/certs/ca-bundle.crt
openssl.capath => /etc/ssl/certs => /etc/ssl/certs

 再度各種動作確認をするもやはりエラーを吐く。php-fpm の pool 設定で php_admin_value[curl.cainfo] 等としても結局同じ設定を 2 度やってるだけで意味も無く。
 例えば Nginx の FastCGI Cache のパージを行ってくれる Nginx Helper というプラグインがあるが、これは内部で cURL を用いてパージ用アドレスを呼び出す事でパージしてくれているのだが……

2018-10-15 08:13:41  | ERROR | Error while purging URL. cURL error 60: SSL certificate problem: unable to get local issuer certificate

 というエラーが大量に発生する。つまりキャッシュパージが正常に行えない状態になる。
 Health Check & Troubleshooting というプラグインの Health Check という項目でもエラーをだしてしまう。

ループバックリクエスト     サイトへのループバックリクエストに失敗しました。これは WP_Cron の動作やテーマ・プラグインエディターの動作に影響を与える可能性があります。
エラーが発生しました: (0) cURL error 60: SSL certificate problem: unable to get local issuer certificate

 この Health Check のメッセージ通り WordPress の動作が上手いこと行っていない状態に。

解決策

 WordPress で cURL の呼び出しをしている関数内部で cURL の呼び出し設定をしている部分を書き換えてみたりしても余り上手くは行かず、本当にどうしようかなと悩んでいたら WordPress のプラグインを見つけた。

Wise Builds cURL Options
Allows configuration of cURL connection options.

 この Wise Builds cURL Options という物は cURL を使用する際に PHP で設定するパラメータを WordPress 上で対象ホスト毎に設定出来るという物。
 これを WordPress にインストールし、設定を行う。
 cURL Rules 以下 Add Rule をクリックして Host に自分のホスト名を入力。Protocol に https として Options に CURLOPT_SSL_VERIFYPEER を入力し、Value は FALSE とする。

 Wise Builds cURL Options 設定例

 PHP から cURL を呼び出す際に設定するパラメータで CURLOPT_SSL_VERIFYPEER というのは証明書の検証を行うか否かを TRUE or FALSE という bool 値でとる。FALSE とする事で証明書の検証を行わせないので「証明書検証に関するエラー」が出なくなりアクセスも出来るようになるという仕組み。
 割と強引な解決法となった。WordPress のソースを追いかけては見た物の PHP は良く分からないので下手に改編するよりもこの方が良かったかなと今は思ってみる。内部検証用だし―― と。

 ちなみにこの Wise Builds cURL Options で CURLOPT_CAINFO オプションとして /etc/pki/tls/certs/ca-bundle.crt と設定をしてみたがこれもどうやら駄目なようだった。

手早い解決策 (2018/10/16 0:47 追記)

 記事にした後も気になってしょうがないから WordPress のソースを追って得られた情報をググってみたりしたら手早い解決策があった。
 次の PHP コードを functions.php に追加するだけ。

add_action('http_api_curl', function( $handle ){
        curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
}, 10);

 最初に書いたプラグインをインストールするよりもこちらの方が手軽で良いだろうと思う。
 こちらも同様にして SSL/TLS 接続における証明書の検証を行わない様にするという物。

スポンサーリンク