繁体   English   中英

连接到 S3 时出现“SSL_connect 返回=1 errno=0 状态=错误:证书验证失败”

[英]Getting “SSL_connect returned=1 errno=0 state=error: certificate verify failed” when connecting to S3

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

我在 OSX Yosemite 上使用 ruby​​ 2.3.1、Rails 4.1.8、aws-sdk-core 2.3.4 和carrierwave 0.11.0 遇到了这个问题。

我已经尝试了在这个类似问题上找到的所有可用内容,以及其他人(这个在 Windows 中): https : //github.com/aws/aws-sdk-core-ruby/issues/166#issuecomment-111603660

这是我的一些文件:

载波

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

头像_上传者.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'

尝试的解决方案:

  • aws.use_bundled_cert!
  • 手动下载证书和参考
  • 我尝试使用 Fog 而不是carrierwave-aws
  • 升级rbenv后尝试重新安装ruby

这是结果

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)

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

  • 您的 openssl 安装没有在其受信任的证书存储中验证 Amazon 服务器所需的证书链...
  • ...这是应该通过添加Aws.use_bundled_cert!解决的确切情况Aws.use_bundled_cert! 根据文档,到初始化程序。 但在这种情况下它不起作用,因为即使此命令指示 ruby​​ openssl 库将各种 CA 证书从aws-sdk-core gem 的CA 捆绑文件添加到受信任的存储,该文件也不包含正确的 CA 证书,如它本身已经快 2 岁了,已经过时了 中间 CA 证书CN=DigiCert Baltimore CA-2 G2已于 2015 年 12 月 8 日发布,所以难怪 CA 捆绑文件不包含它。

现在,您有两个选择:

  • 您可以尝试将此中间 CA 证书(可能包括根 CA 证书( CN=Baltimore CyberTrust Root ))安装到您的 openssl 受信任证书存储中。 这应该使s_client命令工作。 但是您可能仍然会遇到使用来自 ruby​​ 代码的这些可信证书的问题。 有关使其在 OSX 上的 ruby​​ 下工作的具体步骤,请参阅此 SO 问题解决方案部分。

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

    • DigicertCA 证书的官方页面下载中间 CA 证书(您也可以使用上面的直接链接,但要严格遵守安全规则,您还应该检查指纹)
    • 将其转换为 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 问题,以便他们也更新其存储库中的证书包...

你的 Ruby 代码、AWS SDK 等都很好。 这不是 Ruby 或 SDK 问题。 您最初描述的错误消息以及您稍后发布的 OpenSSL 连接日志都指向问题的根本原因: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 中引用该文件。

您可以在此处查看解决根本问题的好方法

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

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

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

openssl s_client -connect <url without https>:443

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

尝试使用这些gems和此设置

文件

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

配置/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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM