Skip to content

Commit

Permalink
- added helper scripts to dianose and resolve the SSL issues
Browse files Browse the repository at this point in the history
- added docs to help explain and safe the user time and research

Fixes boltops-tools#89

Signed-off-by: Aaron Lippold <[email protected]>
  • Loading branch information
aaronlippold committed Sep 28, 2019
1 parent f5b7bcc commit a89bde1
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docs/.ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.5.3
2.6.0
41 changes: 41 additions & 0 deletions docs/_docs/ssl_errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
Title: SSL Errors
# nav_order:
---

UFO uses the AWS Ruby SDK and the underlying default SSL certificate chain configured in your active Ruby and
OpenSSL to communicate to your AWS environment. This means that you _must correctly configure_ your Ruby and OpenSSL to have all the needed ROOT certificates for UFO to be able to communicate to AWS - _especially_ if you are behind a proxy or a corporate SSL-Proxy.

If you are behind a corporate SSL proxy and you have not updated system, OpenSSL and Ruby certificate chains to include the needed corporate root certificates, you will see errors, such as:

```
Seahorse::Client::NetworkingError: SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)
~/.rbenv/versions/2.6.0/lib/ruby/2.6.0/net/protocol.rb:44:in `connect_nonblock'
~/.rbenv/versions/2.6.0/lib/ruby/2.6.0/net/protocol.rb:44:in `ssl_socket_connect'
~/.rbenv/versions/2.6.0/lib/ruby/2.6.0/net/http.rb:996:in `connect'
~/.rbenv/versions/2.6.0/lib/ruby/2.6.0/net/http.rb:930:in `do_start'
~/.rbenv/versions/2.6.0/lib/ruby/2.6.0/net/http.rb:925:in `start'
```

## Helper Scripts

The `docs/utils` directory has a few scripts that should be able to help you resolve these issues and track down which certs are giving you issues.

- `ssl-doctor.rb` if from the very useful examples at <https://github.com/mislav/ssl-tools>, and it can help you find the missing ROOT cert in your certificate chain and give suggestion on getting OpenSSL working correctly.
- `update-cert-chains.sh` will help you update your Ruby and OpenSSL chains by adding in the missing ROOT cert and also pulling in the OSX System Root to your rbenv environment.
- `test-aws-api-access.rb` should now return a list of the S3 buckets for the current AWS profile that is active.

## Trouble-shooting

### Update Brew and OpenSSL

- `brew update`
- `brew upgrade openssl`

### Use the Helper Scripts to find the trouble spot

Once you have updated OpenSSL and your `brew` packages, use the helper scripts above to see if you can track down the missing certificate in your certificate chain.

The `update-cert-chain.sh` file was created using the suggestions from <https://gemfury.com/help/could-not-verify-ssl-certificate/>. Please review the information at <https://gemfury.com/help/could-not-verify-ssl-certificate/> if the `Helper Scripts` above do not fully resolve your issue.

The `test-aws-api-access.rb` uses examples from the <https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/quick-start-guide.html> for using and configuring the Ruby AWS SDK on your system.
89 changes: 89 additions & 0 deletions docs/utils/ssl-doctor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Usage: ruby doctor.rb [HOST=status.github.com[:PORT=443]]
# see: https://github.com/mislav/ssl-tools
require 'rbconfig'
require 'net/https'

if ARGV[0] =~ /^[^-]/
host, port = ARGV[0].split(':', 2)
else
host = 'status.github.com'
end
port ||= 443

ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
ruby_version = RUBY_VERSION
if patch = RbConfig::CONFIG['PATCHLEVEL']
ruby_version += "-p#{patch}"
end
puts "%s (%s)" % [ruby, ruby_version]

openssl_dir = OpenSSL::X509::DEFAULT_CERT_AREA
mac_openssl = '/System/Library/OpenSSL' == openssl_dir
puts "%s: %s" % [OpenSSL::OPENSSL_VERSION, openssl_dir]
[OpenSSL::X509::DEFAULT_CERT_DIR_ENV, OpenSSL::X509::DEFAULT_CERT_FILE_ENV].each do |key|
puts "%s=%s" % [key, ENV[key].to_s.inspect]
end

ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
ca_path = (ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR).chomp('/')

puts "\nHEAD https://#{host}:#{port}"
http = Net::HTTP.new(host, port)
http.use_ssl = true

# Explicitly setting cert_store like this is not needed in most cases but it
# seems necessary in edge cases such as when using `verify_callback` in some
# combination of Ruby + OpenSSL versions.
http.cert_store = OpenSSL::X509::Store.new
http.cert_store.set_default_paths

http.verify_mode = OpenSSL::SSL::VERIFY_PEER
failed_cert = failed_cert_reason = nil

if mac_openssl
warn "warning: will not be able show failed certificate info on OS X's OpenSSL"
# This drives me absolutely nuts. It seems that on Rubies compiled against OS X's
# system OpenSSL, the mere fact of defining a `verify_callback` makes the
# cert verification fail for requests that would otherwise be successful.
else
http.verify_callback = lambda { |verify_ok, store_context|
if !verify_ok
failed_cert = store_context.current_cert
failed_cert_reason = "%d: %s" % [ store_context.error, store_context.error_string ]
end
verify_ok
}
end

user_agent = "net/http #{ruby_version}"
req = Net::HTTP::Head.new('/', 'user-agent' => user_agent)

begin
res = http.start { http.request(req) }
abort res.inspect if res.code.to_i >= 500
puts "OK"
rescue Errno::ECONNREFUSED
puts "Error: connection refused"
exit 1
rescue OpenSSL::SSL::SSLError => e
puts "#{e.class}: #{e.message}"

if failed_cert
puts "\nThe server presented a certificate that could not be verified:"
puts " subject: #{failed_cert.subject}"
puts " issuer: #{failed_cert.issuer}"
puts " error code %s" % failed_cert_reason
end

ca_file_missing = !File.exist?(ca_file) && !mac_openssl
ca_path_empty = Dir["#{ca_path}/*"].empty?

if ca_file_missing || ca_path_empty
puts "\nPossible causes:"
puts " `%s' does not exist" % ca_file if ca_file_missing
puts " `%s/' is empty" % ca_path if ca_path_empty
end

exit 1
end

11 changes: 11 additions & 0 deletions docs/utils/test-aws-api-access.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# usage 'ruby s3-cert-chain-test.rb'
# see: https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/quick-start-guide.html

require 'aws-sdk-s3' # v2: require 'aws-sdk'
#Aws.use_bundled_cert!

s3 = Aws::S3::Resource.new(region: 'us-east-1')

s3.buckets.limit(50).each do |b|
puts "#{b.name}"
end
11 changes: 11 additions & 0 deletions docs/utils/update-cert-chains.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

cert_file=$(ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE' 2>/dev/null)
echo 'What is the uri to your organizations root certificate chain?'
read -p 'org_root_chain: ' org_root_chain
echo "$org_root_chain"
curl "$org_root_chain" -o org_chain.txt
cat org_chain.txt >> "$cert_file"
mkdir -p "${cert_file%/*}"
security find-certificate -a -p /Library/Keychains/System.keychain > "$cert_file"
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$cert_file"

0 comments on commit a89bde1

Please sign in to comment.