はじめに (対象読者・この記事でわかること)

本記事は、サーバー管理者・DevOps エンジニア・Web 開発者など、curl を利用して外部 API や内部サービスと通信する際に SSL 証明書の検証エラーに悩んでいる方を対象としています。
この記事を読むことで、以下のことが理解・実践できるようになります。

  • curl が証明書チェックに失敗する典型的なシナリオとその根本原因
  • ローカル環境・CI/CD パイプライン・本番サーバーそれぞれで有効な対処法
  • --cacert--capath--insecure などオプションの正しい使い分けと、システム全体の CA バンドル設定方法

背景として、近年のクラウド環境やコンテナ化の普及に伴い、証明書チェーンが複雑化し「証明書が信頼できない」エラーが頻発しています。そこで、実務で即座に役立つチェックリストと具体例を交えて解説します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • 基本的な Linux コマンド操作(catopensslcurl など)
  • TLS/SSL の概念と、サーバー証明書・中間証明書・ルート証明書の関係性
  • システムの証明書ストア(/etc/ssl/certs/etc/pki/tls/certs)や OpenSSL の設定ファイルの場所

curl の証明書検証とは何か(概要・背景)

curl はデフォルトでシステムにインストールされている CA(Certificate Authority)バンドルを利用し、接続先サーバーが提示する証明書チェーンを検証します。検証が成功すれば通信は暗号化され、かつ相手の正当性が保証されます。逆に、証明書が信頼できない有効期限が切れているホスト名が一致しない といった問題があると、curl はエラーを返し接続を中止します。

この挙動はセキュリティ上重要ですが、開発・テスト環境では自己署名証明書や社内 CA が使われることが多く、システムの CA バンドルにそれらが含まれていないケースが頻発します。その結果、curl https://example.com が以下のようなエラーを出すことがあります。

curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/libcurl/c/libcurl-errors.html

つまり、「curl が証明書チェックできない」 という状態は、「CA バンドルの設定が不適切」 または 「サーバー側の証明書チェーンが不完全」 が原因です。本章では、こうした原因を体系的に整理し、対処の方向性を示します。

証明書チェックが失敗する原因と対処法(具体的な手順や実装方法)

本セクションでは、実務で遭遇しやすいケースを想定し、順序立ててトラブルシューティングを行う手順を解説します。各ステップでは実際にターミナルで入力するコマンド例や設定ファイルの記述例を示します。

ステップ 1 ‑ 環境の確認

まずは現在の curl バージョンと、使用している CA バンドルの場所を把握します。

Bash
# curl のバージョンとビルドオプションを確認 curl -V # 使用中の CA バンドルパスを取得(OpenSSL がリンクしている場合) openssl version -d

curl -V の出力例:

curl 7.88.1 (x86_64-pc-linux-gnu) libcurl/7.88.1 OpenSSL/1.1.1t zlib/1.2.13
Release-Date: 2023-10-12
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL TLS-SRP

ここで OpenSSL/ のバージョンが表示されていることを確認し、次に openssl version -d でデフォルトの設定ディレクトリ(例: /usr/lib/ssl)を確認します。

ステップ 2 ‑ CA 証明書の設定

2‑1. システム CA バンドルに社内CA を追加

自己署名証明書や社内 CA の PEM ファイル(例: mycorp-ca.pem)がある場合、システムの CA バンドルに追記します。

Bash
# 例: Debian/Ubuntu 系の場合 sudo cp mycorp-ca.pem /usr/local/share/ca-certificates/ sudo update-ca-certificates

CentOS/RHEL 系では次のようにします。

Bash
sudo cp mycorp-ca.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust extract

2‑2. curl に個別の CA ファイルを指定

環境ごとに CA バンドルを切り替えたくない場合、curl の --cacert オプションで明示的にファイルを指定できます。

Bash
curl --cacert /path/to/mycorp-ca.pem https://internal.example.com

--capath を利用するとディレクトリ単位で証明書を検索させることも可能です。

Bash
curl --capath /etc/ssl/certs https://internal.example.com

ステップ 3 ‑ サーバー側証明書チェーンの確認

サーバー側が中間証明書を正しく返していないと、クライアント側では「証明書が不完全」エラーが出ます。openssl s_client でチェーンを検証します。

Bash
openssl s_client -connect internal.example.com:443 -showcerts

出力の最後に「Verify return code: 0 (ok)」が表示されていればチェーンは正常です。エラーが出た場合はサーバー管理者に中間証明書の設定を依頼しましょう。

ハマった点やエラー解決

発生したエラー 主な原因 解決策
SSL certificate problem: self signed certificate 自己署名証明書が CA バンドルに未登録 --cacert で PEM を指定、またはシステム CA に追加
SSL: no alternative certificate subject name matches target host name サーバー証明書の CN/SAN がリクエストホストと不一致 サーバー側の証明書を再発行、もしくは --resolve で名前解決を偽装
SSL certificate problem: unable to get local issuer certificate 中間証明書がサーバー側で未提供 openssl s_client でチェーン確認し、サーバー設定に ssl_certificate(NGINX)や SSLCertificateChainFile(Apache)を追記
curl: (35) error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure TLS バージョン/暗号スイートの不一致 curl --tlsv1.2 でバージョン固定、またはサーバー側で対応する暗号スイートを有効化

解決策のまとめ

  1. CA バンドルの確認・更新
    - システムに社内 CA を追加
    - update-ca-certificates(Debian系)や update-ca-trust(RHEL系)で即時反映

  2. curl オプションで明示的に証明書を指定
    - --cacert で個別 PEM を指定
    - --capath でディレクトリを指定
    - テスト環境は一時的に --insecure(ただし本番では使用しない)

  3. サーバー側の証明書チェーンを正しく構成
    - 中間証明書を適切に設定
    - openssl s_client でチェーン検証を行う

  4. TLS バージョン・暗号スイートの整合性
    - --tlsv1.2--tls-max を使用して互換性を確保

これらを順に実施すれば、curl が証明書チェックできない問題は大半解消できます。

まとめ

本記事では、curl の証明書検証が失敗する原因と、システム CA バンドルの更新、curl のオプション活用、サーバー側証明書チェーンの検証という三つの観点から対処法を解説しました。

  • 原因①:ローカルに信頼できる CA が無い → 対策update-ca-certificates で追加または --cacert 指定
  • 原因②:サーバーが中間証明書を返さない → 対策openssl s_client でチェーン確認し、サーバー側設定を修正
  • 原因③:TLS バージョンや暗号スイートの不整合 → 対策--tlsv1.2 などでバージョン固定

これにより、開発・ステージング・本番環境すべてで安全に curl を利用できるようになります。今後は、自動化された CI/CD パイプラインでの証明書検証や、Docker コンテナ内部での CA 設定についても取り上げる予定です。

参考資料