puppetlabs / r10k

Smarter Puppet deployment
Other
799 stars 354 forks source link

SSL certificate error on Windows 7 #454

Closed bdruth closed 3 years ago

bdruth commented 9 years ago

Good afternoon -

I'm trying to verify an automation setup that I developed on Win 2012 R2 to work on Windows 7 SP1. I have all updates installed on Win7 SP1 and my pre-r10k script installs the GeoTrust Global CA (since that was missing from the root store on Win 2012 R2). Despite this, and despite using a version of Rubygems (2.4.7) newer than the same issue/error documented here, I'm still having no luck trying to get r10k to install modules from Forge.

INFO     -> Updating module C:/Users/IEUser/Downloads/modules/chocolatey
ERROR    -> SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
INFO     -> Updating module C:/Users/IEUser/Downloads/modules/powershell
ERROR    -> SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
INFO     -> Updating module C:/Users/IEUser/Downloads/modules/windows
ERROR    -> SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
INFO     -> Updating module C:/Users/IEUser/Downloads/modules/stdlib
ERROR    -> SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
INFO     -> Updating module C:/Users/IEUser/Downloads/modules/registry
ERROR    -> SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

Unfortunately, I have no idea what URL it's actually trying to access - so there may be yet another root cert missing somewhere, I just can't figure out which.

Thanks!

bdruth commented 9 years ago

This is the extent of my Puppetfile:

mod 'chocolatey/chocolatey'
mod 'puppetlabs/powershell'
mod 'counsyl/windows'
mod 'puppetlabs/stdlib'
mod 'puppetlabs/registry'

There's nothing else and no other setup re: r10k and this is on a fresh VM snapshot.

bdruth commented 9 years ago

I've added some debugging to puppet_forge/connection.rb and (seemingly) am able to confirm that the failing connection is to https://forgeapi.puppetlabs.com ... however, it uses the same CA as the main forge URL, so GeoTrust, and those certs are installed.

adrienthebo commented 9 years ago

This might be due to Windows not properly initializing the SSL cert paths; try applying this patch to connection.rb - it should explicitly set up the paths as needed.

From 0e34f7031218d0a5e95fc5c4df87450935be0dff Mon Sep 17 00:00:00 2001
From: Adrien Thebo <git@somethingsinistral.net>
Date: Tue, 16 Jun 2015 14:13:50 -0700
Subject: [PATCH] Setup default SSL cert store paths when reaching forge via
 HTTPS

---
 lib/shared/puppet_forge/connection.rb | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/lib/shared/puppet_forge/connection.rb b/lib/shared/puppet_forge/connection.rb
index ac402c0..ce5cb24 100644
--- a/lib/shared/puppet_forge/connection.rb
+++ b/lib/shared/puppet_forge/connection.rb
@@ -2,6 +2,7 @@ require 'shared/puppet_forge/version'

 require 'faraday'
 require 'faraday_middleware'
+require 'openssl'

 module PuppetForge
   # Provide a common mixin for adding a HTTP connection to classes.
@@ -51,12 +52,32 @@ module PuppetForge
         options[:headers][:authorization] = token
       end

-      Faraday.new(url, options) do |builder|
-        builder.response(:json, :content_type => /\bjson$/)
-        builder.response(:raise_error)
+      builder = Faraday::RackBuilder.new do |b|
+        b.response(:json, :content_type => /\bjson$/)
+        b.response(:raise_error)
+        b.adapter(*adapter_args)
+      end
+
+      options[:builder] = builder

-        builder.adapter(*adapter_args)
+      if url.match(/^https/)
+        conn = make_https_connection(url, options)
+      else
+        conn = make_http_connection(url, options)
       end
+
+      conn
+    end
+
+    def make_http_connection(url, options)
+      Faraday.new(url, options)
+    end
+
+    def make_https_connection(url, options)
+      cert_store = OpenSSL::X509::Store.new
+      cert_store.set_default_paths
+
+      Faraday.new(url, options.merge(:ssl => {:cert_store => cert_store}))
     end
   end
 end
-- 
2.4.2
adrienthebo commented 9 years ago

It's been about a week since this issue has seen an update, are you still affected by this?

adrienthebo commented 9 years ago

It's been about two weeks since this issue has seen any activity; if I don't hear anything else on this issue within a week or two I'm going to assume that this issue was resolved.

adrienthebo commented 9 years ago

Since I haven't heard back on this issue I'm going to assume this was resolved; if this is still an issue please comment on this ticket and we can continue working on this. Thanks!

cavaliercoder commented 9 years ago

Damn... I'm experiencing this issue. Had the same issue with puppet module install until installing the GeoTrust Cert (on Windows Server 2012 R2 +no updates), but r10k is still no bingo.

