Getting "SSL_connect returned=1 errno=0 state=error: certificate verify failed" when connecting to S3

Getting "SSL_connect returned=1 errno=0 state=error: certificate verify failed" when connecting to S3

我一直在尝试将照片上传到我的 AWS 存储桶,但 运行 进入标题中提到的错误。我知道这很可能与我的 OpenSSL 证书有关,但到目前为止我尝试过的任何建议解决方案都失败了。

我 运行 在 ruby 2.3.1、Rails 4.1.8、aws-sdk-core 2.3.4 和载波 0.11.0 OSX Yosemite.

我也尝试了在这个类似问题上找到的所有可用方法,以及其他方法(这个与 Windows 一起使用):https://github.com/aws/aws-sdk-core-ruby/issues/166#issuecomment-111603660

这是我的一些文件:

carrierwave.rb

CarrierWave.configure do |config|                     # required
  config.aws_credentials = {
    access_key_id:     Rails.application.secrets.aws_access_key_id, # required
    secret_access_key: Rails.application.secrets.aws_access_key,    # required
    region:            'eu-west-2'                  # optional, defaults to 'us-east-1'
  }

  config.aws_bucket = Rails.application.secrets.aws_bucket                        # required
  config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {}
end

avatar_uploader.rb

class AvatarUploader < CarrierWave::Uploader::Base

  storage :aws

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end

编辑(更多信息):

stack trace:

    Seahorse::Client::NetworkingError - SSL_connect returned=1 errno=0 state=error: certificate verify failed:
  /Users/stevenharlow/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:933:in `connect_nonblock'
  /Users/stevenharlow/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:933:in `connect'
  /Users/stevenharlow/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:863:in `do_start'
  /Users/stevenharlow/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:858:in `start'
  /Users/stevenharlow/.rbenv/versions/2.3.1/lib/ruby/2.3.0/delegate.rb:83:in `method_missing'
  aws-sdk-core (2.3.4) lib/seahorse/client/net_http/connection_pool.rb:292:in `start_session'
  aws-sdk-core (2.3.4) lib/seahorse/client/net_http/connection_pool.rb:104:in `session_for'
  aws-sdk-core (2.3.4) lib/seahorse/client/net_http/handler.rb:109:in `session'

尝试过的解决方案:

这是

的结果
CONNECTED(00000003)
depth=1 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Baltimore CA-2 G2
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=Washington/L=Seattle/O=Amazon.com Inc./CN=*.s3-us-west-2.amazonaws.com
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Baltimore CA-2 G2
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Baltimore CA-2 G2
   i:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root
---

<certificate info>

No client certificate CA names sent
---
SSL handshake has read 2703 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES128-SHA
    Session-ID: <session-id>
    Session-ID-ctx: 
    Master-Key: <master-key>
    Key-Arg   : None
    Start Time: 1463697130
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

尝试使用这些 gems 和这个 setup 代替:

Gemfile

gem "carrierwave", "~> 0.11.0"
gem 'carrierwave-aws', "~> 1.0.1"
gem "unf", "~> 0.1.4"

config/carrierwave.rb

require 'carrierwave'
require 'carrierwave/orm/activerecord'

  CarrierWave.configure do |config|
     config.storage    =  :aws                  # required
     config.aws_bucket =  Rails.application.secrets.aws_bucket       # required
     config.aws_acl    =  :public_read
     config.aws_credentials = {
         access_key_id:      Rails.application.secrets.aws_access_key_id,       # required
         secret_access_key:  Rails.application.secrets.aws_access_key     # required
     }
     config.aws_attributes = { 
         cache_control: 'max-age=31536000',
         expires: 1.year.from_now.httpdate
     }
  end

*_uploader.rb

storage :aws

def store_dir
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

# Use Heroku's temp folder for uploads
def cache_dir
  "#{Rails.root}/tmp/uploads"
end

您的 Ruby 代码、AWS SDK 等都很好。这不是 Ruby 或 SDK 问题。您最初描述的错误消息和您后来的 OpenSSL 连接日志 post 都指向问题的根本原因:缺少根证书 and/or 在 OpenSSL 框架中配置不正确的 CA 证书包。进一步的线索是相同的代码可用于生产。不是代码。

原始错误消息本身指向您指出的 OpenSSL 证书验证错误。堆栈跟踪还在 2.3.1/lib/ruby/2.3.0/net/http.rb 中显示 Ruby 内部库错误。这是利用 OpenSSL 框架的核心网络库。

openssl s_client 连接日志更清楚地显示了确切的错误编号和消息:

depth=1 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Baltimore CA-2 G2
verify error:num=20:unable to get local issuer certificate

在您通过 openssl s-client 测试在 DigiCert Baltimore CA-2 CA 上获得 Verify return code: 0 (ok) 之前,您的代码将无法工作

DigiCert Baltimore CA-2 CA 证书不存在或未被该计算机上的 OpenSSL 设置正确引用。这是损坏或不完整的 OpenSSL 安装中非常常见的问题。您需要下载该证书,转换为 PEM 格式,将其保存在 OpenSSL 证书文件夹中的 ca-certificate.crt 文件中,然后在您的配置或环境变量 SSL_CERT_FILE 中引用该文件。

你可以看到一个很好的解决你的根本问题的方法here

注意:要进一步确认此解决方案,您应该 运行 在您的生产服务器上进行 openssl s_client 测试。您应该看到它可以毫无问题地验证同一个 CA。检查那里的 OpenSSL 配置和 CA 证书捆绑配置,看看为什么您的生产环境和开发环境之间存在差异。

在@RodrigoM 的调查帮助和你的问题更新的帮助下,一切都开始变得有意义了。实际上有两个不同的问题导致了您观察到的错误:

  • 您的 openssl 安装没有在其受信任的证书存储中验证 Amazon 服务器所需的证书链...
  • ...这是应该通过将 Aws.use_bundled_cert! 添加到初始值设定项来解决的确切情况,according to the docs. But in this case it does not work because even though this command instructs the ruby openssl library to add various CA certs to the trusted store from the aws-sdk-core gem's CA bundle file, the file also does not contain the proper CA certificate as it is itself almost 2 years old and outdated. The intermediate CA cert CN=DigiCert Baltimore CA-2 G2 已于 2015 年 12 月 8 日发布,所以难怪 CA 捆绑文件确实如此不包含它。

现在,您有两个选择:

  • 您可以尝试安装这个中间CA证书,可能包括根CA证书(CN=Baltimore CyberTrust Root), to your openssl trusted certs store. This should make the s_client command work. But you might still run into issues using these trusted certs from ruby code. For concrete steps for making it work under ruby on OSX, refer to the Solution section of .

  • 此外,由于您使用的是分叉的 aws-sdk-ruby gem 存储库,您也可以 更新 ca-bundle.crt file in your repo 通过自己添加中间 CA 证书(根 CA 证书似乎已经存在于捆绑包中)。为此,您需要执行以下操作:

    • DigicertCA certificates 的官方页面下载中间 CA 证书(您也可以使用上面的直接 link,但是为了严格遵守安全规则,您还应该检查指纹)
    • 将其转换为 PEM 格式(以 DER 格式下载)并使用以下 openssl 命令将其添加到证书包中:

      openssl x509 -in DigiCertBaltimoreCA-2G2.crt -inform DER >> ca-bundle.crt
      

      在 运行 此命令之后,您的 ca-bundle.crt 应该在文件末尾包含中间 CA 证书。

    • 现在只需将这个更新的捆绑文件推送到您的存储库,Aws.use_bundled_cert! 应该开始工作!

    • 如果你关心的话,也许最好的办法是在 aws-sdk-ruby gem 开始一个 github 问题,这样他们也可以更新他们的 repo 中的证书包......

此问题可能是由于证书无效。当您调用 URL(API)

您可以先交叉验证证书。通过输入命令

openssl s_client -connect <url without https>:443

如果您在证书中发现任何问题。然后更新证书。证书管理器可以解决这个问题。