-
Notifications
You must be signed in to change notification settings - Fork 7
Use of Let's Encrypt to generate SSL certificates
Some notes as I'm working out how to use Let's Encrypt - Free SSL/TLS Certificates as a cert authority for opencontext servers.
An update on my latest work -- on branch https://github.com/rdhyee/open-context-py/tree/staging_prod_ssl (specifically https://github.com/rdhyee/open-context-py/tree/dc87af3911197350e8804dbf1fa33ab9a5f7fa89)
I have two different letsencrypt workflows that can possibly combined. When using vagrant/ansible to build staging using the opencontext_predb machine (https://github.com/rdhyee/open-context-py/blob/dc87af3911197350e8804dbf1fa33ab9a5f7fa89/sysadmin/Vagrantfile\#L105-L138 ), there are two paths -- so far I went with Option 2 -- so let me describe the first option here
Option 1 is: run nginx with the server key and certificate that I've put into the Github repo (https://github.com/rdhyee/open-context-py/tree/staging_prod_ssl/sysadmin/files/ssl-certs/opencontext_predb). Originally, I had self-signed ssl certs that could serve as placeholders:
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/C=US/ST=California/L=San Francisco/O=The Alexandria Archive Institute/OU= /CN=*.opencontext.org/"
openssl x509 -req -days 999 -in server.csr -signkey server.key -out server.crt
and
https://github.com/rdhyee/open-context-py/blob/staging_prod_ssl/sysadmin/build.yml#L466-L489
A self-signed SSL cert doesn't leave the browser that happy -- CSS and scripts don't load properly -- but there is encryption. To fix the problem, we can then run certbot to generate a cert for this host (e.g., staging.opencontext.org) by running:
sudo certbot --agree-tos -m raymond.yee@gmail.com --no-eff-email --nginx -d staging.opencontext.org --no-redirect
The plus side is that should set this staging.opencontext.org ready to renew its cert in 90 days. The possible downsides: 1) you have to run this step manually (which isn't a big burden) and 2) there is rate limit on the number of times you can renew a cert (5 times a week) (https://letsencrypt.org/docs/rate-limits/) --> which could be a problem if we're rebuilding staging.opencontext.org a lot (which is not a big problem.
It turns out it's possible to make wildcard certs with letsencrypt. That is, instead of using a self-signed cert, we makea wildcard cert that can be used for any opencontext.org
I have installed certbot on my Mac and downloaded the appropriate google credentials so that I can run certbot to create a wildcard cert.
First, to install certbot
on macOS:
brew install letsencrypt
I also need the certbot-dns-google certbot plugin. How to install the plugin? I learned from ssl - How to install Certbot plugins? - DevOps Stack Exchange. Here's what happened the first time through....
$ which certbot
/usr/local/bin/certbot
$ head /usr/local/bin/certbot
#!/usr/local/Cellar/certbot/0.37.1_1/libexec/bin/python3.7
Then:
/usr/local/Cellar/certbot/0.37.1_1/libexec/bin/python3.7 -m pip install certbot-dns-google
(2020.02.14) It turns out that since I last ran certbot
on my Mac, the homebrew
version of Python was upgraded -- so now I have to reinstall the plugin.
$ head `which certbot`
#!/bin/bash
PYTHONPATH="/usr/local/Cellar/certbot/1.1.0/libexec/lib/python3.8/site-packages:/usr/local/Cellar/certbot/1.1.0/libexec/vendor/lib/python3.8/site-packages" exec "/usr/local/Cellar/certbot/1.1.0/libexec/bin/certbot" "$@"
$ head /usr/local/Cellar/certbot/1.1.0/libexec/bin/certbot
#!/usr/local/opt/python@3.8/bin/python3.8
I'm going to put certbot-dns-google
into /usr/local/Cellar/certbot/1.1.0/libexec/vendor/lib/python3.8/site-packages/
PYTHONPATH="/usr/local/Cellar/certbot/1.1.0/libexec/lib/python3.8/site-packages:/usr/local/Cellar/certbot/1.1.0/libexec/vendor/lib/python3.8/site-packages" /usr/local/opt/python@3.8/bin/python3.8 -m pip install --target /usr/local/Cellar/certbot/1.1.0/libexec/vendor/lib/python3.8/site-packages/ certbot-dns-google
sudo certbot certonly \
--dns-google \
--dns-google-credentials /Volumes/ryvault1/opencontext/keys/opencontext-py-gce.json \
--dns-google-propagation-seconds 120 \
--agree-tos -m raymond.yee@gmail.com --no-eff-email \
-d "*.opencontext.org" -d "opencontext.org"
When I ran certbot on 2019.10.04 (after having a cert already in place that was not near renewal time): I get a message like:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-google, Installer None
Cert not yet due for renewal
You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/opencontext.org.conf)
What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the cert (limit ~5 per 7 days)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Renewing an existing certificate
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/opencontext.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/opencontext.org/privkey.pem
Your cert will expire on 2020-01-02. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Let me copy the new cert to staging and restart nginx
Borrowing a trick from scp from stdin – /dev/blog -- on my Mac, I ran [oc-staging is a configuration in my .ssh config file] to copy the new certs to the staging server which is already running:
# the certs are not visible to my login account -- hence use of sudo -- and the need to type in password
sudo cat /etc/letsencrypt/live/opencontext.org/fullchain.pem | ssh oc-staging "sudo cat >/opt/ocweb/certs/server.crt"
sudo cat /etc/letsencrypt/live/opencontext.org/privkey.pem | ssh oc-staging "sudo cat >/opt/ocweb/certs/server.key"
ssh oc-staging sudo /etc/init.d/nginx restart
Some incantations to encrypt the certs using ansible-vault
. I made use of an encrypted partition on my Mac (/Volumes/ryvault1
) so that I never expose the keys as non-root accessible (a bit of overkill perhaps):
sudo cp /etc/letsencrypt/live/opencontext.org/fullchain.pem /Volumes/ryvault1/tmp/server.crt
sudo cp /etc/letsencrypt/live/opencontext.org/privkey.pem /Volumes/ryvault1/tmp/server.key
sudo chown raymondyee /Volumes/ryvault1/tmp/server.crt
sudo chown raymondyee /Volumes/ryvault1/tmp/server.key
ansible-vault encrypt --encrypt-vault-id=oc /Volumes/ryvault1/tmp/server.crt
ansible-vault encrypt --encrypt-vault-id=oc /Volumes/ryvault1/tmp/server.key
mv /Volumes/ryvault1/tmp/server.crt ~/C/src/open-context-py/sysadmin/files/ssl-certs/opencontext_predb/server.crt
mv /Volumes/ryvault1/tmp/server.key ~/C/src/open-context-py/sysadmin/files/ssl-certs/opencontext_predb/server.key