本文へスキップ
ecdsa.com
Ruby openssl (Net::HTTP, Faraday, HTTParty, RubyGems)Ruby

エラーメッセージ

state=error: certificate verify failed (unable to get local issuer certificate)

別の表記

  • OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=127.0.0.1:8443 state=error: certificate verify failed (unable to get local issuer certificate)

メッセージ全文は「SSL_connect returned=1 errno=0 peeraddr=<ip>:<port> state=error: certificate verify failed (unable to get local issuer certificate)」です。ecdsa.com のテストでは、openssl gem 3.0.1〜4.0.2 で peeraddr が含まれていました。Faraday はこれを同じメッセージの Faraday::SSLError としてラップし、Net::HTTP を直接呼び出すライブラリは OpenSSL::SSL::SSLError をそのまま送出します。

Ruby openssl (Net::HTTP, Faraday, HTTParty, RubyGems) — OpenSSL::SSL::SSLError from SSL_connect

このエラーの意味

Ruby の OpenSSL バインディング(Net::HTTP が使っており、そのためほとんどの Ruby の HTTP クライアントも使っています)は、読み込んだ CA の中に、サーバーの証明書チェーンの発行者を見つけられませんでした。括弧内のテキストは OpenSSL が示す検証失敗の理由で、それより前の部分は SSL_connect のどこで失敗が起きたかを示しています。通常は、CA がプライベートなものであるか、プロキシが間に入っているか、あるいはこの Ruby が参照している CA バンドルにその CA が含まれていないかのいずれかです。

発生する理由

修正方法

  1. 1.

    Ruby の OpenSSL が参照する場所にルートをインストールする

    OpenSSL::X509::DEFAULT_CERT_FILE と DEFAULT_CERT_DIR でパスを確認できます。Debian と Ubuntu では、update-ca-certificates でこれらを更新します。

    bash
    # Ruby's OpenSSL reads the system bundle (see its default paths)
    ruby -ropenssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE, OpenSSL::X509::DEFAULT_CERT_DIR'
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt && sudo update-ca-certificates
  2. 2.

    プロセスに SSL_CERT_FILE を設定する

    OpenSSL は SSL_CERT_FILE と SSL_CERT_DIR に従います。公開ルートと自社の CA を含むバンドルを指定してください。

    bash
    # One process / environment: point OpenSSL at a bundle with the needed roots
    export SSL_CERT_FILE=/etc/ssl/private-ca/corp-ca-bundle.pem
    ruby app.rb
  3. 3.

    1 つのクライアントに専用のストアを持たせる

    OpenSSL::X509::Store で set_default_paths と add_file を組み合わせると、公開ルートを残したままプライベート CA を追加でき、検証も完全に行われます。

    ruby
    # One client: default roots plus a private CA
    store = OpenSSL::X509::Store.new
    store.set_default_paths
    store.add_file("/etc/ssl/private-ca/corp-root-ca.pem")
    
    http = Net::HTTP.new("api.example.com", 443)
    http.use_ssl = true
    http.cert_store = store
  4. 4.

    Faraday などのラッパー:ca_file または cert_store を渡す

    ほとんどの Ruby の HTTP ライブラリは、Net::HTTP の ca_file、ca_path、cert_store に対応する ssl オプションを受け付けます。

    ruby
    conn = Faraday.new("https://api.example.com", ssl: { ca_file: "/etc/ssl/private-ca/corp-root-ca.pem" })

関連するエラー

署名エラーデータベースをすべて見る