3636# Note: This functionality requires HAProxy was compiled against
3737# a version of OpenSSL that supports this.
3838#
39+ # export DEPLOY_HAPROXY_HOT_UPDATE="yes"
40+ # export DEPLOY_HAPROXY_STATS_SOCKET="UNIX:/run/haproxy/admin.sock"
41+ #
42+ # OPTIONAL: Deploy the certificate over the HAProxy stats socket without
43+ # needing to reload HAProxy. Default is "no".
44+ #
45+ # Require the socat binary. DEPLOY_HAPROXY_STATS_SOCKET variable uses the socat
46+ # address format.
47+ #
48+ # export DEPLOY_HAPROXY_MASTER_CLI="UNIX:/run/haproxy-master.sock"
49+ #
50+ # OPTIONAL: To use the master CLI with DEPLOY_HAPROXY_HOT_UPDATE="yes" instead
51+ # of a stats socket, use this variable.
3952
4053# ####### Public functions #####################
4154
@@ -46,13 +59,16 @@ haproxy_deploy() {
4659 _ccert=" $3 "
4760 _cca=" $4 "
4861 _cfullchain=" $5 "
62+ _cmdpfx=" "
4963
5064 # Some defaults
5165 DEPLOY_HAPROXY_PEM_PATH_DEFAULT=" /etc/haproxy"
5266 DEPLOY_HAPROXY_PEM_NAME_DEFAULT=" ${_cdomain} .pem"
5367 DEPLOY_HAPROXY_BUNDLE_DEFAULT=" no"
5468 DEPLOY_HAPROXY_ISSUER_DEFAULT=" no"
5569 DEPLOY_HAPROXY_RELOAD_DEFAULT=" true"
70+ DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT=" no"
71+ DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT=" UNIX:/run/haproxy/admin.sock"
5672
5773 _debug _cdomain " ${_cdomain} "
5874 _debug _ckey " ${_ckey} "
@@ -86,6 +102,11 @@ haproxy_deploy() {
86102 _savedomainconf Le_Deploy_haproxy_pem_name " ${Le_Deploy_haproxy_pem_name} "
87103 elif [ -z " ${Le_Deploy_haproxy_pem_name} " ]; then
88104 Le_Deploy_haproxy_pem_name=" ${DEPLOY_HAPROXY_PEM_NAME_DEFAULT} "
105+ # We better not have '*' as the first character
106+ if [ " ${Le_Deploy_haproxy_pem_name%% " ${Le_Deploy_haproxy_pem_name# ?} " } " = ' *' ]; then
107+ # removes the first characters and add a _ instead
108+ Le_Deploy_haproxy_pem_name=" _${Le_Deploy_haproxy_pem_name# ?} "
109+ fi
89110 fi
90111
91112 # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
@@ -118,6 +139,36 @@ haproxy_deploy() {
118139 Le_Deploy_haproxy_reload=" ${DEPLOY_HAPROXY_RELOAD_DEFAULT} "
119140 fi
120141
142+ # HOT_UPDATE is optional. If not provided then assume "${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
143+ _getdeployconf DEPLOY_HAPROXY_HOT_UPDATE
144+ _debug2 DEPLOY_HAPROXY_HOT_UPDATE " ${DEPLOY_HAPROXY_HOT_UPDATE} "
145+ if [ -n " ${DEPLOY_HAPROXY_HOT_UPDATE} " ]; then
146+ Le_Deploy_haproxy_hot_update=" ${DEPLOY_HAPROXY_HOT_UPDATE} "
147+ _savedomainconf Le_Deploy_haproxy_hot_update " ${Le_Deploy_haproxy_hot_update} "
148+ elif [ -z " ${Le_Deploy_haproxy_hot_update} " ]; then
149+ Le_Deploy_haproxy_hot_update=" ${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT} "
150+ fi
151+
152+ # STATS_SOCKET is optional. If not provided then assume "${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
153+ _getdeployconf DEPLOY_HAPROXY_STATS_SOCKET
154+ _debug2 DEPLOY_HAPROXY_STATS_SOCKET " ${DEPLOY_HAPROXY_STATS_SOCKET} "
155+ if [ -n " ${DEPLOY_HAPROXY_STATS_SOCKET} " ]; then
156+ Le_Deploy_haproxy_stats_socket=" ${DEPLOY_HAPROXY_STATS_SOCKET} "
157+ _savedomainconf Le_Deploy_haproxy_stats_socket " ${Le_Deploy_haproxy_stats_socket} "
158+ elif [ -z " ${Le_Deploy_haproxy_stats_socket} " ]; then
159+ Le_Deploy_haproxy_stats_socket=" ${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT} "
160+ fi
161+
162+ # MASTER_CLI is optional. No defaults are used. When the master CLI is used,
163+ # all commands are sent with a prefix.
164+ _getdeployconf DEPLOY_HAPROXY_MASTER_CLI
165+ _debug2 DEPLOY_HAPROXY_MASTER_CLI " ${DEPLOY_HAPROXY_MASTER_CLI} "
166+ if [ -n " ${DEPLOY_HAPROXY_MASTER_CLI} " ]; then
167+ Le_Deploy_haproxy_stats_socket=" ${DEPLOY_HAPROXY_MASTER_CLI} "
168+ _savedomainconf Le_Deploy_haproxy_stats_socket " ${Le_Deploy_haproxy_stats_socket} "
169+ _cmdpfx=" @1 " # command prefix used for master CLI only.
170+ fi
171+
121172 # Set the suffix depending if we are creating a bundle or not
122173 if [ " ${Le_Deploy_haproxy_bundle} " = " yes" ]; then
123174 _info " Bundle creation requested"
@@ -142,12 +193,13 @@ haproxy_deploy() {
142193 _issuer=" ${_pem} .issuer"
143194 _ocsp=" ${_pem} .ocsp"
144195 _reload=" ${Le_Deploy_haproxy_reload} "
196+ _statssock=" ${Le_Deploy_haproxy_stats_socket} "
145197
146198 _info " Deploying PEM file"
147199 # Create a temporary PEM file
148200 _temppem=" $( _mktemp) "
149201 _debug _temppem " ${_temppem} "
150- cat " ${_ccert} " " ${_cca} " " ${_ckey} " > " ${_temppem} "
202+ cat " ${_ccert} " " ${_cca} " " ${_ckey} " | grep . > " ${_temppem} "
151203 _ret=" $? "
152204
153205 # Check that we could create the temporary file
@@ -265,15 +317,86 @@ haproxy_deploy() {
265317 fi
266318 fi
267319
268- # Reload HAProxy
269- _debug _reload " ${_reload} "
270- eval " ${_reload} "
271- _ret=$?
272- if [ " ${_ret} " != " 0" ]; then
273- _err " Error code ${_ret} during reload"
274- return ${_ret}
320+ if [ " ${Le_Deploy_haproxy_hot_update} " = " yes" ]; then
321+ # set the socket name for messages
322+ if [ -n " ${_cmdpfx} " ]; then
323+ _socketname=" master CLI"
324+ else
325+ _socketname=" stats socket"
326+ fi
327+
328+ # Update certificate over HAProxy stats socket or master CLI.
329+ if _exists socat; then
330+ # look for the certificate on the stats socket, to chose between updating or creating one
331+ _socat_cert_cmd=" echo '${_cmdpfx} show ssl cert' | socat '${_statssock} ' - | grep -q '^${_pem} $'"
332+ _debug _socat_cert_cmd " ${_socat_cert_cmd} "
333+ eval " ${_socat_cert_cmd} "
334+ _ret=$?
335+ if [ " ${_ret} " != " 0" ]; then
336+ _newcert=" 1"
337+ _info " Creating new certificate '${_pem} ' over HAProxy ${_socketname} ."
338+ # certificate wasn't found, it's a new one. We should check if the crt-list exists and creates/inserts the certificate.
339+ _socat_crtlist_show_cmd=" echo '${_cmdpfx} show ssl crt-list' | socat '${_statssock} ' - | grep -q '^${Le_Deploy_haproxy_pem_path} $'"
340+ _debug _socat_crtlist_show_cmd " ${_socat_crtlist_show_cmd} "
341+ eval " ${_socat_crtlist_show_cmd} "
342+ _ret=$?
343+ if [ " ${_ret} " != " 0" ]; then
344+ _err " Couldn't find '${Le_Deploy_haproxy_pem_path} ' in haproxy 'show ssl crt-list'"
345+ return " ${_ret} "
346+ fi
347+ # create a new certificate
348+ _socat_new_cmd=" echo '${_cmdpfx} new ssl cert ${_pem} ' | socat '${_statssock} ' - | grep -q 'New empty'"
349+ _debug _socat_new_cmd " ${_socat_new_cmd} "
350+ eval " ${_socat_new_cmd} "
351+ _ret=$?
352+ if [ " ${_ret} " != " 0" ]; then
353+ _err " Couldn't create '${_pem} ' in haproxy"
354+ return " ${_ret} "
355+ fi
356+ else
357+ _info " Update existing certificate '${_pem} ' over HAProxy ${_socketname} ."
358+ fi
359+ _socat_cert_set_cmd=" echo -e '${_cmdpfx} set ssl cert ${_pem} <<\n$( cat " ${_pem} " ) \n' | socat '${_statssock} ' - | grep -q 'Transaction created'"
360+ _debug _socat_cert_set_cmd " ${_socat_cert_set_cmd} "
361+ eval " ${_socat_cert_set_cmd} "
362+ _ret=$?
363+ if [ " ${_ret} " != " 0" ]; then
364+ _err " Can't update '${_pem} ' in haproxy"
365+ return " ${_ret} "
366+ fi
367+ _socat_cert_commit_cmd=" echo '${_cmdpfx} commit ssl cert ${_pem} ' | socat '${_statssock} ' - | grep -q '^Success!$'"
368+ _debug _socat_cert_commit_cmd " ${_socat_cert_commit_cmd} "
369+ eval " ${_socat_cert_commit_cmd} "
370+ _ret=$?
371+ if [ " ${_ret} " != " 0" ]; then
372+ _err " Can't commit '${_pem} ' in haproxy"
373+ return ${_ret}
374+ fi
375+ if [ " ${_newcert} " = " 1" ]; then
376+ # if this is a new certificate, it needs to be inserted into the crt-list`
377+ _socat_cert_add_cmd=" echo '${_cmdpfx} add ssl crt-list ${Le_Deploy_haproxy_pem_path} ${_pem} ' | socat '${_statssock} ' - | grep -q 'Success!'"
378+ _debug _socat_cert_add_cmd " ${_socat_cert_add_cmd} "
379+ eval " ${_socat_cert_add_cmd} "
380+ _ret=$?
381+ if [ " ${_ret} " != " 0" ]; then
382+ _err " Can't update '${_pem} ' in haproxy"
383+ return " ${_ret} "
384+ fi
385+ fi
386+ else
387+ _err " 'socat' is not available, couldn't update over ${_socketname} "
388+ fi
275389 else
276- _info " Reload successful"
390+ # Reload HAProxy
391+ _debug _reload " ${_reload} "
392+ eval " ${_reload} "
393+ _ret=$?
394+ if [ " ${_ret} " != " 0" ]; then
395+ _err " Error code ${_ret} during reload"
396+ return ${_ret}
397+ else
398+ _info " Reload successful"
399+ fi
277400 fi
278401
279402 return 0
0 commit comments