14

A few days ago we received the error "Strict TLS in CDN not supported" on 1 Heroku app that's behind Cloudflare's proxy (orange cloud, if you know Cloudflare).

Basically, client requests to https://foo.example.com are proxied through Cloudflare, who then make the requests to https://foo.herokuapp.com, caches the response, and passes the result back to the client. Notice that the entire chain is over HTTPS. We've configured Clouflare to only communicate with the end server over HTTPS, and we don't want the end server to ever send out responses over HTTP.

It seems that Heroku's policy no longer allows serving over SSL when they detect that you're behind a proxy that's already handling SSL. Over the past week, more apps have begun showing this error and we've had to disable Cloudflare's proxy. Here's their documentation on this, and the reason given is "because Cloudflare provides SSL certificates."

Anyone else encounter this and have a workaround? While Cloudflare still prevents certain vulnerabilities from the client to Cloudflare, this leaves other vulnerabilities open from Cloudflare to the end server.

Update: I've heard back from Heroku on this:

ACM can be used with Full or Flexible, and can be made to work with "Full (Strict)", but is not recommended. "Full (Strict)" mode ... can be used after ACM completes. If "Full (Strict)" is necessary we recommend a longer term, CA-issued certificate with a CSR signing process instead.

However, I have not found the above to be true. On either setting (Full or Strict), Heroku always reports the above error. I've installed origin certs from Cloudflare to resolve this issue.

Charlie Schliesser
  • 7,851
  • 4
  • 46
  • 76

3 Answers3

16

It looks like Heroku specifically doesn't want you to use ACM (Automatic Certificate Management), in which they use Let's Encrypt to automatically issue certificates for you. This is unnecessary when your certificates aren't client-facing.

If it's always Cloudflare talking to your Heroku app, I suggest instead using "origin certificates". Cloudflare can generate a certificate and private key specifically for you to install on your origin server for the purpose of authenticating it to Cloudflare. This certificate is signed by Cloudflare's private CA, which is not recognized by browsers, only by Cloudflare itself. This means you don't have to jump through so many hoops to verify your domain and renew certs like you would with normal CA certs.

You can tell Cloudflare to generate an origin certificate in the Cloudflare dashboard. You can the install your certificate into Heroku according to this documentation:

https://devcenter.heroku.com/articles/ssl#manually-uploading-certificates-and-intermediaries

Note that this does not require "ACM" on the Heroku side, because you're bringing your own cert. I would expect Heroku is fine with this mode while behind Cloudflare (if not... that would be a pretty serious flaw in Heroku).

Here's Cloudflare's general docs on origin certs:

https://support.cloudflare.com/hc/en-us/articles/115000479507-Managing-Cloudflare-Origin-CA-certificates

(Disclaimer: I haven't actually tried this with Heroku, but I've successfully used origin certs with other hosts in the past.)

Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
  • Thanks for the info! Why would you say ACM is unnecessary in this instance? It still solves the issue of having to install origin certs on all of my apps, and it's all automated. It's been working just fine for a lot of apps for a long time, now I'll have to install origin certs on them all, and those do have expiration dates, although they're absurdly long IIRC. – Charlie Schliesser May 03 '19 at 21:23
  • Well, applying the origin cert to all of my apps apparently takes... not even 20 mins :) So that's a great solution. Still, I wonder why they made this change. Everything via Let's Encrypt is automated, so why should Heroku even care what my proxy situation is? – Charlie Schliesser May 03 '19 at 21:45
  • @CharlieSchliesser There's a *lot* of stuff that goes into operating a real CA that is trusted by browsers. Let's Encrypt is not free to operate -- it is funded by donations. So, over-using it when you don't really needed is sort of inconsiderate. Also, I believe they apply rate limits which might hit big hosts like Heroku. So it makes sense that Heroku would try to discourage people from using ACM (powered by Let's Encrypt) when it's not necessary. – Kenton Varda May 04 '19 at 00:27
4

I was experiencing this problem and this is how I resolved it. First I deleted my certificate from Heroku and also deleted my custom domain then, I went to the terminal

  1. $ heroku certs:info --app myapp (To ensure I did not have a certificate present)

  2. $ heroku certs:auto:enable --app myapp (I did this for good measure, this created a cert)

  3. heroku domains:add data.myapp.com --app data-myapp ( I was working with a subdomain, this added my custom domain)

  4. Add DNS details to Cloudflare, I set it to DNS instead of proxy and it worked. I set it back to Proxy and it worked, I figured, the problem is the process, first use a terminal, two make sure you have a certificate before you add the domain name.

I hope that works for someone.

sam
  • 355
  • 5
  • 10
  • I followed these steps but it didn't work for me... :( – Original BBQ Sauce Dec 27 '20 at 20:41
  • What ended up working was assuming Heroku was treating my Cloudflare SSL setup as "strict" and then following these instructions: https://help.heroku.com/GVS2BTB5/why-am-i-getting-error-525-ssl-handshake-failed-with-cloudflare-when-using-a-herokudns-com-endpoint – Original BBQ Sauce Dec 27 '20 at 21:03
0

I was able to get Heroku to issue the ACM certificate via the following:

  1. enable ACM for my app: heroku certs:auto -a my-app
  2. go to https://dashboard.heroku.com/apps/my-app/settings and add a CNAME for the public-facing domain name (e.g. www.my-app.com). Note the private DNS name (e.g. foo-bar-12345.herokudns.com)
  3. in Cloudflare, add a CNAME DNS entry for www.my-app.com to foo-bar-12345.herokudns.com
  4. in Cloudflare, set TLS to "Flexible"
  5. wait a while
  6. in Heroku, click "Renew ACM status"
  7. wait a while
  8. in Cloudflare, set TLS back to "Strict"
James A. Rosen
  • 64,193
  • 61
  • 179
  • 261