]>
Commit | Line | Data |
---|---|---|
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 | |
43 | haproxy_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 | } |