ericsysmin commented 9 years ago

Yep, after making the changes I still have the issue as well.

C:\>gem list
...
r10k (2.0.3)
...

connection.rb is as follows:

require 'shared/puppet_forge/version'
require 'shared/puppet_forge/connection/connection_failure'

require 'faraday'
require 'faraday_middleware'

module PuppetForge
  # Provide a common mixin for adding a HTTP connection to classes.
  #
  # This module provides a common method for creating HTTP connections as well
  # as reusing a single connection object between multiple classes. Including
  # classes can invoke #conn to get a reasonably configured HTTP connection.
  # Connection objects can be passed with the #conn= method.
  #
  # @example
  #   class HTTPThing
  #     include PuppetForge::Connection
  #   end
  #   thing = HTTPThing.new
  #   thing.conn = thing.make_connection('https://non-standard-forge.site')
  #
  # @api private
  module Connection

    attr_writer :conn

    USER_AGENT = "PuppetForge/#{PuppetForge::VERSION} Faraday/#{Faraday::VERSION} Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"

    def self.authorization=(token)
      @authorization = token
    end

    def self.authorization
      @authorization
    end

    # @return [Faraday::Connection] An existing Faraday connection if one was
    #   already set, otherwise a new Faraday connection.
    def conn
      @conn ||= make_connection('https://forgeapi.puppetlabs.com')
    end

    # Generate a new Faraday connection for the given URL.
    #
    # @param url [String] the base URL for this connection
    # @return [Faraday::Connection]
    def make_connection(url, adapter_args = nil)
      adapter_args ||= [Faraday.default_adapter]
      options = { :headers => { :user_agent => USER_AGENT }}

      if token = PuppetForge::Connection.authorization
        options[:headers][:authorization] = token
      end

      builder = Faraday::RackBuilder.new do |b|
        b.response(:json, :content_type => /\bjson$/)
        b.response(:raise_error)
        b.adapter(*adapter_args)
      end

      options[:builder] = builder

      if url.match(/^https/)
        conn = make_https_connection(url, options)
      else
        conn = make_http_connection(url, options)
      end

      conn
    end

    def make_http_connection(url, options)
      Faraday.new(url, options)
    end

    def make_https_connection(url, options)
      cert_store = OpenSSL::X509::Store.new
      cert_store.set_default_paths

      Faraday.new(url, options.merge(:ssl => {:cert_store => cert_store}))
    end
  end
end
cavaliercoder commented 9 years ago

