]> git.proxmox.com Git - mirror_acme.sh.git/blob - deploy/haproxy.sh
fix #2830 Autorization segment typo fixed
[mirror_acme.sh.git] / deploy / haproxy.sh
1 #!/usr/bin/env sh
2
3 # Script for acme.sh to deploy certificates to haproxy
4 #
5 # The following variables can be exported:
6 #
7 # export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem"
8 #
9 # Defines the name of the PEM file.
10 # Defaults to "<domain>.pem"
11 #
12 # export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy"
13 #
14 # Defines location of PEM file for HAProxy.
15 # Defaults to /etc/haproxy
16 #
17 # export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy"
18 #
19 # OPTIONAL: Reload command used post deploy
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.
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 #
39
40 ######## Public functions #####################
41
42 #domain keyfile certfile cafile fullchain
43 haproxy_deploy() {
44 _cdomain="$1"
45 _ckey="$2"
46 _ccert="$3"
47 _cca="$4"
48 _cfullchain="$5"
49
50 # Some defaults
51 DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
52 DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem"
53 DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
54 DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
55 DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
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
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"
79 else
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}"
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"
119 # Initialise $Le_Keylength if its not already set
120 if [ -z "${Le_Keylength}" ]; then
121 Le_Keylength=""
122 fi
123 if _isEccKey "${Le_Keylength}"; then
124 _info "ECC key type detected"
125 _suffix=".ecdsa"
126 else
127 _info "RSA key type detected"
128 _suffix=".rsa"
129 fi
130 else
131 _suffix=""
132 fi
133 _debug _suffix "${_suffix}"
134
135 # Set variables for later
136 _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}"
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}"
145 cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
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}"
158 cat "${_temppem}" >"${_pem}"
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}"
174 cat "${_cca}" >"${_issuer}"
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
182 [ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists"
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"
211 # If the issuer is a CA cert then our command line has "-CAfile" added
212 if [ "${_subjectdn}" = "${_issuerdn}" ]; then
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="="
225 else
226 _header_sep=" "
227 fi
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}\" \
236 -no_nonce \
237 ${_cafile_argument} \
238 | grep -q \"${_pem}: good\""
239 _debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
240 eval "${_openssl_ocsp_cmd}"
241 _ret=$?
242 else
243 # Non fatal: No issuer file was present so no OCSP stapling file created
244 _err "OCSP stapling in use but no .issuer file was present"
245 fi
246 else
247 # Non fatal: No OCSP url was found int the certificate
248 _err "OCSP update requested but no OCSP URL was found in certificate"
249 fi
250
251 # Non fatal: Check return code of openssl command
252 if [ "${_ret}" != "0" ]; then
253 _err "Updating OCSP stapling failed with return code ${_ret}"
254 fi
255 else
256 # An OCSP file was already present but certificate did not have OCSP extension
257 if [ -f "${_ocsp}" ]; then
258 _err "OCSP was not requested but .ocsp file exists."
259 # Could remove the file at this step, although HAProxy just ignores it in this case
260 # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
261 fi
262 fi
263
264 # Reload HAProxy
265 _debug _reload "${_reload}"
266 eval "${_reload}"
267 _ret=$?
268 if [ "${_ret}" != "0" ]; then
269 _err "Error code ${_ret} during reload"
270 return ${_ret}
271 else
272 _info "Reload successful"
273 fi
274
275 return 0
276 }