diff --git a/playbooks/roles/letsencrypt-acme-sh-install/files/driver.sh b/playbooks/roles/letsencrypt-acme-sh-install/files/driver.sh index 68035ccd7e..e8bf5a094e 100644 --- a/playbooks/roles/letsencrypt-acme-sh-install/files/driver.sh +++ b/playbooks/roles/letsencrypt-acme-sh-install/files/driver.sh @@ -48,6 +48,27 @@ if [[ ${1} == "issue" ]]; then # - extract everything between ' ' # - stick every two lines together, separated by a : done +elif [[ ${1} == "issue-selfsign" ]]; then + shift; + for arg in "$@"; do + # looks like + # "-d foo01.com -d foo.com " "-d bar01.com -d bar.com" + arr=(${arg}) + len=${#arr[@]} + for (( i=0; i<$len; i++ )); do + if [[ $((i%2)) -eq 0 ]]; then + continue # this should be a "-d" + else + # The ACME protocol hashes "stuff" and the TXT record + # is ultimately a sha256 encoded into base64url + # (RFC8555); emulate that here. + base64url=$(echo -n ${arr[$i]}-${RANDOM} | \ + openssl dgst -binary -sha256 | \ + openssl base64 | sed 's/+/-/g; s,/,_,g; s/=//g') + echo "${arr[$i]}:${base64url}" + fi + done + done elif [[ ${1} == "renew" ]]; then shift; for arg in "$@"; do @@ -81,19 +102,22 @@ elif [[ ${1} == "selfsign" ]]; then mkdir -p ${CERT_HOME}/${domain} cd ${CERT_HOME}/${domain} echo "Creating certs in ${CERT_HOME}/${domain}" + # Create key for domain + openssl genrsa -out ${domain}.key 2048 + # openssl makes this 0600; match the permissions acme.sh + # makes it with for general sanity + chmod 0640 ${domain}.key # Generate a fake CA key openssl genrsa -out ca.key 2048 # Create fake CA root certificate openssl req -x509 -new -nodes -key ca.key -sha256 -days 1024 -subj "/C=US/ST=CA/O=opendev" -out ca.cer - # Create key for localhost - openssl genrsa -out ${domain}.key 2048 # Create localhost certificate signing request openssl req -sha256 -new -key ${domain}.key -out ${domain}.csr -subj '/CN=localhost' # Create localhost certificate signed by fake CA openssl x509 -req -CA ca.cer -CAkey ca.key -CAcreateserial \ -sha256 -days 365 -in ${domain}.csr -out ${domain}.cer cp ${domain}.cer fullchain.cer - } | tee -a ${LOG_FILE} + } 2>&1 | tee -a ${LOG_FILE} done else echo "Unknown driver arg: $1" diff --git a/playbooks/roles/letsencrypt-create-certs/README.rst b/playbooks/roles/letsencrypt-create-certs/README.rst index 223aa011da..309f6cc9ee 100644 --- a/playbooks/roles/letsencrypt-create-certs/README.rst +++ b/playbooks/roles/letsencrypt-create-certs/README.rst @@ -8,13 +8,26 @@ on the host. **Role Variables** .. zuul:rolevar:: letsencrypt_self_sign_only + :default: False If set to True, will locally generate self-signed certificates in the same locations the real script would, instead of contacting letsencrypt. This is set during gate testing as the authentication tokens are not available. +.. zuul:rolevar:: letsencrypt_self_generate_tokens + :default: False + + When set to ``True``, self-generate fake DNS-01 TXT tokens rather + than acquiring them through the ACME process with letsencrypt. + This avoids leaving "half-open" challenges during gate testing, + where we have no way to publish the DNS TXT records letsencrypt + gives us to complete the certificate issue. This should be + ``True`` if ``letsencrypt_self_sign_only`` is ``True`` (unless you + wish to specifically test the ``acme.sh`` operation). + .. zuul:rolevar:: letsencrypt_use_staging + :default: False If set to True will use the letsencrypt staging environment, rather than make production requests. Useful during initial provisioning diff --git a/playbooks/roles/letsencrypt-request-certs/tasks/acme.yaml b/playbooks/roles/letsencrypt-request-certs/tasks/acme.yaml index a3f759a16a..d198387eef 100644 --- a/playbooks/roles/letsencrypt-request-certs/tasks/acme.yaml +++ b/playbooks/roles/letsencrypt-request-certs/tasks/acme.yaml @@ -7,7 +7,7 @@ - name: Run acme.sh driver for certificate issue shell: cmd: | - /opt/acme.sh/driver.sh issue {{ acme_args }} + /opt/acme.sh/driver.sh {{ 'issue-selfsign' if letsencrypt_self_generate_tokens else 'issue' }} {{ acme_args }} args: chdir: /opt/acme.sh/ register: acme_output diff --git a/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 b/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 index 5125b32f3f..f22e1bfe63 100644 --- a/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 +++ b/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 @@ -3,6 +3,7 @@ # issues. As we don't have the authentication keys exposed in the # gate, only generate a place-holder self-signed cert for testing. letsencrypt_use_staging: True +letsencrypt_self_generate_tokens: {{ letsencrypt_self_generate_tokens|default(True) }} letsencrypt_self_sign_only: True -letsencrypt_account_email: le-test@opendev.org \ No newline at end of file +letsencrypt_account_email: le-test@opendev.org diff --git a/zuul.d/system-config-run.yaml b/zuul.d/system-config-run.yaml index 2d356892b0..2aa572ab17 100644 --- a/zuul.d/system-config-run.yaml +++ b/zuul.d/system-config-run.yaml @@ -187,6 +187,8 @@ run_playbooks: - playbooks/service-nameserver.yaml - playbooks/letsencrypt.yaml + # Make sure this test runs acme.sh + letsencrypt_self_generate_tokens: False host-vars: bridge.openstack.org: host_copy_output: