36
36
# Note: This functionality requires HAProxy was compiled against
37
37
# a version of OpenSSL that supports this.
38
38
#
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.
39
52
40
53
# ####### Public functions #####################
41
54
@@ -46,13 +59,16 @@ haproxy_deploy() {
46
59
_ccert=" $3 "
47
60
_cca=" $4 "
48
61
_cfullchain=" $5 "
62
+ _cmdpfx=" "
49
63
50
64
# Some defaults
51
65
DEPLOY_HAPROXY_PEM_PATH_DEFAULT=" /etc/haproxy"
52
66
DEPLOY_HAPROXY_PEM_NAME_DEFAULT=" ${_cdomain} .pem"
53
67
DEPLOY_HAPROXY_BUNDLE_DEFAULT=" no"
54
68
DEPLOY_HAPROXY_ISSUER_DEFAULT=" no"
55
69
DEPLOY_HAPROXY_RELOAD_DEFAULT=" true"
70
+ DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT=" no"
71
+ DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT=" UNIX:/run/haproxy/admin.sock"
56
72
57
73
_debug _cdomain " ${_cdomain} "
58
74
_debug _ckey " ${_ckey} "
@@ -86,6 +102,11 @@ haproxy_deploy() {
86
102
_savedomainconf Le_Deploy_haproxy_pem_name " ${Le_Deploy_haproxy_pem_name} "
87
103
elif [ -z " ${Le_Deploy_haproxy_pem_name} " ]; then
88
104
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
89
110
fi
90
111
91
112
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
@@ -118,6 +139,36 @@ haproxy_deploy() {
118
139
Le_Deploy_haproxy_reload=" ${DEPLOY_HAPROXY_RELOAD_DEFAULT} "
119
140
fi
120
141
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
+
121
172
# Set the suffix depending if we are creating a bundle or not
122
173
if [ " ${Le_Deploy_haproxy_bundle} " = " yes" ]; then
123
174
_info " Bundle creation requested"
@@ -142,12 +193,13 @@ haproxy_deploy() {
142
193
_issuer=" ${_pem} .issuer"
143
194
_ocsp=" ${_pem} .ocsp"
144
195
_reload=" ${Le_Deploy_haproxy_reload} "
196
+ _statssock=" ${Le_Deploy_haproxy_stats_socket} "
145
197
146
198
_info " Deploying PEM file"
147
199
# Create a temporary PEM file
148
200
_temppem=" $( _mktemp) "
149
201
_debug _temppem " ${_temppem} "
150
- cat " ${_ccert} " " ${_cca} " " ${_ckey} " > " ${_temppem} "
202
+ cat " ${_ccert} " " ${_cca} " " ${_ckey} " | grep . > " ${_temppem} "
151
203
_ret=" $? "
152
204
153
205
# Check that we could create the temporary file
@@ -265,15 +317,86 @@ haproxy_deploy() {
265
317
fi
266
318
fi
267
319
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
275
389
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
277
400
fi
278
401
279
402
return 0
0 commit comments