Let’s Encrypt and Google App Engine in 2017
So yesterday I set out to protect my Google App Engine (GAE) API with HTTPS. I had already set up my Google App Engine instance. I was vaguely familiar with Let’s Encrypt (https://letsencrypt.org/), although I had never used it. I also had a basic grasp of cryptographic primitives used in encryption and certificates.
There are a lot of blog posts out there about this along with a bunch of StackOverflow posts, all with varying instructions. The official ones by Google seem outdated, and the only thing I could find on Let’s Encrypt side was a bug saying something along the lines of “plz add support for GAE”. I tried a few, and by combining steps in some of them (and a lot of frustration and eventually-resolved confusion) I got it to work. I’m writing up this blog post primarily for myself (so that when I need to re-encrypt in a few months I know how), but hopefully someone out there might find it useful.
(Update: Automated certificate management is coming soon: https://issuetracker.google.com/issues/35900034)
Preliminaries:
- LetsEncrypt issues SSL certificates by automatically verifying that you have ownership of the domain you claim you have. (More on how to verify later.)
- LetsEncrypt client has since been renamed to certbot and is maintained by the EFF: https://certbot.eff.org/
- LetsEncrypt allows you to cover up to 100 domains / subdomains in one certificate.
- LetsEncrypt implements a protocol called ACME (Automated Management Certificate Environment) that allows you to perpetually renew their certificates.
- LetsEncrypt only issues 3 month certificates.
- When LetsEncrypt ‘supports’ a hosting provider, it means you can use their automated software to renew your certificates. If your provider (*cough* Google App Engine *cough*) is not supported, you can still get a LetsEncrypt certificate (it just takes a little more effort), and you’ll need to manually renew it every three months.
- (Not necessary info, but good to know) Amazon apparently has a certificate manager that automates this whole process (and renewal) for you.
Instructions:
- Install CertBot, I used (running on Mac OSX):
brew install certbot
Although there are many ways to install it: https://certbot.eff.org/docs/install.html
2. Decide whether you want to verify your domain through DNS (adding a TXT record to your DNS, same thing you do to verify ownership for Google Analytics or Google WebMaster tools) or HTTP (uploading a file to your app).
For HTTP:
sudo certbot certonly --manual
For DNS (note: DNS can take a while to update, so this may be slower than HTTP):
sudo certbot certonly --manual --preferred-challenges dns
3. Follow instructions! CertBot will ask you to enter a list of space or comma separated domains. Then it will go one by one asking you to verify them by the method you chose in the previous step (DO NOT close the terminal while you complete these steps, then it will issue a new challenge).
For HTTP:
It will ask you to create a file at yourdomain.com/.well-known/acme-challenge/ABC with the value XYZ (note: ABC and XYZ are just placeholders, not actual values). Create folder called letsencrypt in your google app directory, place a file in it called ABC with the contents XYZ, and add the following handler to your app.yaml:
handlers:
- url: /.well-known/acme-challenge
static_dir: letsencrypt...
Then deploy the app (gcloud app deploy app.yaml)! Finally verify that it works (by visiting yourdomain.com/.well-known/acme-challenge/ABC and making sure it doesn’t 404). If that works, go ahead and press enter on the waiting certbot terminal.
For DNS:
It will ask you to add a TXT record to _acme-challenge.yourdomain.com or _acme-challenge.yoursubdomain.yourdomain.com with the contents XYZ (Note: XYZ is a placeholder, not a real value). Go to your domain name provider and add the record, for namecheap it was
type: TXT
host: _acme-challenge (or _acme-challenge.yoursubdomain)
value: XYZ
Then save it and wait for it to propagate. You’ll be able to tell when it’s done because the value XYZ will show up in the output of the DIG terminal command:
$ dig -t txt _acme-challenge.yourdomain.comOR $ dig -t txt _acme-challenge.yoursubdomain.yourdomain.com
Once it appears press enter in the certbot terminal.
4. Congrats! Certbot has just congratulated you on the fact that you have a shiny new certificate waiting for you at: /etc/letsencrypt/live/yourdomain.com/fullchain.pem
Head over to Google’s App Engines SSL Certificates Pages (App Engine > Settings > SSL Certificates, or just https://console.cloud.google.com/appengine/settings/certificates), where you’ll be prompted to copy and paste a certificate and private key (note: you can also upload a file, but this is harder as only root has read permissions on /etc/letsencrypt/live/ and Chrome doesn’t have root permissions). The certificate can be uploaded as is, you can use the following command to copy it to your clipboard:
$ sudo cat /etc/letsencrypt/live/yourdomain.com/fullchain.pem | pbcopy
Before you can upload the private key though, you must convert it to an RSA private key (for the difference see here: https://stackoverflow.com/a/20065522/781199). To do this, run the following command:
$ sudo openssl rsa -inform pem -in /etc/letsencrypt/live/yourdomain.com/privkey.pem -outform pem > /etc/letsencrypt/live/yourdomain.com/rsaprivatekey.pem
(Note: if you want to write out to a file like that, you’ll need root permissions as only root has write permissions on /etc/letsencrypt/live/, to do that you can use “$ sudo su root”).
And then copy and paste it into the private key box on Google App Engine:
$ sudo cat /etc/letsencrypt/live/yourdomain.com/rsaprivatekey.pem | pbcopy
Done! Your site is now HTTPS protected! Don’t forget to renew your cert in 3 months 🔐