Heroku SSL EndPoint -- update cert gives Internal server error - ruby-on-rails

I have a COMODO wildcard SSL certificate that I am trying to replace my old SSL certificate with.
I followed the guides here:
https://devcenter.heroku.com/articles/ssl-endpoint
http://ryan.mcgeary.org/2011/09/16/how-to-add-a-dnsimple-ssl-certificate-to-heroku/
Based off of these, I combined them in to one .pem:
cat STAR_[domain]_com.crt /
EssentialSSLCA_2.crt /
ComodoUTNSGCCA.crt /
UTNAddTrustSGCCA.crt /
AddTrustExternalCARoot.crt >> STAR_[domain]_com-bundle.pem
I then ran:
heroku certs:update STAR_[domain]_com-bundle.pem server.key
and I receive:
Updating SSL Endpoint hyogo-2759.herokussl.com for [heroku-app]... failed
! Internal server error.
! Run `heroku status` to check for known platform issues.
Thanks for your time

So, the skinny is that Heroku's error messages were not very good and/or were not expecting what I gave them, hence the Internal Server Error lacking any specifics.
Heroku got back to me and said they will look in to better error messages for this, but I doubt that will happen.
The solution:
Instead of using the .pem extension, use .crt

Related

How can I build an SSL cert/chain for the Rails pg gem to fix PG::ConnectionBad (SSL SYSCALL error: Connection reset by peer (0x00002746/10054))

My company seems to have recently made some sort of change to the Cisco Endpoint Ark blah blah blah setup on our corporate Windows laptops, and the SSL configuration has killed the ability of one of my programs to talk to a Postgres server hosted at Azure. E.g.,
C:\Users\xxxxx\Projects\stuff_and_things>rails c
Loading production environment (Rails 6.0.3.4)
irb(main):001:0> User.first
Traceback (most recent call last):
1: from (irb):1
PG::ConnectionBad (SSL SYSCALL error: Connection reset by peer (0x00002746/10054))
For 3 years, just specifying sslmode: require has been all I've needed for the pg gem to connect to my database server. I've played with the various sslmode and sslrootcert keywords in my database.yml file, but nothing I've tried has worked, and I'm not getting any hints or error messages about what the problem actually is. Rails can't get far enough in this process to even give me any messages in the log.
From other things I've read, I think I need to build a new, single cert that includes the whole chain of trust in one file, and specify that as root.crt, but I can't find any reference about how to do that. I know Rails is "old and busted" now, so finding any tips about this has been really difficult.
Does anyone have any clearer insight on how I could make the Rails pg gem happy again, or at least any way I could get better error messages from the process?
I recalled that I've had to work around this kind of SSL issue on our laptops before, to get bundler working. Thanks to that pointer to RubyInstaller's SSL FAQ, I got that to work after adding Cisco's Umbrella root and 2048 cert .pem's to the right place, and run a script that comes with RubyInstaller to rehash the cert stack. Notably, I was helped in this process through bundler's error messages, which told me that I needed those particular certs to satisfy the chain of trust.
Weighing in at 240KB, I finally realized that the .pem file that RubyInstaller's script had produced -- which is still keeping bundler happy -- was, in fact, the complete trust chain I needed to make the pg gem happy as well, so, in my database.yml, I've used:
sslmode: verify-full
sslrootcert: C:\Ruby25-x64\ssl\cert.pem
And this seems to have made Rails happy again. Now I have to figure out how I'm going to keep these settings separate between my Windows and Linux machines hitting the same production server...

Rails/Ubuntu: SSLv3 read server certificate B: certificate verify failed

Two days ago, I started seeing this error on the production server of my app (on staging everything works fine). I found a lot of topics here on SO, but none of them solved this issue for me.
Here's the piece of code that's causing this error message:
#client = Savon.client(wsdl: wsdl_url)
##client = Savon.client(wsdl: wsdl_url, ssl_verify_mode: :none) # this sovles the problem, but I don't want to skip the verification
On SO, I also found that a possible solution might be to create an initializer file and put there the following:
require 'open-uri'
require 'net/https'
module Net
class HTTP
alias_method :original_use_ssl=, :use_ssl=
def use_ssl=(flag)
#self.ca_path = Rails.root.join('lib/ca-bundle.crt').to_s
self.ssl_version = :TLSv1_2 # added
self.ca_file = '/etc/ssl/certs/ca-certificates.crt' # the file exists
self.verify_mode = OpenSSL::SSL::VERIFY_PEER
self.original_use_ssl = flag
end
end
end
But this, unfortunately, didn't solve the error. I also tried to reinstall the certificate on the production Ubuntu (14.04) server
sudo apt-get install openssl ca-certificates
The package has been upgraded, but the error is unfortunately still here.
Any tips what could I do yet and get rid of the error?
EDIT: How or where should I start debugging?
Run openssl s_client -showcerts -connect server_you_are_connecting_to.com:443 and examine the certificate. After this you should find yourself in one of the following situations:
The certificate is valid (has valid expiry date and common name), but it is signed by the certificate authority (CA) that isn't trusted by your system. If that's the case, you would need to add the CA's certificate to the trusted store or update the ca-bundle package on your system.
The certificate is invalid (is expired or has the wrong common name). If disabling peer SSL certificate verification isn't an option for you, then you can implement your own certificate verification callback, for example as described here -- in this case the code wouldn't be relying on system's trusted store, but rather check that the peer server uses a specific certificate.
Hope this helps.
I also started getting this error a few days ago.
Removing geocoder fixed the issue.
Per Heroku support, sometimes these errors occur when an external provider changes their SSL configuration.
Reply to comment:
Nothing in logs specifically saying geocoder, but I saw in my error reports (via exception notifier gem) that the app crashed, with this error, on lines making a request to geocoder.
I also had a callback on the users model, and noticed the app crashed anytime a user was saved/updated.
Lucky guess I suppose.

Mongo SSL config with CA cert only works for rails console, not rails server

I am trying to configure a Rails 4.2.6 app to connect over SSL to a MongoDB cluster on compose.io. The app uses the mongo 2.4.1 and mongoid 5.1.5 gems. Compose.io MongoDB clusters use self-signed SSL certificates so I downloaded the CA certificate from compose.io and placed it in lib/certs/mongo-ca-bundle.pem.
My mongoid.yml file looks like this (redacted):
development:
clients:
default:
uri: mongodb://myuser:mypassword#some-host.dblayer.com:1111,some-other-host.dblayer.com:2222/mydb?ssl=true
options:
ssl_ca_cert: /path/to/myapp/lib/certs/mongo-ca-bundle.pem
The above configuration works perfectly when I run rails console and I can successfully run queries against collections in the compose.io database.
However, when I try to run rails server it crashes after 30 seconds with a "No server is available" error message:
[..]/mongo/server_selector/selectable.rb:115:in `select_server': No server is available matching preference: #<Mongo::ServerSelector::Primary:0x47167439625640 tag_sets=[] max_staleness=nil> using server_selection_timeout=30 and local_threshold=0.015 (Mongo::Error::NoServerAvailable)
[..]/mongo/cluster.rb:226:in `next_primary'
When I enable debug logging for mongoid it indicates that the problem is with the SSL handshake:
DEBUG -- : MONGODB | Server some-host.dblayer.com:1111 initializing.
DEBUG -- : MONGODB | SSL handshake failed. MongoDB may not be configured with SSL support.
I used to get the same error in the rails console until I added the ssl_ca_cert configuration. I did manage to get the server to connect by specifying ssl_verify: false but I don't consider that a valid workaround. How can I fix this? How come the console works but the server doesn't?
It seems I was missing a certificate in the CA-bundle causing the connection to fail. With the proper CA cert in the bundle, rails server can connect just fine.
The reason that rails console worked seems to be that it connects to the local mongodb instance even if I specify a different URL in mongoid.yml. This seems buggy to me, but I haven't investigated further.

How do you install a LetsEncrypt SSL Certificate on Heroku

