@@ -16,19 +16,22 @@ LOCAL_CA_CRT_DIR="${LOCAL_CA_DIR}/new_certs"
16
16
17
17
info " Starting certificate renewal process with local CA"
18
18
19
+ # Load some configuration from file with environment variables as fallback
20
+ CONFIG_FILE=" ${NGINX_CERTBOT_CONFIG_FILE:-/ etc/ nginx-certbot/ config.yml} "
21
+ if [ -f " ${CONFIG_FILE} " ]; then
22
+ certbot_email=" $( shyaml get-value certbot.email ' ' < " ${CONFIG_FILE} " ) "
23
+ certbot_rsa_key_size=" $( shyaml get-value certbot.rsa-key-size ' ' < " ${CONFIG_FILE} " ) "
24
+ fi
25
+ : " ${certbot_email:= ${CERTBOT_EMAIL} } "
26
+ : " ${certbot_rsa_key_size:= ${RSA_KEY_SIZE:- 2048} } "
27
+
19
28
# We require an email to be set here as well, in order to simulate how it would
20
29
# be in the real certbot case.
21
- if [ -z " ${CERTBOT_EMAIL } " ]; then
22
- error " CERTBOT_EMAIL environment variable undefined; local CA will do nothing!"
30
+ if [ -z " ${certbot_email } " ]; then
31
+ error " certbot.email or CERTBOT_EMAIL environment variable must be set; without it certbot will do nothing!"
23
32
exit 1
24
33
fi
25
34
26
- # Ensure that an RSA key size is set.
27
- if [ -z " ${RSA_KEY_SIZE} " ]; then
28
- debug " RSA_KEY_SIZE unset, defaulting to 2048"
29
- RSA_KEY_SIZE=2048
30
- fi
31
-
32
35
# This is an OpenSSL configuration file that has settings for creating a well
33
36
# configured CA, as well as server certificates that adhere to the strict
34
37
# standards of web browsers. This is not complete, but will have the missing
@@ -111,7 +114,7 @@ generate_ca() {
111
114
# Make sure there is a private key available for the CA.
112
115
if [ ! -f " ${LOCAL_CA_KEY} " ]; then
113
116
info " Generating new private key for local CA"
114
- openssl genrsa -out " ${LOCAL_CA_KEY} " " ${RSA_KEY_SIZE } "
117
+ openssl genrsa -out " ${LOCAL_CA_KEY} " " ${certbot_rsa_key_size } "
115
118
fi
116
119
117
120
# Make sure there exists a self-signed certificate for the CA.
@@ -136,7 +139,7 @@ generate_ca() {
136
139
" 0.organizationName = github.com/JonasAlfredsson" \
137
140
" organizationalUnitName = docker-nginx-certbot" \
138
141
" commonName = Local Debug CA" \
139
- " emailAddress = ${CERTBOT_EMAIL } " \
142
+ " emailAddress = ${certbot_email } " \
140
143
) \
141
144
-extensions ca_cert \
142
145
-days " ${LOCAL_CA_ROOT_CERT_VALIDITY} " \
@@ -177,15 +180,15 @@ get_certificate() {
177
180
# It is good practice to generate a new key every time a new certificate is
178
181
# requested, in order to guard against potential key compromises.
179
182
info " Generating new private key for '${cert_name} '"
180
- openssl genrsa -out " /etc/letsencrypt/live/${cert_name} /privkey.pem" " ${RSA_KEY_SIZE } "
183
+ openssl genrsa -out " /etc/letsencrypt/live/${cert_name} /privkey.pem" " ${certbot_rsa_key_size } "
181
184
182
185
# Create a certificate signing request from the private key.
183
186
info " Generating certificate signing request for '${cert_name} '"
184
187
openssl req -new -config <( printf " %s\n" \
185
188
" ${openssl_cnf} " \
186
189
" [ dn_section ]" \
187
190
" commonName = ${cert_name} " \
188
- " emailAddress = ${CERTBOT_EMAIL } " \
191
+ " emailAddress = ${certbot_email } " \
189
192
) \
190
193
-key " /etc/letsencrypt/live/${cert_name} /privkey.pem" \
191
194
-out " ${LOCAL_CA_DIR} /${cert_name} .csr"
@@ -217,42 +220,79 @@ get_certificate() {
217
220
# time this script is invoked.
218
221
generate_ca
219
222
220
- # Get all the cert names for which we should create certificates for, along
221
- # with the corresponding server names.
222
- #
223
- # This will return an associative array that looks something like this:
224
- # "cert_name" => "server_name1 server_name2"
225
- declare -A certificates
226
- for conf_file in /etc/nginx/conf.d/* .conf* ; do
227
- parse_config_file " ${conf_file} " certificates
228
- done
229
-
230
- # Iterate over each key and create a signed certificate for them.
231
- for cert_name in " ${! certificates[@]} " ; do
232
- server_names=(${certificates["$cert_name"]} )
233
-
234
- # Assemble the list of domains to be included in the request.
235
- ip_count=0
236
- dns_count=0
237
- alt_names=()
223
+ # Assemble the list of domains to be included in the request.
224
+ # $@: All domain name variants
225
+ assemble_alt_names () {
226
+ local server_names=(" ${@ } " )
227
+ local ip_count=0
228
+ local dns_count=0
229
+ local alt_names=()
238
230
for server_name in " ${server_names[@]} " ; do
239
231
if is_ip " ${server_name} " ; then
240
232
# See if the alt name looks like an IP address.
241
- ip_count=$(( ${ ip_count} + 1 ))
233
+ ip_count=$(( ip_count + 1 ))
242
234
alt_names+=(" IP.${ip_count} =${server_name} " )
243
235
else
244
236
# Else we suppose this is a valid DNS name.
245
- dns_count=$(( ${ dns_count} + 1 ))
237
+ dns_count=$(( dns_count + 1 ))
246
238
alt_names+=(" DNS.${dns_count} =${server_name} " )
247
239
fi
248
240
done
241
+ echo " ${alt_names[@]} "
242
+ }
249
243
250
- # Hand over all the info required for the certificate request, and
251
- # let the local CA handle the rest.
252
- if ! get_certificate " ${cert_name} " " ${alt_names[@]} " ; then
253
- error " Local CA failed for '${cert_name} '. Check the logs for details."
254
- fi
255
- done
244
+ # Get all the cert names for which we should create certificates for, along
245
+ # with the corresponding server names.
246
+ if [ -f " ${CONFIG_FILE} " ] && shyaml -q get-value certificates < " ${CONFIG_FILE} " ; then
247
+ debug " Using config file '${CONFIG_FILE} ' for certificate specifications"
248
+ # Loop over the certificates array and request the certificates
249
+ while read -r -d ' ' cert; do
250
+ debug " Parsing certificate specification"
251
+ cert_name=" $( shyaml get-value name ' ' <<< " ${cert}" ) "
252
+ if [ -z " ${cert_name} " ]; then
253
+ error " 'name' is missing; ignoring this certificate specification"
254
+ continue
255
+ fi
256
+ debug " Certificate name is: ${cert_name} "
257
+ domains=()
258
+ while read -r -d ' ' domain; do
259
+ domains+=(" ${domain} " )
260
+ done < <( shyaml get-values-0 domains ' ' <<< " ${cert}" )
261
+ if [ " ${# domains[@]} " -eq 0 ]; then
262
+ error " 'domains' are missing; ignoring this certificate specification"
263
+ continue
264
+ fi
265
+ debug " Certificate domains are is: ${domains[*]} "
266
+
267
+ # Assemble the list of domains to be included in the request.
268
+ read -ra alt_names < <( assemble_alt_names " ${domains[@]} " )
269
+ # Hand over all the info required for the certificate request, and
270
+ # let the local CA handle the rest.
271
+ if ! get_certificate " ${cert_name} " " ${alt_names[@]} " ; then
272
+ error " Local CA failed for '${cert_name} '. Check the logs for details."
273
+ fi
274
+ done < <( shyaml -y get-values-0 certificates ' ' < " ${CONFIG_FILE} " )
275
+ else
276
+ debug " Using automatic discovery of nginx conf file for certificate specifications"
277
+ # This will return an associative array that looks something like this:
278
+ # "cert_name" => "server_name1 server_name2"
279
+ declare -A certificates
280
+ for conf_file in /etc/nginx/conf.d/* .conf* ; do
281
+ parse_config_file " ${conf_file} " certificates
282
+ done
283
+
284
+ # Iterate over each key and create a signed certificate for them.
285
+ for cert_name in " ${! certificates[@]} " ; do
286
+ server_names=(" ${certificates["$cert_name"]} " )
287
+ # Assemble the list of domains to be included in the request.
288
+ read -ra alt_names < <( assemble_alt_names " ${server_names[@]} " )
289
+ # Hand over all the info required for the certificate request, and
290
+ # let the local CA handle the rest.
291
+ if ! get_certificate " ${cert_name} " " ${alt_names[@]} " ; then
292
+ error " Local CA failed for '${cert_name} '. Check the logs for details."
293
+ fi
294
+ done
295
+ fi
256
296
257
297
# After trying to sign all of the certificates, auto enable any configs that we
258
298
# did indeed succeed with.
0 commit comments