Mensaje de error
state=error: certificate verify failed (unable to get local issuer certificate)
También se muestra como
- 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)
El mensaje completo es «SSL_connect returned=1 errno=0 peeraddr=<ip>:<port> state=error: certificate verify failed (unable to get local issuer certificate)»; en nuestras pruebas, peeraddr aparecía con la gema openssl de la 3.0.1 a la 4.0.2. Faraday lo envuelve como Faraday::SSLError con el mismo mensaje; las bibliotecas que llaman directamente a Net::HTTP dejan pasar OpenSSL::SSL::SSLError tal cual.
Ruby openssl (Net::HTTP, Faraday, HTTParty, RubyGems) — OpenSSL::SSL::SSLError from SSL_connect
Qué significa
La interfaz de OpenSSL para Ruby (en la que se basan Net::HTTP y, por tanto, la mayoría de los clientes HTTP de Ruby) no encontró el emisor de la cadena de certificados del servidor entre las CA que carga. El texto entre paréntesis es el motivo de verificación de OpenSSL; todo lo anterior describe en qué punto de SSL_connect se produjo el fallo. Normalmente, la CA es privada o está detrás de un proxy, o este Ruby consulta un bundle de CA que no la contiene.
Por qué ocurre
Una CA privada o un proxy que inspecciona TLS
frecuenteLa cadena termina en una raíz que no está en el almacén de OpenSSL que usa Ruby.
Un Ruby compilado con su propio OpenSSL (rbenv, asdf, rvm en macOS)
frecuenteEstas instalaciones de Ruby usan el bundle de CA del OpenSSL de Homebrew o del OpenSSL incluido, no el llavero de macOS; las raíces que el departamento de TI añade al llavero no se aplican.
El servidor no envía su certificado intermedio
ocasionalOpenSSL no descarga los intermedios que faltan, así que un servidor que solo envía el certificado hoja falla aquí aunque los navegadores lo acepten.
RubyInstaller en Windows
ocasionalRuby en Windows incluye su propio bundle de CA; las raíces corporativas del almacén de Windows no forman parte de él automáticamente.
Cómo solucionarlo
- 1.
Instalar la raíz donde la busca el OpenSSL de Ruby
OpenSSL::X509::DEFAULT_CERT_FILE y DEFAULT_CERT_DIR muestran las rutas del archivo y del directorio; en Debian y Ubuntu, update-ca-certificates actualiza los certificados que contienen.
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.
Establecer SSL_CERT_FILE para el proceso
OpenSSL respeta SSL_CERT_FILE y SSL_CERT_DIR; haz que apunten a un bundle que contenga las raíces públicas y tu 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.
Dar a un cliente su propio almacén
Un OpenSSL::X509::Store con set_default_paths más add_file conserva las raíces públicas y añade la CA privada, con verificación completa.
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.
Faraday y otros envoltorios: pasar ca_file o cert_store
La mayoría de las bibliotecas HTTP de Ruby aceptan opciones ssl que se corresponden con ca_file, ca_path o cert_store de Net::HTTP.
ruby conn = Faraday.new("https://api.example.com", ssl: { ca_file: "/etc/ssl/private-ca/corp-root-ca.pem" })
Errores relacionados
state=error: certificate verify failed (self-signed certificate in certificate…Ruby openssl (Net::HTTP, Faraday, RubyGems)Could not verify the SSL certificate for https://gems.example.com/.Bundlercurl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)