I ran Windows update until all updates were installed (including root cert updates) on Server 2012 R2 x64... issue persists :( r10k v2.0.3

roanosullivan commented 9 years ago

I'm having similar issues, also r10k v2.0.3 and Windows 2012 R2. Can this Issue be re-opened?

c33s commented 8 years ago

same problem here. my very insecure workaround was to add :ssl => {:verify => false} to the Faraday.new() options

full file (lib/puppet_forge/connection.rb):

require 'puppet_forge/connection/connection_failure'

require 'faraday'
require 'faraday_middleware'
require 'puppet_forge/middleware/symbolify_json'

module PuppetForge
  # Provide a common mixin for adding a HTTP connection to classes.
  #
  # This module provides a common method for creating HTTP connections as well
  # as reusing a single connection object between multiple classes. Including
  # classes can invoke #conn to get a reasonably configured HTTP connection.
  # Connection objects can be passed with the #conn= method.
  #
  # @example
  #   class HTTPThing
  #     include PuppetForge::Connection
  #   end
  #   thing = HTTPThing.new
  #   thing.conn = thing.make_connection('https://non-standard-forge.site')
  #
  # @api private
  module Connection

    attr_writer :conn

    USER_AGENT = "#{PuppetForge.user_agent} PuppetForge.gem/#{PuppetForge::VERSION} Faraday/#{Faraday::VERSION} Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})".strip

    def self.authorization=(token)
      @authorization = token
    end

    def self.authorization
      @authorization
    end

    # @return [Faraday::Connection] An existing Faraday connection if one was
    #   already set, otherwise a new Faraday connection.
    def conn
      @conn ||= default_connection
    end

    def default_connection

      begin
        # Use Typhoeus if available.
        Gem::Specification.find_by_name('typhoeus', '~> 0.6')
        require 'typhoeus/adapters/faraday'
        adapter = :typhoeus
      rescue Gem::LoadError
        adapter = Faraday.default_adapter
      end

      make_connection(PuppetForge.host, [adapter])
    end
    module_function :default_connection

    # Generate a new Faraday connection for the given URL.
    #
    # @param url [String] the base URL for this connection
    # @return [Faraday::Connection]
    def make_connection(url, adapter_args = nil, opts = {})
      adapter_args ||= [Faraday.default_adapter]
      options = 
      { :headers => { :user_agent => USER_AGENT }, :ssl => {:verify => false} }.merge(opts)

      if token = PuppetForge::Connection.authorization
        options[:headers][:authorization] = token
      end

      Faraday.new(url, options) do |builder|
        builder.use PuppetForge::Middleware::SymbolifyJson
        builder.response(:json, :content_type => /\bjson$/)
        builder.response(:raise_error)
        builder.use(:connection_failure)

        builder.adapter(*adapter_args)
      end
    end
    module_function :make_connection
  end
end
benpriestman commented 8 years ago

I've come across similar issues on Windows. I don't have this problem, if I install r10k in the ruby install that is bundled with puppet's installable packages. I do have this problem, if I try and use ruby from http://rubyinstaller.org/ with puppet and the puppet module tool installed as gems.

My conclusion was that this is a symptom of a much deeper problem: that stock ruby uses openssl, which uses uses hard-coded paths for its default certificate store, which are not appropriate for Windows. The best summary I've found of this is the comments made by luislavena in https://github.com/oneclick/rubyinstaller/issues/249. Also see https://groups.google.com/forum/#!searchin/rubyinstaller/ssl/rubyinstaller/DVIDvs7xKC0/Z22dY49LFnEJ.

My solution was to use a provisioning script to write out a set of default certs to a file and have %SSL_CERT_FILE% hold the path to this file.

Is this the same issue that the other posting here are facing, or is this something else?

adrienthebo commented 8 years ago

@malaikah interesting - thanks for chasing this down!

benpriestman commented 8 years ago

If you're using Git For Windows (or any form of git, I suppose), you can also borrow the cacert bundle that uses. git config http.sslcainfo Will tell you where it is. Comparing a few different installs, this seems to sometimes be a relative, sometimes an absolute path, so you might need to do some additional jiggery-pokery to construct a reliable value.

adrienthebo commented 8 years ago

On your system, what is that path? Depending on how complex it is it might be possible to hardcode that path into r10k as an additional location for CA certs on Windows.

benpriestman commented 8 years ago

C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt. That path is a pretty likely bet, but it depends on what git client you have installed, so hard-coding it seems like a bad idea.

sfhardman commented 8 years ago

For Git for Windows you can workaround as follows:

echo "export SSL_CERT_FILE=/mingw64/ssl/certs/ca-bundle.crt" >> ~/.bash_profile
source ~/.bash_profile
mattdanskey commented 7 years ago

Thanks for giving the pieces needed to figure this out!

I've done the following workaround for powershell (with r10k installed using the ruby from RubyInstaller): 1) Install git 2) Set the SSL_CERT_FILE environment variable to the path to ca-bundle.crt that came with git. This can be done manually or by running the following line in powershell (double check the path is correct for you first):

[Environment]::SetEnvironmentVariable("SSL_CERT_FILE", "C:\Program Files\Git\mingw64\ssl\certs\ca-bundle.crt", "Machine")

3) Restart powershell

glennsarti commented 6 years ago

I created a quick PS script to download a complete ca cert bundle and configure SSL correctly for me

https://github.com/glennsarti/dev-tools/blob/master/RubyCerts.ps1

dietmarb01 commented 5 years ago

I have the impression that it has to do with "path translation" between the compile environment and a "real" Windows machine.

On WS2010, I traced ruby.exe with ProcMon and issued the command r10k puppetfile install with the source set to a company-internal SSL secured repository.

The trace showed unsuccessful attempts to access the certifiate store at C:\programfiles64folder\PuppetLabs\Puppet\puppet\ssl\cert.pem instead of
C:\Program Files\Puppet Labs\Puppet\puppet\ssl\cert.pem to which I had previously added my company's root CA for that repository.

I then re-created the failing path using symlinks (yeah, now also on Windows:-) and it worked!

Grep'ing over the Puppet installation folder showed quite a number of occurrences of this non-Windows path, e.g. in ./Puppet/puppet/bin/curl-config which appears to be a shell script that popped out of the build process to get access to build variables. Maybe there is some Ruby-internal path translation(?) at other places, but here it obviously does not kick in.

Now the many posts about specifying the path to the CA bundle with an environment variable do actually make more sense to me. I defined set SSL_CERT_FILE=C:\Program Files\Puppet Labs\Puppet\puppet\ssl\cert.pem without(!) any quotes, removed the symlinks and the r10k command still worked:-)

Hurrah!!

Anyone inclined to fix it at the source?

github-actions[bot] commented 3 years ago

This issue has been marked stale because it has had no activity for 60 days. The Puppet Team is actively prioritizing existing bugs and new features, if this issue is still important to you please comment and we will add this to our backlog to complete. Otherwise, it will be closed in 7 days.