#!/bin/bash # Certbot post-renewal hook for OCI Vault upload # Managed by Ansible - DO NOT EDIT MANUALLY # # This script uploads renewed certificates to OCI Vault so that # fornax can distribute them to target hosts via Ansible. # # Uses Instance Principal authentication (no config file needed). # Called by certbot --deploy-hook after each successful renewal. set -euo pipefail CERT_DIR="{{ certbot_directory }}/config/live" LOG_PREFIX="[$(date '+%Y-%m-%d %H:%M:%S')] [vault-upload]" echo "${LOG_PREFIX} Starting vault upload hook" # RENEWED_LINEAGE is set by certbot to the path of the renewed cert # e.g. /srv/certbot/config/live/bootes.helu.ca if [[ -z "${RENEWED_LINEAGE:-}" ]]; then echo "${LOG_PREFIX} ERROR: RENEWED_LINEAGE not set — not running under certbot?" exit 1 fi CERT_NAME=$(basename "${RENEWED_LINEAGE}") FULLCHAIN="${RENEWED_LINEAGE}/fullchain.pem" PRIVKEY="${RENEWED_LINEAGE}/privkey.pem" OCI="{{ certbot_directory }}/.venv/bin/oci" COMPARTMENT_ID="{{ oci_govern_compartment_id }}" VAULT_ID="{{ oci_vault_id }}" # Convert dots to hyphens to match Terraform secret naming (e.g. pan.helu.ca → pan-helu-ca) VAULT_PREFIX="${CERT_NAME//./-}" echo "${LOG_PREFIX} Processing certificate: ${CERT_NAME} (vault prefix: ${VAULT_PREFIX})" if [[ ! -f "${FULLCHAIN}" ]] || [[ ! -f "${PRIVKEY}" ]]; then echo "${LOG_PREFIX} ERROR: Certificate files not found in ${RENEWED_LINEAGE}" exit 1 fi # Look up secret OCIDs by name (Terraform creates secrets named {domain-hyphens}-fullchain/-privkey) lookup_secret_id() { local secret_name="$1" local result if ! result=$(${OCI} vault secret list \ --auth instance_principal \ --compartment-id "${COMPARTMENT_ID}" \ --vault-id "${VAULT_ID}" \ --name "${secret_name}" \ --lifecycle-state ACTIVE \ --all \ --query 'data[0].id' \ --raw-output 2>&1); then echo "${LOG_PREFIX} ERROR: OCI CLI failed looking up secret '${secret_name}': ${result}" >&2 return 1 fi echo "${result}" } FULLCHAIN_SECRET_ID=$(lookup_secret_id "${VAULT_PREFIX}-fullchain") || true PRIVKEY_SECRET_ID=$(lookup_secret_id "${VAULT_PREFIX}-privkey") || true if [[ -z "${FULLCHAIN_SECRET_ID}" ]] || [[ "${FULLCHAIN_SECRET_ID}" == "null" ]] || \ [[ -z "${PRIVKEY_SECRET_ID}" ]] || [[ "${PRIVKEY_SECRET_ID}" == "null" ]]; then echo "${LOG_PREFIX} ERROR: Could not find vault secrets for ${VAULT_PREFIX} (fullchain=${FULLCHAIN_SECRET_ID:-missing}, privkey=${PRIVKEY_SECRET_ID:-missing})" echo "${LOG_PREFIX} Ensure 'terraform apply' has been run on bootes_certificates.tf" exit 1 fi echo "${LOG_PREFIX} Found secret OCIDs for ${VAULT_PREFIX}" # Upload fullchain to OCI Vault FULLCHAIN_B64=$(base64 -w 0 < "${FULLCHAIN}") if ! upload_output=$(${OCI} vault secret update-base64 \ --auth instance_principal \ --secret-id "${FULLCHAIN_SECRET_ID}" \ --secret-content-content "${FULLCHAIN_B64}" 2>&1); then echo "${LOG_PREFIX} ERROR: Failed to upload fullchain for ${CERT_NAME}: ${upload_output}" exit 1 fi echo "${LOG_PREFIX} Uploaded fullchain for ${CERT_NAME}" # Upload private key to OCI Vault PRIVKEY_B64=$(base64 -w 0 < "${PRIVKEY}") if ! upload_output=$(${OCI} vault secret update-base64 \ --auth instance_principal \ --secret-id "${PRIVKEY_SECRET_ID}" \ --secret-content-content "${PRIVKEY_B64}" 2>&1); then echo "${LOG_PREFIX} ERROR: Failed to upload privkey for ${CERT_NAME}: ${upload_output}" exit 1 fi echo "${LOG_PREFIX} Uploaded privkey for ${CERT_NAME}" {% if certbot_local_cert_name is defined %} # Also combine cert for local HAProxy if this is the local cert if [[ "${CERT_NAME}" == "{{ certbot_local_cert_name }}" ]]; then echo "${LOG_PREFIX} Combining local cert for HAProxy: ${CERT_NAME}" HAPROXY_CERT="{{ haproxy_cert_path }}" cat "${FULLCHAIN}" "${PRIVKEY}" > "${HAPROXY_CERT}.tmp" mv "${HAPROXY_CERT}.tmp" "${HAPROXY_CERT}" chown {{ certbot_user }}:{{ haproxy_group }} "${HAPROXY_CERT}" chmod 640 "${HAPROXY_CERT}" if systemctl is-active --quiet haproxy; then echo "${LOG_PREFIX} Reloading HAProxy..." systemctl reload haproxy fi fi {% endif %} # Update certificate metrics {{ certbot_directory }}/hooks/cert-metrics.sh echo "${LOG_PREFIX} Vault upload hook completed successfully"