]>
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 | |
6567bb4c | 57 | _debug _cdomain "${_cdomain}" |
58 | _debug _ckey "${_ckey}" | |
59 | _debug _ccert "${_ccert}" | |
60 | _debug _cca "${_cca}" | |
61 | _debug _cfullchain "${_cfullchain}" | |
62 | ||
ba20af48 | 63 | # PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" |
c43c711f GS |
64 | _getdeployconf DEPLOY_HAPROXY_PEM_PATH |
65 | _debug2 DEPLOY_HAPROXY_PEM_PATH "${DEPLOY_HAPROXY_PEM_PATH}" | |
ba20af48 | 66 | if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then |
67 | Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}" | |
68 | _savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}" | |
69 | elif [ -z "${Le_Deploy_haproxy_pem_path}" ]; then | |
70 | Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" | |
71 | fi | |
72 | ||
73 | # Ensure PEM_PATH exists | |
74 | if [ -d "${Le_Deploy_haproxy_pem_path}" ]; then | |
75 | _debug "PEM_PATH ${Le_Deploy_haproxy_pem_path} exists" | |
6567bb4c | 76 | else |
ba20af48 | 77 | _err "PEM_PATH ${Le_Deploy_haproxy_pem_path} does not exist" |
78 | return 1 | |
79 | fi | |
80 | ||
81 | # PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" | |
c43c711f GS |
82 | _getdeployconf DEPLOY_HAPROXY_PEM_NAME |
83 | _debug2 DEPLOY_HAPROXY_PEM_NAME "${DEPLOY_HAPROXY_PEM_NAME}" | |
ba20af48 | 84 | if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then |
85 | Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}" | |
86 | _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}" | |
87 | elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then | |
88 | Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" | |
6567bb4c | 89 | fi |
90 | ||
91 | # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" | |
c43c711f GS |
92 | _getdeployconf DEPLOY_HAPROXY_BUNDLE |
93 | _debug2 DEPLOY_HAPROXY_BUNDLE "${DEPLOY_HAPROXY_BUNDLE}" | |
6567bb4c | 94 | if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then |
95 | Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}" | |
96 | _savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}" | |
97 | elif [ -z "${Le_Deploy_haproxy_bundle}" ]; then | |
98 | Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" | |
99 | fi | |
100 | ||
101 | # ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}" | |
c43c711f GS |
102 | _getdeployconf DEPLOY_HAPROXY_ISSUER |
103 | _debug2 DEPLOY_HAPROXY_ISSUER "${DEPLOY_HAPROXY_ISSUER}" | |
6567bb4c | 104 | if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then |
105 | Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}" | |
106 | _savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}" | |
107 | elif [ -z "${Le_Deploy_haproxy_issuer}" ]; then | |
108 | Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER_DEFAULT}" | |
109 | fi | |
110 | ||
111 | # RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}" | |
c43c711f GS |
112 | _getdeployconf DEPLOY_HAPROXY_RELOAD |
113 | _debug2 DEPLOY_HAPROXY_RELOAD "${DEPLOY_HAPROXY_RELOAD}" | |
6567bb4c | 114 | if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then |
115 | Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}" | |
116 | _savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}" | |
117 | elif [ -z "${Le_Deploy_haproxy_reload}" ]; then | |
118 | Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}" | |
119 | fi | |
120 | ||
121 | # Set the suffix depending if we are creating a bundle or not | |
122 | if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then | |
123 | _info "Bundle creation requested" | |
733b4e0a | 124 | # Initialise $Le_Keylength if its not already set |
125 | if [ -z "${Le_Keylength}" ]; then | |
126 | Le_Keylength="" | |
6567bb4c | 127 | fi |
733b4e0a | 128 | if _isEccKey "${Le_Keylength}"; then |
7d19d784 | 129 | _info "ECC key type detected" |
130 | _suffix=".ecdsa" | |
6567bb4c | 131 | else |
7d19d784 | 132 | _info "RSA key type detected" |
6567bb4c | 133 | _suffix=".rsa" |
134 | fi | |
e9e99954 | 135 | else |
6567bb4c | 136 | _suffix="" |
137 | fi | |
7d19d784 | 138 | _debug _suffix "${_suffix}" |
6567bb4c | 139 | |
140 | # Set variables for later | |
ba20af48 | 141 | _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}" |
6567bb4c | 142 | _issuer="${_pem}.issuer" |
143 | _ocsp="${_pem}.ocsp" | |
144 | _reload="${Le_Deploy_haproxy_reload}" | |
145 | ||
146 | _info "Deploying PEM file" | |
147 | # Create a temporary PEM file | |
148 | _temppem="$(_mktemp)" | |
149 | _debug _temppem "${_temppem}" | |
707e0539 | 150 | cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}" |
6567bb4c | 151 | _ret="$?" |
152 | ||
153 | # Check that we could create the temporary file | |
154 | if [ "${_ret}" != "0" ]; then | |
155 | _err "Error code ${_ret} returned during PEM file creation" | |
156 | [ -f "${_temppem}" ] && rm -f "${_temppem}" | |
157 | return ${_ret} | |
158 | fi | |
159 | ||
160 | # Move PEM file into place | |
161 | _info "Moving new certificate into place" | |
162 | _debug _pem "${_pem}" | |
707e0539 | 163 | cat "${_temppem}" >"${_pem}" |
6567bb4c | 164 | _ret=$? |
165 | ||
166 | # Clean up temp file | |
167 | [ -f "${_temppem}" ] && rm -f "${_temppem}" | |
168 | ||
169 | # Deal with any failure of moving PEM file into place | |
170 | if [ "${_ret}" != "0" ]; then | |
171 | _err "Error code ${_ret} returned while moving new certificate into place" | |
172 | return ${_ret} | |
173 | fi | |
174 | ||
175 | # Update .issuer file if requested | |
176 | if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then | |
177 | _info "Updating .issuer file" | |
178 | _debug _issuer "${_issuer}" | |
707e0539 | 179 | cat "${_cca}" >"${_issuer}" |
6567bb4c | 180 | _ret="$?" |
181 | ||
182 | if [ "${_ret}" != "0" ]; then | |
183 | _err "Error code ${_ret} returned while copying issuer/CA certificate into place" | |
184 | return ${_ret} | |
185 | fi | |
186 | else | |
1a126b70 | 187 | [ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists" |
6567bb4c | 188 | fi |
189 | ||
190 | # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option | |
191 | if [ -z "${Le_OCSP_Staple}" ]; then | |
192 | Le_OCSP_Staple="0" | |
193 | fi | |
194 | if [ "${Le_OCSP_Staple}" = "1" ]; then | |
195 | _info "Updating OCSP stapling info" | |
196 | _debug _ocsp "${_ocsp}" | |
197 | _info "Extracting OCSP URL" | |
8419b42e | 198 | _ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}") |
6567bb4c | 199 | _debug _ocsp_url "${_ocsp_url}" |
200 | ||
201 | # Only process OCSP if URL was present | |
202 | if [ "${_ocsp_url}" != "" ]; then | |
203 | # Extract the hostname from the OCSP URL | |
204 | _info "Extracting OCSP URL" | |
205 | _ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3) | |
206 | _debug _ocsp_host "${_ocsp_host}" | |
207 | ||
208 | # Only process the certificate if we have a .issuer file | |
209 | if [ -r "${_issuer}" ]; then | |
210 | # Check if issuer cert is also a root CA cert | |
8419b42e | 211 | _subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) |
6567bb4c | 212 | _debug _subjectdn "${_subjectdn}" |
8419b42e | 213 | _issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) |
6567bb4c | 214 | _debug _issuerdn "${_issuerdn}" |
215 | _info "Requesting OCSP response" | |
e184a1b9 | 216 | # If the issuer is a CA cert then our command line has "-CAfile" added |
6567bb4c | 217 | if [ "${_subjectdn}" = "${_issuerdn}" ]; then |
e184a1b9 | 218 | _cafile_argument="-CAfile \"${_issuer}\"" |
219 | else | |
220 | _cafile_argument="" | |
221 | fi | |
222 | _debug _cafile_argument "${_cafile_argument}" | |
223 | # if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed | |
8419b42e | 224 | _openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2) |
e184a1b9 | 225 | _debug _openssl_version "${_openssl_version}" |
226 | _openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1) | |
227 | _openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2) | |
228 | if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then | |
229 | _header_sep="=" | |
6567bb4c | 230 | else |
e184a1b9 | 231 | _header_sep=" " |
6567bb4c | 232 | fi |
e184a1b9 | 233 | # Request the OCSP response from the issuer and store it |
8419b42e | 234 | _openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \ |
e184a1b9 | 235 | -issuer \"${_issuer}\" \ |
236 | -cert \"${_pem}\" \ | |
237 | -url \"${_ocsp_url}\" \ | |
238 | -header Host${_header_sep}\"${_ocsp_host}\" \ | |
239 | -respout \"${_ocsp}\" \ | |
240 | -verify_other \"${_issuer}\" \ | |
e184a1b9 | 241 | ${_cafile_argument} \ |
242 | | grep -q \"${_pem}: good\"" | |
243 | _debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}" | |
244 | eval "${_openssl_ocsp_cmd}" | |
245 | _ret=$? | |
6567bb4c | 246 | else |
247 | # Non fatal: No issuer file was present so no OCSP stapling file created | |
248 | _err "OCSP stapling in use but no .issuer file was present" | |
249 | fi | |
250 | else | |
251 | # Non fatal: No OCSP url was found int the certificate | |
252 | _err "OCSP update requested but no OCSP URL was found in certificate" | |
253 | fi | |
254 | ||
7d19d784 | 255 | # Non fatal: Check return code of openssl command |
6567bb4c | 256 | if [ "${_ret}" != "0" ]; then |
707e0539 | 257 | _err "Updating OCSP stapling failed with return code ${_ret}" |
6567bb4c | 258 | fi |
259 | else | |
260 | # An OCSP file was already present but certificate did not have OCSP extension | |
261 | if [ -f "${_ocsp}" ]; then | |
262 | _err "OCSP was not requested but .ocsp file exists." | |
31d9ba7e | 263 | # Could remove the file at this step, although HAProxy just ignores it in this case |
6567bb4c | 264 | # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file" |
707e0539 | 265 | fi |
6567bb4c | 266 | fi |
267 | ||
268 | # Reload HAProxy | |
269 | _debug _reload "${_reload}" | |
270 | eval "${_reload}" | |
271 | _ret=$? | |
272 | if [ "${_ret}" != "0" ]; then | |
6567bb4c | 273 | _err "Error code ${_ret} during reload" |
274 | return ${_ret} | |
08d29a83 | 275 | else |
276 | _info "Reload successful" | |
e9e99954 | 277 | fi |
f845b371 | 278 | |
6567bb4c | 279 | return 0 |
f845b371 | 280 | } |