Let’s Encrypt with OCI Certificates Service

load balancer oci Mar 05, 2025

I do a fair about of lab work in my OCI Tenancy. A lot of this work involves things like web servers, load balancers and other things that require X.509 certificates for TLS. For this work, I like to use the Let’s Encrypt CA, because you can’t beat the price and ease of use. This was working fine, but I found my normal process too manual. I often found myself configuring a lab with a new certificate, TLS would be working, and then when I came back to the lab a few months later everything would be expired! With certificate expiration dates getting shorter and shorter, I was looking for a way to fully automate renewals.

I came across a few blog posts from the Oracle A-Team, talking about Let’s Encrypt and using a certbot DNS plugin that works with OCI directly. Following these examples, I was able to generate Let’s Encrypt certificates for my labs in a fully automated process. However, this still left me manually renewing the certificates in services that used them for TLS. I had a few areas in my lab using nginx and the certbot handled that well enough, but what about my OCI Load Balancers that leveraged the OCI Certificates service? This brought me to the certbot renew --deploy-hook functionality.

In the steps below I will walk through the full process of generating a new certificate, adding it to the OCI Certificates service, configuring an OCI Load Balancer to use it, and finally renewing the certificate while automatically deploying to OCI.

Creating Certificate

  1. Follow the OCI and Certbot configuration steps via Christopher Johnson’s blog post.

    • His post does a great job of walking you through the basic setup to get his certbot plugin working.
    • For this demo, I will be using ~/certs as a base directory for things like the certbot-dns-oci plugin, logs, work and config directories.
  2. Now that certbot is configured, use it to generate a new certificate locally.

    export domain=certlab.psadmin.cloud 
    cd ~/certs
    certbot certonly \
      --logs-dir logs --work-dir work --config-dir config \
      --dns-oci-instance-principal=y \
      --authenticator dns-oci \
      --email [email protected] \
      --agree-tos \
      --no-eff-email \
      -d $domain
    
  3. We now have a certificate! Let’s use oci-cli to create it in the OCI Certificates service.

    • Get the OCID of the Compartment you want to manage certificates in and set some other variables.

      # Variables
      
      ## OCI Certificate Compartment
      comp_id="ocid1.compartment.oc1..aaaaa<YOUR_CERT_COMP_ID>"
      
      ## Certbot Certificate config
      cert_dir="/home/opc/certs"
      cert_name="certlab.psadmin.cloud"
      chain="$(cat $cert_dir/config/live/$cert_name/chain.pem)"
      cert="$(cat $cert_dir/config/live/$cert_name/cert.pem)"
      privkey="$(cat $cert_dir/config/live/$cert_name/privkey.pem)"
      
    • Create the Certificate in OCI

      # Create Certificate - Imported
      oci certs-mgmt certificate create-by-importing-config \
        --auth instance_principal \
        --compartment-id $comp_id \
        --name $cert_name \
        --cert-chain-pem "$chain" \
        --certificate-pem "$cert" \
        --private-key-pem "$privkey"
      
    • Validate the Certificate was created in OCI

      # Validate Certificate
      oci certs-mgmt certificate list \
        --auth instance_principal \
        --compartment-id $comp_id \
        --name $cert_name \
        --output table --all \
        --query "data.items[*].{Name:name,OCID:id}"
      +-----------------------+----------------------------------------------------------------------------------------+
      | Name                  | OCID                                                                                   |
      +-----------------------+----------------------------------------------------------------------------------------+
      | certlab.psadmin.cloud | ocid1.certificate.oc1.iad.amaaaaaaha7drbiagvmy32yvpugesvbe6ca4ywf7treg3w6a44zrbvbeme5a |
      +-----------------------+----------------------------------------------------------------------------------------+
  4. Now that we have a managed certificate, we can configure an OCI Load Balancer Listener to use it.

Renewing Certificate

  1. Before we use certbot to renew our certificate, let’s create a renewal-hooks script to deploy any updated certificates to the OCI Certificates service.

    1. Set variables and create a new renewal hooks script file.

      cert_dir="/home/opc/certs"
      touch $cert_dir/config/renewal-hooks/deploy/oci_deploy.sh
      chmod a+x $cert_dir/config/renewal-hooks/deploy/oci_deploy.sh
      
    2. Update the oci_deploy.sh script with the code below.

      # oci_deploy.sh - Deploy script for deploying renewed certs to OCI
      ###
      
      # Variables
      
      ## OCI Certificate Compartment
      comp_id="ocid1.compartment.oc1..<YOUR_COMP_OCID>"
      
      ## Assume single domain that shares OCI Certificate name
      cert_name="${RENEWED_DOMAINS?}" # certbot deploy-hook env var
      
      ## Certbot Certificate config
      cert_dir="${RENEWED_LINEAGE?}" # certbot deploy-hook env var
      chain="$(cat $cert_dir/chain.pem)"
      cert="$(cat $cert_dir/cert.pem)"
      privkey="$(cat $cert_dir/privkey.pem)"
      
      # Get Certificate OCID
      cert_id=$(oci certs-mgmt certificate list \
        --auth instance_principal \
        --compartment-id $comp_id \
        --name $cert_name \
        --all \
        --query "data.items[0].id" \
        --raw-output
      )
      
      # Update Certificate
      oci certs-mgmt certificate \
        update-certificate-by-importing-config-details \
        --auth instance_principal \
        --certificate-id "$cert_id" \
        --certificate-pem "$cert" \
        --private-key-pem "$privkey" \
        --cert-chain-pem "$chain"
      
    3. If you want to test this before using from certbot, run this script directly.

      # NOTE: A new certificate version should show in OCI with the same certificate. 
      
      # Variables that can be used for testing outside of certbot
      cert_dir="/home/opc/certs" export RENEWED_DOMAINS=certlab.psadmin.cloud export RENEWED_LINEAGE=$cert_dir/config/live/$RENEWED_DOMAINS $cert_dir/config/renewal-hooks/deploy/oci_deploy.sh
    4. Use oci-cli or the OCI Console to validate the new versions(same certificate).

  2. Now that we validated our deploy hook script, let’s use certbot to renew our certificate and pass the --deploy-hook argument.

    • This will generate a new certificate for us locally, as well as deploy it to OCI Certificates service.
    • NOTE: By default, certbot will not renew a certificate unless it expires soon. For the purposes of this demo, I am passing the --force-renew flag. In general this flag should be skipped so this command can be scheduled daily and it will only take action if needed.
    cert_name=certlab.psadmin.cloud 
    cd ~/certs
    certbot renew \
      --logs-dir logs --work-dir work --config-dir config \
      --dns-oci-instance-principal=y \
      --authenticator dns-oci \
      --cert-name $cert_name \
      --deploy-hook config/renewal-hooks/deploy/oci_deploy.sh \
      # --force-renew # Use for testing
    
  3. Use ocicli or the OCI Console to validate the new versions(new certificate).

 

Conclusion

This was a pretty simple demo, using a very basic deploy hook script. It works great for my lab, but really needs additional validation and more flexibility built in to be useful beyond that. My goal was to demonstrate the power of the OCI Certificates service when tied to tools like the ACME client. Can you think of any other use cases, processes, plugins, etc. that would be worth exploring with OCI and certificate management?