Since Heroku is read-only and does not allow sudo, what do I need to do to be able to install the LetsEncrypt.org certificate on their server for my app?
If I have already set config.force_ssl = true does that matter?
I read the blog post in the first answer here, but I didn't want to pollute my code-base with ACME urls & logic. So I did something similar, but used DNS domain validation ...
With certbot, specify DNS as your preferred challenge:
sudo certbot certonly --manual --preferred-challenges dns
After a couple of prompts, certbot will tell you to deply a DNS TXT record to validate your domain:
Please deploy a DNS TXT record under the name
_acme-challenge.www.codesy.io with the following value:
CxYdvM...5WvXR0
Once this is deployed,
Press ENTER to continue
Your domain registrar probably has its own docs for deploying a TXT record. Do that, and go back to certbot and press ENTER - Let's Encrypt will check the TXT record, sign the cert, and certbot will save it for you to upload to heroku.
See my own blog post for more detail.
Here are two bash functions that you can use to automate the process for you
function makessl {
sudo certbot certonly --manual --rsa-key-size 4096 --preferred-challenges dns -d ${1}
sudo heroku certs:add --type=sni /etc/letsencrypt/live/${1}/fullchain.pem /etc/letsencrypt/live/${1}/privkey.pem
}
function renewssl {
sudo certbot certonly --manual --rsa-key-size 4096 --preferred-challenges dns -d ${1}
sudo heroku certs:update /etc/letsencrypt/live/${1}/fullchain.pem /etc/letsencrypt/live/${1}/privkey.pem
}
They take an arguement for the domain name and as long as you run them from within your heroku app folder you will not have to specify an --app NAME
Example: makessl www.domain.com
Example: renewssl www.domain.com
Combine this is #Eric's answer and you're good to go:
heroku certs:auto:enable
FYI, Heroku now offers automated certificate management w/ Let's Encrypt if you run a paid dyno. You can enable it with:
heroku certs:auto:enable
More info:
https://devcenter.heroku.com/articles/automated-certificate-management
Edit: This answer no longer applies.
It was written before Heroku implemented native support for LetsEncrypt. Leaving the rest for posterity, but this is no longer necessary. Use #Eric's answer now.
Installing the initial certificate
You can use certbot in manual mode to generate the challenge response, modify your site to return that response, then finally complete the certbot manual process.
See this blog post by Daniel Morrison, or the linked answer under Certificate Updates below, for more details.
Certificate updates
As #Flimm mentioned, and as is mentioned in the linked blog post, you'll have to update this every 3 months until Heroku provides better support for LetsEncrypt. You can make that process smoother (no code changes to upload) using an environment variable as described in this answer (Node/Express but the concepts are the same): https://stackoverflow.com/a/40199581/37168
Sabayon
There is a GitHub project that can automate all of this for you by setting your Heroku environment variables. It's a tiny webapp you install as another Heroku app that in turn configures your primary app. I haven't tried it yet but am planning to use it instead of updating my cert next time: https://github.com/dmathieu/sabayon
The default recommendation of Heroku is SSL using Server Name Indication
(SNI), which is free. Since you already obtained your certificate and key, you can add them by:
heroku certs:add <cert>.pem <key>.key
If you need to support legacy browser clients which do not support SNI use the Herkou SSL Endpoint addon which costs $20/mo:
Add that addon by running
heroku addons:create ssl:endpoint
And then add your LetsEncrypt.org certificates:
heroku certs:add <cert>.pem <key>.key
the best way can be to assign the new ssl domain(that starts with https) to your domain which automatically overrides the non-http domain
I created a certbot plugin that uses the Heroku CLI to automate authentication and installation of Let's Encrypt certificates: https://github.com/gboudreau/certbot-heroku
I only have an example that uses the php-nginx Heroku buildpack, but reading that example and finding the equivalent for other buildpacks should be easy enough.
Pull Requests are welcome to help others!

Using https and SSL with Ruby on Rails

I've run into bit of a problem with setting up my self-signed certificate to test out how it all works. I found a nice gist on GitHub : https://gist.github.com/trcarden/3295935#file-gistfile1-sh-L17
explaining how to do it simply enough.
It errors out on step 3, when entering this command into the Rails console:
$ openssl req -new -key server.key -out server.csr
The problem I run into is the following:
Unable to load config info from /usr/local/ssl/openssl.cnf
This is an output from the Rails console and it seems as a pretty standard error when searching for it on the internet. I've found lots of Q&A threads on various sites but absolutely nothing I've managed to find does the trick.
Any advice on what do try out to solve this ? Thanks
For anyone that has an issue like this, the problem was with using the rails WEBrick library for the server. I'm not sure exactly why, but simply switching to Thin server and using the
thin start --ssl command instead of force_ssl with WEBrick fixed the issue. Feel free to post any additional info if you know of any reasons.

Resources