]> git.proxmox.com Git - mirror_acme.sh.git/blame - deploy/haproxy.sh
Merge pull request #3553 from acmesh-official/dev
[mirror_acme.sh.git] / deploy / haproxy.sh
CommitLineData
f845b371 1#!/usr/bin/env sh
2
6567bb4c 3# Script for acme.sh to deploy certificates to haproxy
4#
5# The following variables can be exported:
6#
ba20af48 7# export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem"
6567bb4c 8#
ba20af48 9# Defines the name of the PEM file.
454c9082 10# Defaults to "<domain>.pem"
ba20af48 11#
12# export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy"
13#
14# Defines location of PEM file for HAProxy.
15# Defaults to /etc/haproxy
6567bb4c 16#
17# export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy"
18#
19# OPTIONAL: Reload command used post deploy
31d9ba7e 20# This defaults to be a no-op (ie "true").
21# It is strongly recommended to set this something that makes sense
22# for your distro.
6567bb4c 23#
24# export DEPLOY_HAPROXY_ISSUER="no"
25#
26# OPTIONAL: Places CA file as "${DEPLOY_HAPROXY_PEM}.issuer"
27# Note: Required for OCSP stapling to work
28#
29# export DEPLOY_HAPROXY_BUNDLE="no"
30#
31# OPTIONAL: Deploy this certificate as part of a multi-cert bundle
32# This adds a suffix to the certificate based on the certificate type
33# eg RSA certificates will have .rsa as a suffix to the file name
34# HAProxy will load all certificates and provide one or the other
35# depending on client capabilities
36# Note: This functionality requires HAProxy was compiled against
37# a version of OpenSSL that supports this.
38#
f845b371 39
40######## Public functions #####################
41
42#domain keyfile certfile cafile fullchain
43haproxy_deploy() {
44 _cdomain="$1"
45 _ckey="$2"
46 _ccert="$3"
47 _cca="$4"
48 _cfullchain="$5"
49
6567bb4c 50 # Some defaults
ba20af48 51 DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
52 DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem"
6567bb4c 53 DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
54 DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
454c9082 55 DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
6567bb4c 56
57 if [ -f "${DOMAIN_CONF}" ]; then
58 # shellcheck disable=SC1090
59 . "${DOMAIN_CONF}"
60 fi
61
62 _debug _cdomain "${_cdomain}"
63 _debug _ckey "${_ckey}"
64 _debug _ccert "${_ccert}"
65 _debug _cca "${_cca}"
66 _debug _cfullchain "${_cfullchain}"
67
ba20af48 68 # PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
69 if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
70 Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
71 _savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
72 elif [ -z "${Le_Deploy_haproxy_pem_path}" ]; then
73 Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
74 fi
75
76 # Ensure PEM_PATH exists
77 if [ -d "${Le_Deploy_haproxy_pem_path}" ]; then
78 _debug "PEM_PATH ${Le_Deploy_haproxy_pem_path} exists"
6567bb4c 79 else
ba20af48 80 _err "PEM_PATH ${Le_Deploy_haproxy_pem_path} does not exist"
81 return 1
82 fi
83
84 # PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
85 if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
86 Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
87 _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
88 elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
89 Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
6567bb4c 90 fi
91
92 # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
93 if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
94 Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
95 _savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
96 elif [ -z "${Le_Deploy_haproxy_bundle}" ]; then
97 Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
98 fi
99
100 # ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
101 if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
102 Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
103 _savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
104 elif [ -z "${Le_Deploy_haproxy_issuer}" ]; then
105 Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
106 fi
107
108 # RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
109 if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
110 Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
111 _savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
112 elif [ -z "${Le_Deploy_haproxy_reload}" ]; then
113 Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
114 fi
115
116 # Set the suffix depending if we are creating a bundle or not
117 if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
118 _info "Bundle creation requested"
733b4e0a 119 # Initialise $Le_Keylength if its not already set
120 if [ -z "${Le_Keylength}" ]; then
121 Le_Keylength=""
6567bb4c 122 fi
733b4e0a 123 if _isEccKey "${Le_Keylength}"; then
7d19d784 124 _info "ECC key type detected"
125 _suffix=".ecdsa"
6567bb4c 126 else
7d19d784 127 _info "RSA key type detected"
6567bb4c 128 _suffix=".rsa"
129 fi
e9e99954 130 else
6567bb4c 131 _suffix=""
132 fi
7d19d784 133 _debug _suffix "${_suffix}"
6567bb4c 134
135 # Set variables for later
ba20af48 136 _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}"
6567bb4c 137 _issuer="${_pem}.issuer"
138 _ocsp="${_pem}.ocsp"
139 _reload="${Le_Deploy_haproxy_reload}"
140
141 _info "Deploying PEM file"
142 # Create a temporary PEM file
143 _temppem="$(_mktemp)"
144 _debug _temppem "${_temppem}"
707e0539 145 cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
6567bb4c 146 _ret="$?"
147
148 # Check that we could create the temporary file
149 if [ "${_ret}" != "0" ]; then
150 _err "Error code ${_ret} returned during PEM file creation"
151 [ -f "${_temppem}" ] && rm -f "${_temppem}"
152 return ${_ret}
153 fi
154
155 # Move PEM file into place
156 _info "Moving new certificate into place"
157 _debug _pem "${_pem}"
707e0539 158 cat "${_temppem}" >"${_pem}"
6567bb4c 159 _ret=$?
160
161 # Clean up temp file
162 [ -f "${_temppem}" ] && rm -f "${_temppem}"
163
164 # Deal with any failure of moving PEM file into place
165 if [ "${_ret}" != "0" ]; then
166 _err "Error code ${_ret} returned while moving new certificate into place"
167 return ${_ret}
168 fi
169
170 # Update .issuer file if requested
171 if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then
172 _info "Updating .issuer file"
173 _debug _issuer "${_issuer}"
707e0539 174 cat "${_cca}" >"${_issuer}"
6567bb4c 175 _ret="$?"
176
177 if [ "${_ret}" != "0" ]; then
178 _err "Error code ${_ret} returned while copying issuer/CA certificate into place"
179 return ${_ret}
180 fi
181 else
1a126b70 182 [ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists"
6567bb4c 183 fi
184
185 # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option
186 if [ -z "${Le_OCSP_Staple}" ]; then
187 Le_OCSP_Staple="0"
188 fi
189 if [ "${Le_OCSP_Staple}" = "1" ]; then
190 _info "Updating OCSP stapling info"
191 _debug _ocsp "${_ocsp}"
192 _info "Extracting OCSP URL"
193 _ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}")
194 _debug _ocsp_url "${_ocsp_url}"
195
196 # Only process OCSP if URL was present
197 if [ "${_ocsp_url}" != "" ]; then
198 # Extract the hostname from the OCSP URL
199 _info "Extracting OCSP URL"
200 _ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3)
201 _debug _ocsp_host "${_ocsp_host}"
202
203 # Only process the certificate if we have a .issuer file
204 if [ -r "${_issuer}" ]; then
205 # Check if issuer cert is also a root CA cert
206 _subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
207 _debug _subjectdn "${_subjectdn}"
208 _issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
209 _debug _issuerdn "${_issuerdn}"
210 _info "Requesting OCSP response"
e184a1b9 211 # If the issuer is a CA cert then our command line has "-CAfile" added
6567bb4c 212 if [ "${_subjectdn}" = "${_issuerdn}" ]; then
e184a1b9 213 _cafile_argument="-CAfile \"${_issuer}\""
214 else
215 _cafile_argument=""
216 fi
217 _debug _cafile_argument "${_cafile_argument}"
218 # if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
219 _openssl_version=$(openssl version | cut -d' ' -f2)
220 _debug _openssl_version "${_openssl_version}"
221 _openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
222 _openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
223 if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then
224 _header_sep="="
6567bb4c 225 else
e184a1b9 226 _header_sep=" "
6567bb4c 227 fi
e184a1b9 228 # Request the OCSP response from the issuer and store it
229 _openssl_ocsp_cmd="openssl ocsp \
230 -issuer \"${_issuer}\" \
231 -cert \"${_pem}\" \
232 -url \"${_ocsp_url}\" \
233 -header Host${_header_sep}\"${_ocsp_host}\" \
234 -respout \"${_ocsp}\" \
235 -verify_other \"${_issuer}\" \
e184a1b9 236 ${_cafile_argument} \
237 | grep -q \"${_pem}: good\""
238 _debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
239 eval "${_openssl_ocsp_cmd}"
240 _ret=$?
6567bb4c 241 else
242 # Non fatal: No issuer file was present so no OCSP stapling file created
243 _err "OCSP stapling in use but no .issuer file was present"
244 fi
245 else
246 # Non fatal: No OCSP url was found int the certificate
247 _err "OCSP update requested but no OCSP URL was found in certificate"
248 fi
249
7d19d784 250 # Non fatal: Check return code of openssl command
6567bb4c 251 if [ "${_ret}" != "0" ]; then
707e0539 252 _err "Updating OCSP stapling failed with return code ${_ret}"
6567bb4c 253 fi
254 else
255 # An OCSP file was already present but certificate did not have OCSP extension
256 if [ -f "${_ocsp}" ]; then
257 _err "OCSP was not requested but .ocsp file exists."
31d9ba7e 258 # Could remove the file at this step, although HAProxy just ignores it in this case
6567bb4c 259 # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
707e0539 260 fi
6567bb4c 261 fi
262
263 # Reload HAProxy
264 _debug _reload "${_reload}"
265 eval "${_reload}"
266 _ret=$?
267 if [ "${_ret}" != "0" ]; then
6567bb4c 268 _err "Error code ${_ret} during reload"
269 return ${_ret}
08d29a83 270 else
271 _info "Reload successful"
e9e99954 272 fi
f845b371 273
6567bb4c 274 return 0
f845b371 275}