curl で「SSL certificate problem」が出て HTTPS にアクセスできない
curl は接続先のサーバ証明書を CA バンドルで検証し、たどれなければ exit code 60 で止まる。
原因は CA バンドルの欠落か、社内プロキシ・自己署名証明書による差し替えのどちらかで、正しい CA を渡せば解決する。
公開:
要約
curl: (60) SSL certificate problem: unable to get local issuer certificate は、サーバが提示した証明書からルート証明書までの経路を curl が作れなかったという意味である。
サーバ側が壊れているとは限らず、curl 側が信頼する CA の一覧に、その経路の起点が入っていないことのほうが多い。
したがって直すべきは「どの CA を信頼させるか」であり、検証を切ることではない。-k を付ければ確かに通るが、その時点で通信相手が本物かどうかを確かめる手段を失う。
よくある原因
- CA バンドルが古い、または存在しない。
最小構成の Docker イメージや古い CI ランナーではca-certificatesが入っていないことがある。 - 社内プロキシが TLS を終端して独自の証明書に差し替えている。
ブラウザは会社が配布した CA を信頼するよう設定済みでも、curl はそれを見ていない。 - 接続先が自己署名証明書を使っている。
開発用のローカルサーバでよくある。 - サーバが中間証明書を送っていない。
ブラウザは不足分を自動で取りに行くことがあるため「ブラウザでは見えるのに curl だけ落ちる」という形で表面化する。
解決策
1. まず -v でチェーンを見る
curl -v https://example.com/ 2>&1 | grep -E "subject:|issuer:|SSL certificate"issuer: に社名や見慣れない CA が出れば 2 の可能性が高い。subject: と issuer: が同じなら自己署名である。
2. CA バンドルを更新する
# Debian / Ubuntu
apt-get update && apt-get install -y --reinstall ca-certificates
# Alpine
apk add --no-cache ca-certificatescurl 公式は Mozilla のルート証明書から生成した cacert.pem を配布しているので、パッケージを使えない環境ではこれを取得して使う(Extract CA Certs from Mozilla(新しいタブで開く))。
3. 独自 CA を明示的に渡す
社内 CA や自己署名の CA 証明書が手元にあるなら、それを指定する。
curl --cacert /path/to/corp-ca.pem https://internal.example.com/毎回書きたくない場合は環境変数を使う。
curl は CURL_CA_BUNDLE が設定されていればそのパスを CA バンドルとして読む(Schannel を使う Windows ビルドを除く)。
export CURL_CA_BUNDLE=/path/to/corp-ca.pem4. 中間証明書の欠落はサーバ側で直す
クライアント側に足せるのはルート CA までで、中間証明書はサーバが送るべきものである。openssl s_client -connect example.com:443 -showcerts で送られてくる証明書が 1 枚しかない場合は、サーバの証明書ファイルに中間証明書を連結してもらう。
5. -k は調査用にとどめる
curl -k https://example.com/これは検証そのものを無効にする。
原因の切り分けには使えるが、スクリプトや CI にそのまま残すと中間者攻撃を検知できなくなる。
恒久対応は 2〜4 のいずれかで行う。