#!/usr/bin/sh #------------------------------------------------------------------------------ # /var/install/bin/certs_dehydrated-hook # # Copyright (c) 2016-2025 The Eisfair Team, team(at)eisfair(dot)org # # Creation : 2016-09-02 jed # Last Update: $Id$ # # Available hooks: # # clean_challenge - called after attempting to validate each domain. # deploy_cert - called once for each certificate that has been produced. # deploy_challenge - called once for every domain that needs to be validated. # deploy_ocsp - called once for each updated ocsp stapling file that has been produced. # exit_hook - called at the end of a cron command. # generate_csr - called before any certificate signing operation takes place. # invalid_challenge - called if the challenge response has failed. # startup_hook - called before the cron command to do some initial tasks. # sync_cert - called after the certificates have been created but before they are symlinked. # unchanged_cert - called once for each certificate that is still valid. # request_failure - called when a HTTP request fails. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. #------------------------------------------------------------------------------ module_name=`basename $0 | cut -d- -f1` # debug mode true/false #debug=true if ${debug:-false} then exec 2> /tmp/${module_name}-hook-trace$$.log set -x ask_debug=true export ask_debug fi EXEC_CMD="$0 $*" configfile=/etc/config.d/${module_name} dehydrated_data_path=/var/certs/dehydrated DEHYDRATED_DATA_PATH=`grep "^DEHYDRATED_DATA_PATH=" ${configfile} | sed -e 's/#.*$//' -e "s/^.*=['\"]\(.*\)['\"].*$/\1/" -e 's#/ *$##'` if [ -n "${DEHYDRATED_DATA_PATH}" ] then dehydrated_data_path="${DEHYDRATED_DATA_PATH}" fi #------------------------------------------------------------------------------ # !! BASEDIR and WELLKNOWN variables are also exported and can be used in # !! an external program. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # clean_challenge - This hook is called after attempting to validate each # domain, whether or not validation was successful. Here # you can delete files or DNS records that are no longer # needed. # # Parameters: # # DOMAIN - The domain name (CN or subject alternative name) being # validated. # TOKEN_FILENAME - The name of the file containing the token to be served # for HTTP validation. Should be served by your web server # as /.well-known/acme-challenge/${TOKEN_FILENAME}. # TOKEN_VALUE - The token value that needs to be served for validation. # For DNS validation, this is what you want to put in the # _acme-challenge TXT record. For HTTP validation it is # the value that is expected be found in the $TOKEN_FILENAME # file. #------------------------------------------------------------------------------ clean_challenge () { export DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" if [ -s ${dehydrated_data_path}/${module_name}_clean_challenge ] then echo "-> Executing hook script 'clean_challenge' ..." /bin/sh ${dehydrated_data_path}/${module_name}_clean_challenge fi } #------------------------------------------------------------------------------ # deploy_cert - This hook is called once for each certificate that has # been produced. Here you might, for instance, copy your # new certificates to service-specific locations and reload # the service. # # Parameters: # # DOMAIN - The primary domain name, i.e. the certificate common # name (CN). # KEYFILE - The path of the file containing the private key. # CERTFILE - The path of the file containing the signed certificate. # FULLCHAINFILE - The path of the file containing the full certificate # chain. # CHAINFILE - The path of the file containing the intermediate # certificate(s). # TIMESTAMP - Timestamp when the specified certificate was created. #------------------------------------------------------------------------------ deploy_cert () { export DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}" if [ -s ${dehydrated_data_path}/${module_name}_deploy_cert ] then echo "-> Executing hook script 'deploy_cert' ..." /bin/sh ${dehydrated_data_path}/${module_name}_deploy_cert fi } #------------------------------------------------------------------------------ # deploy_challenge - This hook is called once for every domain that needs # to be validated, including any alternative names you # may have listed. # # Parameters: # # DOMAIN - The domain name (CN or subject alternative name) being # validated. # TOKEN_FILENAME - The name of the file containing the token to be served # for HTTP validation. Should be served by your web server # as /.well-known/acme-challenge/${TOKEN_FILENAME}. # TOKEN_VALUE - The token value that needs to be served for validation. # For DNS validation, this is what you want to put in the # _acme-challenge TXT record. For HTTP validation it is # the value that is expected be found in the $TOKEN_FILENAME # file. #------------------------------------------------------------------------------ deploy_challenge () { export DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" if [ -s ${dehydrated_data_path}/${module_name}_deploy_challenge ] then echo "-> Executing hook script 'deploy_challenge' ..." /bin/sh ${dehydrated_data_path}/${module_name}_deploy_challenge fi } #------------------------------------------------------------------------------ # deploy_ocsp - This hook is called once for each updated ocsp stapling file # that has been produced. Here you might, for instance, copy # your new ocsp stapling files to service-specific locations # and reload the service. # # Parameters: # # DOMAIN - The primary domain name, i.e. the certificate common name (CN). # OCSPFILE - The path of the ocsp stapling file. # TIMESTAMP - Timestamp when the specified ocsp stapling file was created. #------------------------------------------------------------------------------ deploy_ocsp () { export DOMAIN="${1}" OCSPFILE="${2}" TIMESTAMP="${3}" if [ -s ${dehydrated_data_path}/${module_name}_deploy_ocsp ] then echo "-> Executing hook script 'deploy_ocsp' ..." /bin/sh ${dehydrated_data_path}/${module_name}_deploy_ocsp fi } #------------------------------------------------------------------------------ # exit_hook - This hook is called at the end of a cron command and can # be used to do some final (cleanup or other) tasks. # # Parameters: # # ERROR - Contains the error message if dehydrated exits with error. #------------------------------------------------------------------------------ exit_hook () { export ERROR="${1}" if [ -s ${dehydrated_data_path}/${module_name}_exit_hook ] then echo "-> Executing hook script 'exit_hook' ..." /bin/sh ${dehydrated_data_path}/${module_name}_exit_hook fi } #------------------------------------------------------------------------------ # generate_csr - This hook is called before any certificate signing operation # takes place. It can be used to generate or fetch a certificate # signing request with external tools. The output should be just # the cerificate signing request formatted as PEM. # # Parameters: # # DOMAIN - The primary domain as specified in domains.txt. This # does not need to match with the domains in the CSR, it's # basically just the directory name. # CERTDIR - Certificate output directory for this particular # certificate. Can be used for storing additional files. # ALTNAMES - All domain names for the current certificate as specified # in domains.txt. Again, this doesn't need to match with the # CSR, it's just there for convenience. #------------------------------------------------------------------------------ generate_csr () { export DOMAIN="${1}" CERTDIR="${2}" ALTNAMES="${3}" if [ -s ${dehydrated_data_path}/${module_name}_generate_csr ] then echo "-> Executing hook script 'generate_csr' ..." /bin/sh ${dehydrated_data_path}/${module_name}_generate_csr fi } #------------------------------------------------------------------------------ # invalid_challenge - This hook is called if the challenge response has # failed, so domain owners can be aware and act # accordingly. # # Parameters: # # DOMAIN - The primary domain name, i.e. the certificate common name (CN). # RESPONSE - The response that the verification server returned #------------------------------------------------------------------------------ invalid_challenge () { export DOMAIN="${1}" RESPONSE="${2}" if [ -s ${dehydrated_data_path}/${module_name}_invalid_challenge ] then echo "-> Executing hook script 'invalid_challenge' ..." /bin/sh ${dehydrated_data_path}/${module_name}_invalid_challenge fi } #------------------------------------------------------------------------------ # request_failure - This hook is called when a HTTP request fails (e.g., when # the ACME server is busy, returns an error, etc). It will # be called upon any response code that does not start with # '2'. Useful to alert admins about problems with requests. # # Parameters: # # STATUSCODE - The HTML status code that originated the error. # REASON - The specified reason for the error. # REQTYPE - The kind of request that was made (GET, POST...) # HEADERS - HTTP headers returned by the CA. #------------------------------------------------------------------------------ request_failure () { export STATUSCODE="${1}" REASON="${2}" REQTYPE="${3}" HEADERS="${4}" if [ -s ${dehydrated_data_path}/${module_name}_request_failure ] then echo "-> Executing hook script 'request_failure' ..." /bin/sh ${dehydrated_data_path}/${module_name}_request_failure fi } #------------------------------------------------------------------------------ # startup_hook - This hook is called before the cron command to do some # initial tasks (e.g. starting a webserver). #------------------------------------------------------------------------------ startup_hook () { if [ -s ${dehydrated_data_path}/${module_name}_startup_hook ] then echo "-> Executing hook script 'startup_hook' ..." /bin/sh ${dehydrated_data_path}/${module_name}_startup_hook fi } #------------------------------------------------------------------------------ # sync_cert - This hook is called after the certificates have been created but # before they are symlinked. This allows you to sync the files to # disk to prevent creating a symlink to empty files on unexpected # system crashes. # This hook is not intended to be used for further processing of # certificate files, see deploy_cert for that. # # Parameters: # # KEYFILE - The path of the file containing the private key. # CERTFILE - The path of the file containing the signed certificate. # FULLCHAINFILE - The path of the file containing the full certificatei # chain. # CHAINFILE - The path of the file containing the intermediate # certificate(s). # REQUESTFILE - The path of the file containing the certificate signing # request. #------------------------------------------------------------------------------ sync_cert () { export KEYFILE="${1}" CERTFILE="${2}" FULLCHAINFILE="${3}" CHAINFILE="${4}" REQUESTFILE="${5}" if [ -s ${dehydrated_data_path}/${module_name}_sync_cert ] then echo "-> Executing hook script 'sync_cert' ..." /bin/sh ${dehydrated_data_path}/${module_name}_sync_cert fi } #------------------------------------------------------------------------------ # unchanged_cert - This hook is called once for each certificate that is # still valid and therefore wasn't reissued. # # Parameters: # # DOMAIN - The primary domain name, i.e. the certificate common # name (CN). # KEYFILE - The path of the file containing the private key. # CERTFILE - The path of the file containing the signed certificate. # FULLCHAINFILE - The path of the file containing the full certificate # chain. # CHAINFILE - The path of the file containing the intermediate # certificate(s). #------------------------------------------------------------------------------ unchanged_cert () { export DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" if [ -s ${dehydrated_data_path}/${module_name}_unchanged_cert ] then echo "-> Executing hook script 'unchanged_cert' ..." /bin/sh ${dehydrated_data_path}/${module_name}_unchanged_cert fi } #============================================================================== # main #============================================================================== HANDLER="${1}" shift # call scripts only for valid hooks case "${HANDLER}" in deploy_challenge|clean_challenge|deploy_cert|deploy_ocsp|generate_csr|unchanged_cert|invalid_challenge|request_failure|startup_hook|exit_hook|sync_cert ) "${HANDLER}" "$@" ;; * ) ;; esac #============================================================================== # end #==============================================================================