Automatic renewal of Oracle Cloud Load Balancer SSL Certs with Certbot & Let's Encrypt
I recently had trouble finding a solution to issue public SSL certs for an OCI Load Balancer with automatic renewal. I was hoping the OCI native Certificates resource would be the answer, but these are untrusted self-signed certs only.
So naturally, I turned to Certbot to see if it could provide an answer, and as it so happens the deploy-hook function combined with Oracle's oci-cli tool makes for a straightforward and effective solution.
Prerequisites
Install Packages:
- python3
- python3-venv
- libaugeas0
Create Python VENV:
/usr/bin/python3 -m venv /opt/certbot/
/opt/certbot/bin/pip install --upgrade pip
Install Certbot:
/opt/certbot/bin/pip install certbot
Install OCI-CLI:
According to Oracles Documentation at the time of writing, though best to follow the most recent official installation guide.
bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
The installation script will walk you through the creation of your configuration file. You will then want to add your API Keys to your selected User in the OCI console:
Identity > Users > User Details > API Keys
Create OCI Load Balancer and Listener:
If you're following this guide, I will assume you already have a Load Balancer resource in OCI. You should create a HTTPS Listener with a Backend Set before proceeding.
The Scripts:
This below command will issue an LE cert for example.com with the SAN www.example.com using the DNS method, which requires being able to create a TXT record under the authoritative zone for example.com.
Complete and save this script as renew-certs.sh:
#!/bin/bash
certbot certonly \
-d example.com,www.example.com \
--cert-name example.com \
--manual \
--preferred-challenges dns \
--force-renew \
--deploy-hook ./deploy-hook.sh
By using this method, we will not be required to respond to HTTP challenge requests on the local Certbot host, which can become complex when sitting behind a Load Balancer.
(If the DNS method is not an option for you, this guide does a good job at walking through the steps involved in creating the neccessary Listener, Backend Set and Path Route Set)
Certbot will then call a deploy-hook script, which is executed only on successful renewal of certs. The deploy-hook is passed the environment variables $RENEWED_DOMAINS (the certificate CN) and $RENEWED_LINEAGE (the path to the directory containing all cert keys)
Complete and save this script as deploy-hook.sh:
#!/bin/bash
oci lb certificate create \
--config-file ./config \
--load-balancer-id <ocid> \
--wait-for-state SUCCEEDED \
--certificate-name "$RENEWED_DOMAINS-"`date +"%Y-%m-%d"` \
--ca-certificate-file "$RENEWED_LINEAGE/fullchain.pem" \
--private-key-file "$RENEWED_LINEAGE/privkey.pem" \
--public-certificate-file "$RENEWED_LINEAGE/cert.pem"
oci lb listener update --force \
--config-file ./config \
--load-balancer-id <ocid> \
--wait-for-state SUCCEEDED \
--listener-name "HTTPS" \
--default-backend-set-name <backend_set> \
--port 443 --protocol HTTPS \
--ssl-certificate-name "$RENEWED_DOMAINS-"`date +"%Y-%m-%d"` \
--hostname-names \[\"$RENEWED_DOMAINS\"\]
The two steps in this script are:
1) Upload the newly generated cert to the Load Balancer resource
2) Apply the newly generated cert to the Load Balancer Listener
Done! Running renew-certs.sh will take care of cert renewal, as well as pushing the new certs out to your OCI Load Balancer. This script can be executed by a cronjob every 30 days, or at whatever frequency you wish to renew.
Hope this helped, feel free to send any questions my way if you have run into trouble.