@@ -16,19 +16,22 @@ LOCAL_CA_CRT_DIR="${LOCAL_CA_DIR}/new_certs"
1616
1717info " Starting certificate renewal process with local CA"
1818
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+
1928# We require an email to be set here as well, in order to simulate how it would
2029# 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!"
2332 exit 1
2433fi
2534
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-
3235# This is an OpenSSL configuration file that has settings for creating a well
3336# configured CA, as well as server certificates that adhere to the strict
3437# standards of web browsers. This is not complete, but will have the missing
@@ -111,7 +114,7 @@ generate_ca() {
111114 # Make sure there is a private key available for the CA.
112115 if [ ! -f " ${LOCAL_CA_KEY} " ]; then
113116 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 } "
115118 fi
116119
117120 # Make sure there exists a self-signed certificate for the CA.
@@ -136,7 +139,7 @@ generate_ca() {
136139 " 0.organizationName = github.com/JonasAlfredsson" \
137140 " organizationalUnitName = docker-nginx-certbot" \
138141 " commonName = Local Debug CA" \
139- " emailAddress = ${CERTBOT_EMAIL } " \
142+ " emailAddress = ${certbot_email } " \
140143 ) \
141144 -extensions ca_cert \
142145 -days " ${LOCAL_CA_ROOT_CERT_VALIDITY} " \
@@ -177,15 +180,15 @@ get_certificate() {
177180 # It is good practice to generate a new key every time a new certificate is
178181 # requested, in order to guard against potential key compromises.
179182 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 } "
181184
182185 # Create a certificate signing request from the private key.
183186 info " Generating certificate signing request for '${cert_name} '"
184187 openssl req -new -config <( printf " %s\n" \
185188 " ${openssl_cnf} " \
186189 " [ dn_section ]" \
187190 " commonName = ${cert_name} " \
188- " emailAddress = ${CERTBOT_EMAIL } " \
191+ " emailAddress = ${certbot_email } " \
189192 ) \
190193 -key " /etc/letsencrypt/live/${cert_name} /privkey.pem" \
191194 -out " ${LOCAL_CA_DIR} /${cert_name} .csr"
@@ -217,42 +220,79 @@ get_certificate() {
217220# time this script is invoked.
218221generate_ca
219222
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=()
238230 for server_name in " ${server_names[@]} " ; do
239231 if is_ip " ${server_name} " ; then
240232 # See if the alt name looks like an IP address.
241- ip_count=$(( ${ ip_count} + 1 ))
233+ ip_count=$(( ip_count + 1 ))
242234 alt_names+=(" IP.${ip_count} =${server_name} " )
243235 else
244236 # Else we suppose this is a valid DNS name.
245- dns_count=$(( ${ dns_count} + 1 ))
237+ dns_count=$(( dns_count + 1 ))
246238 alt_names+=(" DNS.${dns_count} =${server_name} " )
247239 fi
248240 done
241+ echo " ${alt_names[@]} "
242+ }
249243
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
256296
257297# After trying to sign all of the certificates, auto enable any configs that we
258298# did indeed succeed with.
0 commit comments